-
Notifications
You must be signed in to change notification settings - Fork 3.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
217 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
/** | ||
* @author n1474335 [n1474335@gmail.com] | ||
* @copyright Crown Copyright 2021 | ||
* @license Apache-2.0 | ||
* | ||
* JA3S created by Salesforce | ||
* 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"; | ||
|
||
/** | ||
* JA3S Fingerprint operation | ||
*/ | ||
class JA3SFingerprint extends Operation { | ||
|
||
/** | ||
* JA3SFingerprint constructor | ||
*/ | ||
constructor() { | ||
super(); | ||
|
||
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.infoURL = "https://engineering.salesforce.com/tls-fingerprinting-with-ja3-and-ja3s-247362855967"; | ||
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", "JA3S 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)); | ||
|
||
const handshake = s.readInt(1); | ||
if (handshake !== 0x16) | ||
throw new OperationError("Not handshake data."); | ||
|
||
// Version | ||
s.moveForwardsBy(2); | ||
|
||
// Length | ||
const length = s.readInt(2); | ||
if (s.length !== length + 5) | ||
throw new OperationError("Incorrect handshake length."); | ||
|
||
// Handshake type | ||
const handshakeType = s.readInt(1); | ||
if (handshakeType !== 2) | ||
throw new OperationError("Not a Server Hello."); | ||
|
||
// Handshake length | ||
const handshakeLength = s.readInt(3); | ||
if (s.length !== handshakeLength + 9) | ||
throw new OperationError("Not enough data in Server Hello."); | ||
|
||
// Hello version | ||
const helloVersion = s.readInt(2); | ||
|
||
// Random | ||
s.moveForwardsBy(32); | ||
|
||
// Session ID | ||
const sessionIDLength = s.readInt(1); | ||
s.moveForwardsBy(sessionIDLength); | ||
|
||
// Cipher suite | ||
const cipherSuite = s.readInt(2); | ||
|
||
// Compression Method | ||
s.moveForwardsBy(1); | ||
|
||
// Extensions | ||
const extensionsLength = s.readInt(2); | ||
const extensions = s.getBytes(extensionsLength); | ||
const es = new Stream(extensions); | ||
const exts = []; | ||
while (es.hasMore()) { | ||
const type = es.readInt(2); | ||
const length = es.readInt(2); | ||
es.moveForwardsBy(length); | ||
exts.push(type); | ||
} | ||
|
||
// Output | ||
const ja3s = [ | ||
helloVersion.toString(), | ||
cipherSuite, | ||
exts.join("-") | ||
]; | ||
const ja3sStr = ja3s.join(","); | ||
const ja3sHash = runHash("md5", Utils.strToArrayBuffer(ja3sStr)); | ||
|
||
switch (outputFormat) { | ||
case "JA3S string": | ||
return ja3sStr; | ||
case "Full details": | ||
return `Hash digest: | ||
${ja3sHash} | ||
Full JA3S string: | ||
${ja3sStr} | ||
TLS Version: | ||
${helloVersion.toString()} | ||
Cipher Suite: | ||
${cipherSuite} | ||
Extensions: | ||
${exts.join("-")}`; | ||
case "Hash digest": | ||
default: | ||
return ja3sHash; | ||
} | ||
} | ||
|
||
} | ||
|
||
export default JA3SFingerprint; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
/** | ||
* JA3SFingerprint tests. | ||
* | ||
* @author n1474335 [n1474335@gmail.com] | ||
* @copyright Crown Copyright 2021 | ||
* @license Apache-2.0 | ||
*/ | ||
import TestRegister from "../../lib/TestRegister.mjs"; | ||
|
||
TestRegister.addTests([ | ||
{ | ||
name: "JA3S Fingerprint: TLS 1.0", | ||
input: "160301003d020000390301543dd2ddedbfe33895bd6bc676a3fa6b9fe5773a6e04d5476d1af3bcbc1dcbbb00c011000011ff01000100000b00040300010200230000", | ||
expectedOutput: "bed95e1b525d2f41db3a6d68fac5b566", | ||
recipeConfig: [ | ||
{ | ||
"op": "JA3S Fingerprint", | ||
"args": ["Hex", "Hash digest"] | ||
} | ||
], | ||
}, | ||
{ | ||
name: "JA3S Fingerprint: TLS 1.1", | ||
input: "160302003d020000390302543dd2ed88131999a0120d36c14a4139671d75aae3d7d7779081d3cf7dd7725a00c013000011ff01000100000b00040300010200230000", | ||
expectedOutput: "130fac2dc19b142500acb0abc63b6379", | ||
recipeConfig: [ | ||
{ | ||
"op": "JA3S Fingerprint", | ||
"args": ["Hex", "Hash digest"] | ||
} | ||
], | ||
}, | ||
{ | ||
name: "JA3S Fingerprint: TLS 1.2", | ||
input: "160303003d020000390303543dd328b38b445686739d58fab733fa23838f575e0e5ad9a1b9baace6cc3b4100c02f000011ff01000100000b00040300010200230000", | ||
expectedOutput: "ccc514751b175866924439bdbb5bba34", | ||
recipeConfig: [ | ||
{ | ||
"op": "JA3S Fingerprint", | ||
"args": ["Hex", "Hash digest"] | ||
} | ||
], | ||
}, | ||
{ | ||
name: "JA3S Fingerprint: TLS 1.3", | ||
input: "16030100520200004e7f123ef1609fd3f4fa8668aac5822d500fb0639b22671d0fb7258597355795511bf61301002800280024001d0020ae0e282a3b7a463e71064ecbaf671586e979b0edbebf7a4735c31678c70f660c", | ||
expectedOutput: "986ae432c402479fe7a0c6fbe02164c1", | ||
recipeConfig: [ | ||
{ | ||
"op": "JA3S Fingerprint", | ||
"args": ["Hex", "Hash digest"] | ||
} | ||
], | ||
}, | ||
]); |