Skip to content

Commit

Permalink
Added HASSH operations
Browse files Browse the repository at this point in the history
  • Loading branch information
n1474335 committed Aug 10, 2021
1 parent 57bb8fb commit e9ca4dc
Show file tree
Hide file tree
Showing 8 changed files with 384 additions and 13 deletions.
2 changes: 2 additions & 0 deletions src/core/config/Categories.json
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,8 @@
"VarInt Decode",
"JA3 Fingerprint",
"JA3S Fingerprint",
"HASSH Client Fingerprint",
"HASSH Server Fingerprint",
"Format MAC addresses",
"Change IP format",
"Group IP addresses",
Expand Down
166 changes: 166 additions & 0 deletions src/core/operations/HASSHClientFingerprint.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
/**
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2021
* @license Apache-2.0
*
* HASSH created by Salesforce
* Ben Reardon (@benreardon)
* Adel Karimi (@0x4d31)
* and the JA3 crew:
* John B. Althouse
* Jeff Atkinson
* Josh Atkins
*
* Algorithm released under the BSD-3-clause licence
*/

import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import Utils from "../Utils.mjs";
import Stream from "../lib/Stream.mjs";
import {runHash} from "../lib/Hash.mjs";

/**
* HASSH Client Fingerprint operation
*/
class HASSHClientFingerprint extends Operation {

/**
* HASSHClientFingerprint constructor
*/
constructor() {
super();

this.name = "HASSH Client Fingerprint";
this.module = "Crypto";
this.description = "Generates a HASSH fingerprint to help identify SSH clients based on hashing together values from the Client Key Exchange Init message.<br><br>Input: A hex stream of the SSH_MSG_KEXINIT packet application layer from Client to Server.";
this.infoURL = "https://engineering.salesforce.com/open-sourcing-hassh-abed3ae5044c";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
name: "Input format",
type: "option",
value: ["Hex", "Base64", "Raw"]
},
{
name: "Output format",
type: "option",
value: ["Hash digest", "HASSH algorithms string", "Full details"]
}
];
}

/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const [inputFormat, outputFormat] = args;

input = Utils.convertToByteArray(input, inputFormat);
const s = new Stream(new Uint8Array(input));

// Length
const length = s.readInt(4);
if (s.length !== length + 4)
throw new OperationError("Incorrect packet length.");

// Padding length
const paddingLength = s.readInt(1);

// Message code
const messageCode = s.readInt(1);
if (messageCode !== 20)
throw new OperationError("Not a Key Exchange Init.");

// Cookie
s.moveForwardsBy(16);

// KEX Algorithms
const kexAlgosLength = s.readInt(4);
const kexAlgos = s.readString(kexAlgosLength);

// Server Host Key Algorithms
const serverHostKeyAlgosLength = s.readInt(4);
s.moveForwardsBy(serverHostKeyAlgosLength);

// Encryption Algorithms Client to Server
const encAlgosC2SLength = s.readInt(4);
const encAlgosC2S = s.readString(encAlgosC2SLength);

// Encryption Algorithms Server to Client
const encAlgosS2CLength = s.readInt(4);
s.moveForwardsBy(encAlgosS2CLength);

// MAC Algorithms Client to Server
const macAlgosC2SLength = s.readInt(4);
const macAlgosC2S = s.readString(macAlgosC2SLength);

// MAC Algorithms Server to Client
const macAlgosS2CLength = s.readInt(4);
s.moveForwardsBy(macAlgosS2CLength);

// Compression Algorithms Client to Server
const compAlgosC2SLength = s.readInt(4);
const compAlgosC2S = s.readString(compAlgosC2SLength);

// Compression Algorithms Server to Client
const compAlgosS2CLength = s.readInt(4);
s.moveForwardsBy(compAlgosS2CLength);

// Languages Client to Server
const langsC2SLength = s.readInt(4);
s.moveForwardsBy(langsC2SLength);

// Languages Server to Client
const langsS2CLength = s.readInt(4);
s.moveForwardsBy(langsS2CLength);

// First KEX packet follows
s.moveForwardsBy(1);

// Reserved
s.moveForwardsBy(4);

// Padding string
s.moveForwardsBy(paddingLength);

// Output
const hassh = [
kexAlgos,
encAlgosC2S,
macAlgosC2S,
compAlgosC2S
];
const hasshStr = hassh.join(";");
const hasshHash = runHash("md5", Utils.strToArrayBuffer(hasshStr));

switch (outputFormat) {
case "HASSH algorithms string":
return hasshStr;
case "Full details":
return `Hash digest:
${hasshHash}
Full HASSH algorithms string:
${hasshStr}
Key Exchange Algorithms:
${kexAlgos}
Encryption Algorithms Client to Server:
${encAlgosC2S}
MAC Algorithms Client to Server:
${macAlgosC2S}
Compression Algorithms Client to Server:
${compAlgosC2S}`;
case "Hash digest":
default:
return hasshHash;
}
}

}

export default HASSHClientFingerprint;
166 changes: 166 additions & 0 deletions src/core/operations/HASSHServerFingerprint.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
/**
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2021
* @license Apache-2.0
*
* HASSH created by Salesforce
* Ben Reardon (@benreardon)
* Adel Karimi (@0x4d31)
* and the JA3 crew:
* John B. Althouse
* Jeff Atkinson
* Josh Atkins
*
* Algorithm released under the BSD-3-clause licence
*/

import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import Utils from "../Utils.mjs";
import Stream from "../lib/Stream.mjs";
import {runHash} from "../lib/Hash.mjs";

/**
* HASSH Server Fingerprint operation
*/
class HASSHServerFingerprint extends Operation {

/**
* HASSHServerFingerprint constructor
*/
constructor() {
super();

this.name = "HASSH Server Fingerprint";
this.module = "Crypto";
this.description = "Generates a HASSH fingerprint to help identify SSH servers based on hashing together values from the Server Key Exchange Init message.<br><br>Input: A hex stream of the SSH_MSG_KEXINIT packet application layer from Server to Client.";
this.infoURL = "https://engineering.salesforce.com/open-sourcing-hassh-abed3ae5044c";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
name: "Input format",
type: "option",
value: ["Hex", "Base64", "Raw"]
},
{
name: "Output format",
type: "option",
value: ["Hash digest", "HASSH algorithms string", "Full details"]
}
];
}

/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const [inputFormat, outputFormat] = args;

input = Utils.convertToByteArray(input, inputFormat);
const s = new Stream(new Uint8Array(input));

// Length
const length = s.readInt(4);
if (s.length !== length + 4)
throw new OperationError("Incorrect packet length.");

// Padding length
const paddingLength = s.readInt(1);

// Message code
const messageCode = s.readInt(1);
if (messageCode !== 20)
throw new OperationError("Not a Key Exchange Init.");

// Cookie
s.moveForwardsBy(16);

// KEX Algorithms
const kexAlgosLength = s.readInt(4);
const kexAlgos = s.readString(kexAlgosLength);

// Server Host Key Algorithms
const serverHostKeyAlgosLength = s.readInt(4);
s.moveForwardsBy(serverHostKeyAlgosLength);

// Encryption Algorithms Client to Server
const encAlgosC2SLength = s.readInt(4);
s.moveForwardsBy(encAlgosC2SLength);

// Encryption Algorithms Server to Client
const encAlgosS2CLength = s.readInt(4);
const encAlgosS2C = s.readString(encAlgosS2CLength);

// MAC Algorithms Client to Server
const macAlgosC2SLength = s.readInt(4);
s.moveForwardsBy(macAlgosC2SLength);

// MAC Algorithms Server to Client
const macAlgosS2CLength = s.readInt(4);
const macAlgosS2C = s.readString(macAlgosS2CLength);

// Compression Algorithms Client to Server
const compAlgosC2SLength = s.readInt(4);
s.moveForwardsBy(compAlgosC2SLength);

// Compression Algorithms Server to Client
const compAlgosS2CLength = s.readInt(4);
const compAlgosS2C = s.readString(compAlgosS2CLength);

// Languages Client to Server
const langsC2SLength = s.readInt(4);
s.moveForwardsBy(langsC2SLength);

// Languages Server to Client
const langsS2CLength = s.readInt(4);
s.moveForwardsBy(langsS2CLength);

// First KEX packet follows
s.moveForwardsBy(1);

// Reserved
s.moveForwardsBy(4);

// Padding string
s.moveForwardsBy(paddingLength);

// Output
const hassh = [
kexAlgos,
encAlgosS2C,
macAlgosS2C,
compAlgosS2C
];
const hasshStr = hassh.join(";");
const hasshHash = runHash("md5", Utils.strToArrayBuffer(hasshStr));

switch (outputFormat) {
case "HASSH algorithms string":
return hasshStr;
case "Full details":
return `Hash digest:
${hasshHash}
Full HASSH algorithms string:
${hasshStr}
Key Exchange Algorithms:
${kexAlgos}
Encryption Algorithms Server to Client:
${encAlgosS2C}
MAC Algorithms Server to Client:
${macAlgosS2C}
Compression Algorithms Server to Client:
${compAlgosS2C}`;
case "Hash digest":
default:
return hasshHash;
}
}

}

export default HASSHServerFingerprint;
2 changes: 1 addition & 1 deletion src/core/operations/JA3Fingerprint.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class JA3Fingerprint extends Operation {

this.name = "JA3 Fingerprint";
this.module = "Crypto";
this.description = "Generates a JA3 fingerprint to help identify TLS clients based on hashing together values from the Client Hello.<br><br>Input: A hex stream of the TLS Client Hello application layer.";
this.description = "Generates a JA3 fingerprint to help identify TLS clients based on hashing together values from the Client Hello.<br><br>Input: A hex stream of the TLS Client Hello packet application layer.";
this.infoURL = "https://engineering.salesforce.com/tls-fingerprinting-with-ja3-and-ja3s-247362855967";
this.inputType = "string";
this.outputType = "string";
Expand Down
2 changes: 1 addition & 1 deletion src/core/operations/JA3SFingerprint.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class JA3SFingerprint extends Operation {

this.name = "JA3S Fingerprint";
this.module = "Crypto";
this.description = "Generates a JA3S fingerprint to help identify TLS servers based on hashing together values from the Server Hello.<br><br>Input: A hex stream of the TLS Server Hello record in the application layer.";
this.description = "Generates a JA3S fingerprint to help identify TLS servers based on hashing together values from the Server Hello.<br><br>Input: A hex stream of the TLS Server Hello record application layer.";
this.infoURL = "https://engineering.salesforce.com/tls-fingerprinting-with-ja3-and-ja3s-247362855967";
this.inputType = "string";
this.outputType = "string";
Expand Down
2 changes: 2 additions & 0 deletions tests/operations/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ import "./tests/RSA.mjs";
import "./tests/CBOREncode.mjs";
import "./tests/CBORDecode.mjs";
import "./tests/JA3Fingerprint.mjs";
import "./tests/JA3SFingerprint.mjs";
import "./tests/HASSH.mjs";


// Cannot test operations that use the File type yet
Expand Down
Loading

0 comments on commit e9ca4dc

Please sign in to comment.