From d2ff03cea49e37a71b7d1e90eeeac60625eb7241 Mon Sep 17 00:00:00 2001 From: tomgond Date: Wed, 21 Feb 2024 19:55:09 +0200 Subject: [PATCH 01/19] Update DateTime.mjs Add test for time-delta --- tests/operations/tests/DateTime.mjs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/operations/tests/DateTime.mjs b/tests/operations/tests/DateTime.mjs index 6276890d..df6d6677 100644 --- a/tests/operations/tests/DateTime.mjs +++ b/tests/operations/tests/DateTime.mjs @@ -31,4 +31,26 @@ TestRegister.addTests([ }, ], }, + { + name: "DateTime Delta Positive", + input: "20/02/2024 13:36:00", + expectedOutput: "20/02/2024 13:37:00", + recipeConfig: [ + { + op: "DateTime Delta", + args: ["Standard date and time", "DD/MM/YYYY HH:mm:ss", "+0.0:01:0"], + }, + ], + }, + { + name: "DateTime Delta Negative", + input: "20/02/2024 14:37:00", + expectedOutput: "20/02/2024 13:37:00", + recipeConfig: [ + { + op: "DateTime Delta", + args: ["Standard date and time", "DD/MM/YYYY HH:mm:ss", "-0.1:00:0"], + }, + ], + }, ]); From 4dc4c7edd2a388792a5915d3abf2b4969620e17c Mon Sep 17 00:00:00 2001 From: tomgond Date: Wed, 21 Feb 2024 19:56:42 +0200 Subject: [PATCH 02/19] Update Categories.json Add DateTime Delta to categories --- src/core/config/Categories.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index 4f1b3328..d68c1713 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -312,6 +312,7 @@ "To UNIX Timestamp", "Windows Filetime to UNIX Timestamp", "UNIX Timestamp to Windows Filetime", + "DateTime Delta", "Extract dates", "Get Time", "Sleep" From 6331c203064563c628fe38f58cffb2206ce97afa Mon Sep 17 00:00:00 2001 From: tomgond Date: Wed, 21 Feb 2024 19:58:13 +0200 Subject: [PATCH 03/19] Add code for DateTime Delta to calculate operation --- src/core/operations/DateTimeDelta.mjs | 109 ++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 src/core/operations/DateTimeDelta.mjs diff --git a/src/core/operations/DateTimeDelta.mjs b/src/core/operations/DateTimeDelta.mjs new file mode 100644 index 00000000..6a7b8f7a --- /dev/null +++ b/src/core/operations/DateTimeDelta.mjs @@ -0,0 +1,109 @@ +/** + * @author tomgond [tom.gonda@gmail.com] + * @copyright Crown Copyright 2024 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import moment from "moment-timezone"; +import {DATETIME_FORMATS, FORMAT_EXAMPLES} from "../lib/DateTime.mjs"; + +/** + * @param {string} timeString + * @returns {string} +*/ +function parseTimeString(timeString) { + // Split the string into its components + const parts = timeString.split(":"); + // Extract the sign, days, hours, minutes, and seconds + const sign = parts[0][0] === "-" ? "-" : "+"; + const days = parseInt(parts[0].split(".")[0].slice(1), 10); + const hours = parseInt(parts[0].split(".")[1], 10); + const minutes = parseInt(parts[1], 10); + const seconds = parseInt(parts[2], 10); + + return { + sign, + days, + hours, + minutes, + seconds + }; +} + +/** + * DateTime Delta operation + */ +class DateTimeDelta extends Operation { + + /** + * DateTimeDelta constructor + */ + constructor() { + super(); + + this.name = "DateTime Delta"; + this.module = "Default"; + this.description = "Calculates a new DateTime value given an input DateTime value and a time difference (delta) from the input DateTime value."; + this.infoURL = ""; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + "name": "Built in formats", + "type": "populateOption", + "value": DATETIME_FORMATS, + "target": 1 + }, + { + "name": "Input format string", + "type": "binaryString", + "value": "DD/MM/YYYY HH:mm:ss" + }, + { + "name": "Time Delta", + "type": "binaryString", + "value": "+0.00:00:00" + } + + ]; + } + + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const inputFormat = args[1], + inputTimezone = "UTC"; + const deltaStr = args[2]; + + let date = ""; + try { + date = moment.tz(input, inputFormat, inputTimezone); + if (!date || date.format() === "Invalid date") throw Error; + } catch (err) { + return `Invalid format.\n\n${FORMAT_EXAMPLES}`; + } + + const deltaDict = parseTimeString(deltaStr); + let newDate; + if (deltaDict.sign === "-") { + newDate = date.add(-deltaDict.days, "days") + .add(-deltaDict.hours, "hours") + .add(-deltaDict.minutes, "minutes") + .add(-deltaDict.seconds, "seconds"); + + } else { + newDate = date.add(deltaDict.days, "days") + .add(deltaDict.hours, "hours") + .add(deltaDict.minutes, "minutes") + .add(deltaDict.seconds, "seconds"); + } + return newDate.tz(inputTimezone).format(inputFormat.replace(/[<>]/g, "")); + } +} + +export default DateTimeDelta; From 4e9567f5396d1d700cb204655c6793bdaf2221ff Mon Sep 17 00:00:00 2001 From: tomgond Date: Thu, 22 Feb 2024 21:49:24 +0200 Subject: [PATCH 04/19] Update DateTimeDelta.mjs Some change to re-run tests. --- src/core/operations/DateTimeDelta.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/operations/DateTimeDelta.mjs b/src/core/operations/DateTimeDelta.mjs index 6a7b8f7a..585ee370 100644 --- a/src/core/operations/DateTimeDelta.mjs +++ b/src/core/operations/DateTimeDelta.mjs @@ -10,7 +10,7 @@ import {DATETIME_FORMATS, FORMAT_EXAMPLES} from "../lib/DateTime.mjs"; /** * @param {string} timeString - * @returns {string} + * @returns {string} */ function parseTimeString(timeString) { // Split the string into its components From e85acee509757df7bc750ad99ce8a8aca089d182 Mon Sep 17 00:00:00 2001 From: tomgond Date: Fri, 23 Feb 2024 07:09:04 +0200 Subject: [PATCH 05/19] Update DateTimeDelta.mjs Another commit for re-build --- src/core/operations/DateTimeDelta.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/operations/DateTimeDelta.mjs b/src/core/operations/DateTimeDelta.mjs index 585ee370..66949ace 100644 --- a/src/core/operations/DateTimeDelta.mjs +++ b/src/core/operations/DateTimeDelta.mjs @@ -32,7 +32,7 @@ function parseTimeString(timeString) { } /** - * DateTime Delta operation + * DateTime Delta operation */ class DateTimeDelta extends Operation { From 1b16c26699d4f53917a2267308b2d8c4efbf3a13 Mon Sep 17 00:00:00 2001 From: mshwed Date: Mon, 11 Mar 2019 09:32:44 -0400 Subject: [PATCH 06/19] Operation: Added extract hash feature --- src/core/config/Categories.json | 1 + src/core/operations/ExtractHashes.mjs | 81 +++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 src/core/operations/ExtractHashes.mjs diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index 2dd9f29f..2d7b30ff 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -337,6 +337,7 @@ "Extract domains", "Extract file paths", "Extract dates", + "Extract Hashes", "Regular expression", "XPath expression", "JPath expression", diff --git a/src/core/operations/ExtractHashes.mjs b/src/core/operations/ExtractHashes.mjs new file mode 100644 index 00000000..ed186fb3 --- /dev/null +++ b/src/core/operations/ExtractHashes.mjs @@ -0,0 +1,81 @@ +/** + * @author mshwed [m@ttshwed.com] + * @copyright Crown Copyright 2019 + * @license Apache-2.0 + */ + +import Operation from "../Operation"; +import { search } from "../lib/Extract"; + +/** + * Extract Hash Values operation + */ +class ExtractHashes extends Operation { + + /** + * ExtractHashValues constructor + */ + constructor() { + super(); + + this.name = "Extract Hashes"; + this.module = "Default"; + this.description = "Extracts hash values based on hash byte length"; + this.infoURL = "https://en.wikipedia.org/wiki/Comparison_of_cryptographic_hash_functions"; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + name: "Hash length", + type: "number", + value: 32 + }, + { + name: "All hashes", + type: "boolean", + value: false + }, + { + name: "Display Total", + type: "boolean", + value: false + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + let results = []; + let hashCount = 0; + + const hashLength = args[0]; + const searchAllHashes = args[1]; + const showDisplayTotal = args[2]; + + let hashLengths = [hashLength]; + if (searchAllHashes) hashLengths = [4, 8, 16, 32, 64, 128, 160, 192, 224, 256, 320, 384, 512, 1024]; + + for (let hashLength of hashLengths) { + const regex = new RegExp(`(\\b|^)[a-f0-9]{${hashLength}}(\\b|$)`, "g"); + const searchResults = search(input, regex, null, false); + + hashCount += searchResults.split("\n").length - 1; + results.push(searchResults); + } + + let output = ""; + if (showDisplayTotal) { + output = `Total Results: ${hashCount}\n\n`; + } + + output = output + results.join(""); + return output; + } + +} + +export default ExtractHashes; From 98edef389ca7100d1b3dde6ac39062550be7d90c Mon Sep 17 00:00:00 2001 From: mshwed Date: Mon, 11 Mar 2019 09:53:12 -0400 Subject: [PATCH 07/19] Corrected module type --- src/core/operations/ExtractHashes.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/operations/ExtractHashes.mjs b/src/core/operations/ExtractHashes.mjs index ed186fb3..27402835 100644 --- a/src/core/operations/ExtractHashes.mjs +++ b/src/core/operations/ExtractHashes.mjs @@ -19,7 +19,7 @@ class ExtractHashes extends Operation { super(); this.name = "Extract Hashes"; - this.module = "Default"; + this.module = "Regex"; this.description = "Extracts hash values based on hash byte length"; this.infoURL = "https://en.wikipedia.org/wiki/Comparison_of_cryptographic_hash_functions"; this.inputType = "string"; From de8ed6962d99cc11b632da39753581b70e950846 Mon Sep 17 00:00:00 2001 From: mshwed Date: Mon, 11 Mar 2019 20:02:49 -0400 Subject: [PATCH 08/19] Improved description of operation --- src/core/operations/ExtractHashes.mjs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/core/operations/ExtractHashes.mjs b/src/core/operations/ExtractHashes.mjs index 27402835..f411f12d 100644 --- a/src/core/operations/ExtractHashes.mjs +++ b/src/core/operations/ExtractHashes.mjs @@ -20,13 +20,13 @@ class ExtractHashes extends Operation { this.name = "Extract Hashes"; this.module = "Regex"; - this.description = "Extracts hash values based on hash byte length"; + this.description = "Extracts potential hashes based on hash character length"; this.infoURL = "https://en.wikipedia.org/wiki/Comparison_of_cryptographic_hash_functions"; this.inputType = "string"; this.outputType = "string"; this.args = [ { - name: "Hash length", + name: "Hash character length", type: "number", value: 32 }, @@ -56,11 +56,16 @@ class ExtractHashes extends Operation { const searchAllHashes = args[1]; const showDisplayTotal = args[2]; - let hashLengths = [hashLength]; - if (searchAllHashes) hashLengths = [4, 8, 16, 32, 64, 128, 160, 192, 224, 256, 320, 384, 512, 1024]; + // Convert character length to bit length + let hashBitLengths = [(hashLength / 2) * 8]; - for (let hashLength of hashLengths) { - const regex = new RegExp(`(\\b|^)[a-f0-9]{${hashLength}}(\\b|$)`, "g"); + if (searchAllHashes) hashBitLengths = [4, 8, 16, 32, 64, 128, 160, 192, 224, 256, 320, 384, 512, 1024]; + + for (let hashBitLength of hashBitLengths) { + // Convert bit length to character length + let hashCharacterLength = (hashBitLength / 8) * 2; + + const regex = new RegExp(`(\\b|^)[a-f0-9]{${hashCharacterLength}}(\\b|$)`, "g"); const searchResults = search(input, regex, null, false); hashCount += searchResults.split("\n").length - 1; From a6b774da8168a86442d8a3240defaa7b154f4ddf Mon Sep 17 00:00:00 2001 From: mshwed Date: Tue, 12 Mar 2019 10:13:28 -0400 Subject: [PATCH 09/19] Fixed issues with const/let and changed default character length --- src/core/operations/ExtractHashes.mjs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/operations/ExtractHashes.mjs b/src/core/operations/ExtractHashes.mjs index f411f12d..ac4765ec 100644 --- a/src/core/operations/ExtractHashes.mjs +++ b/src/core/operations/ExtractHashes.mjs @@ -28,7 +28,7 @@ class ExtractHashes extends Operation { { name: "Hash character length", type: "number", - value: 32 + value: 40 }, { name: "All hashes", @@ -49,7 +49,7 @@ class ExtractHashes extends Operation { * @returns {string} */ run(input, args) { - let results = []; + const results = []; let hashCount = 0; const hashLength = args[0]; @@ -61,9 +61,9 @@ class ExtractHashes extends Operation { if (searchAllHashes) hashBitLengths = [4, 8, 16, 32, 64, 128, 160, 192, 224, 256, 320, 384, 512, 1024]; - for (let hashBitLength of hashBitLengths) { + for (const hashBitLength of hashBitLengths) { // Convert bit length to character length - let hashCharacterLength = (hashBitLength / 8) * 2; + const hashCharacterLength = (hashBitLength / 8) * 2; const regex = new RegExp(`(\\b|^)[a-f0-9]{${hashCharacterLength}}(\\b|$)`, "g"); const searchResults = search(input, regex, null, false); From 3983e1a8e23ca4bf8e7c5d52b0bbb562b77d946f Mon Sep 17 00:00:00 2001 From: mshwed Date: Sun, 31 Mar 2024 10:57:03 -0400 Subject: [PATCH 10/19] Updated imports --- src/core/operations/ExtractHashes.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/operations/ExtractHashes.mjs b/src/core/operations/ExtractHashes.mjs index ac4765ec..ba31164f 100644 --- a/src/core/operations/ExtractHashes.mjs +++ b/src/core/operations/ExtractHashes.mjs @@ -4,8 +4,8 @@ * @license Apache-2.0 */ -import Operation from "../Operation"; -import { search } from "../lib/Extract"; +import Operation from "../Operation.mjs"; +import { search } from "../lib/Extract.mjs"; /** * Extract Hash Values operation From 61295a968ef932cb7d9b0f0f9a3b742feee0b700 Mon Sep 17 00:00:00 2001 From: a3957273 <89583054+a3957273@users.noreply.github.com> Date: Mon, 1 Apr 2024 16:01:48 +0000 Subject: [PATCH 11/19] Lower case 'hash' --- src/core/config/Categories.json | 2 +- src/core/operations/ExtractHashes.mjs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index 2d7b30ff..cfbe99e0 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -337,7 +337,7 @@ "Extract domains", "Extract file paths", "Extract dates", - "Extract Hashes", + "Extract hashes", "Regular expression", "XPath expression", "JPath expression", diff --git a/src/core/operations/ExtractHashes.mjs b/src/core/operations/ExtractHashes.mjs index ba31164f..abba0b54 100644 --- a/src/core/operations/ExtractHashes.mjs +++ b/src/core/operations/ExtractHashes.mjs @@ -18,7 +18,7 @@ class ExtractHashes extends Operation { constructor() { super(); - this.name = "Extract Hashes"; + this.name = "Extract hashes"; this.module = "Regex"; this.description = "Extracts potential hashes based on hash character length"; this.infoURL = "https://en.wikipedia.org/wiki/Comparison_of_cryptographic_hash_functions"; From 6b95ba7dd6f9afdfe39b8fe57d12f61064ed827a Mon Sep 17 00:00:00 2001 From: a3957273 <89583054+a3957273@users.noreply.github.com> Date: Mon, 1 Apr 2024 16:10:42 +0000 Subject: [PATCH 12/19] Fix regular expresion crash in extract hashes --- src/core/operations/ExtractHashes.mjs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/operations/ExtractHashes.mjs b/src/core/operations/ExtractHashes.mjs index abba0b54..3f15e53c 100644 --- a/src/core/operations/ExtractHashes.mjs +++ b/src/core/operations/ExtractHashes.mjs @@ -68,8 +68,8 @@ class ExtractHashes extends Operation { const regex = new RegExp(`(\\b|^)[a-f0-9]{${hashCharacterLength}}(\\b|$)`, "g"); const searchResults = search(input, regex, null, false); - hashCount += searchResults.split("\n").length - 1; - results.push(searchResults); + hashCount += searchResults.length; + results.push(...searchResults); } let output = ""; @@ -77,7 +77,7 @@ class ExtractHashes extends Operation { output = `Total Results: ${hashCount}\n\n`; } - output = output + results.join(""); + output = output + results.join("\n"); return output; } From 56f92afbf4b15b27ac6f20a1e3621841ed838f55 Mon Sep 17 00:00:00 2001 From: tomgond Date: Mon, 1 Apr 2024 19:41:44 +0300 Subject: [PATCH 13/19] Change time-delta argument to be per time unit Day, hour, minute, second. Instead of a single string. --- src/core/operations/DateTimeDelta.mjs | 83 +++++++++++++-------------- 1 file changed, 41 insertions(+), 42 deletions(-) diff --git a/src/core/operations/DateTimeDelta.mjs b/src/core/operations/DateTimeDelta.mjs index 66949ace..c923374d 100644 --- a/src/core/operations/DateTimeDelta.mjs +++ b/src/core/operations/DateTimeDelta.mjs @@ -9,30 +9,7 @@ import moment from "moment-timezone"; import {DATETIME_FORMATS, FORMAT_EXAMPLES} from "../lib/DateTime.mjs"; /** - * @param {string} timeString - * @returns {string} -*/ -function parseTimeString(timeString) { - // Split the string into its components - const parts = timeString.split(":"); - // Extract the sign, days, hours, minutes, and seconds - const sign = parts[0][0] === "-" ? "-" : "+"; - const days = parseInt(parts[0].split(".")[0].slice(1), 10); - const hours = parseInt(parts[0].split(".")[1], 10); - const minutes = parseInt(parts[1], 10); - const seconds = parseInt(parts[2], 10); - - return { - sign, - days, - hours, - minutes, - seconds - }; -} - -/** - * DateTime Delta operation + * DateTime Delta operation */ class DateTimeDelta extends Operation { @@ -61,9 +38,29 @@ class DateTimeDelta extends Operation { "value": "DD/MM/YYYY HH:mm:ss" }, { - "name": "Time Delta", - "type": "binaryString", - "value": "+0.00:00:00" + "name": "Time Operation", + "type": "option", + "value": ["Add", "Subtract"] + }, + { + "name": "Days", + "type": "number", + "value": 0 + }, + { + "name": "Hours", + "type": "number", + "value": 0 + }, + { + "name": "Minutes", + "type": "number", + "value": 0 + }, + { + "name": "Seconds", + "type": "number", + "value": 0 } ]; @@ -76,31 +73,33 @@ class DateTimeDelta extends Operation { * @returns {string} */ run(input, args) { - const inputFormat = args[1], - inputTimezone = "UTC"; - const deltaStr = args[2]; - + const inputTimezone = "UTC"; + const inputFormat = args[1]; + const operationType = args[2]; + const daysDelta = args[3]; + const hoursDelta = args[4]; + const minutesDelta = args[5]; + const secondsDelta = args[6]; let date = ""; + try { date = moment.tz(input, inputFormat, inputTimezone); if (!date || date.format() === "Invalid date") throw Error; } catch (err) { return `Invalid format.\n\n${FORMAT_EXAMPLES}`; } - - const deltaDict = parseTimeString(deltaStr); let newDate; - if (deltaDict.sign === "-") { - newDate = date.add(-deltaDict.days, "days") - .add(-deltaDict.hours, "hours") - .add(-deltaDict.minutes, "minutes") - .add(-deltaDict.seconds, "seconds"); + if (operationType === "Add") { + newDate = date.add(daysDelta, "days") + .add(hoursDelta, "hours") + .add(minutesDelta, "minutes") + .add(secondsDelta, "seconds"); } else { - newDate = date.add(deltaDict.days, "days") - .add(deltaDict.hours, "hours") - .add(deltaDict.minutes, "minutes") - .add(deltaDict.seconds, "seconds"); + newDate = date.add(-daysDelta, "days") + .add(-hoursDelta, "hours") + .add(-minutesDelta, "minutes") + .add(-secondsDelta, "seconds"); } return newDate.tz(inputTimezone).format(inputFormat.replace(/[<>]/g, "")); } From dfedfa9f4cab634d7c332580e133116ab33a2c48 Mon Sep 17 00:00:00 2001 From: tomgond Date: Mon, 1 Apr 2024 19:42:56 +0300 Subject: [PATCH 14/19] Fix test to fit new time-delta format --- tests/operations/tests/DateTime.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/operations/tests/DateTime.mjs b/tests/operations/tests/DateTime.mjs index df6d6677..16848bcc 100644 --- a/tests/operations/tests/DateTime.mjs +++ b/tests/operations/tests/DateTime.mjs @@ -38,7 +38,7 @@ TestRegister.addTests([ recipeConfig: [ { op: "DateTime Delta", - args: ["Standard date and time", "DD/MM/YYYY HH:mm:ss", "+0.0:01:0"], + args: ["Standard date and time", "DD/MM/YYYY HH:mm:ss", "Add", 0, 0, 1, 0], }, ], }, @@ -49,7 +49,7 @@ TestRegister.addTests([ recipeConfig: [ { op: "DateTime Delta", - args: ["Standard date and time", "DD/MM/YYYY HH:mm:ss", "-0.1:00:0"], + args: ["Standard date and time", "DD/MM/YYYY HH:mm:ss", "Subtract", 0, 1, 0, 0], }, ], }, From c5e5ed2b4d9a38d2b97231fb6d38faf38ee8b541 Mon Sep 17 00:00:00 2001 From: Janne Kataja Date: Sun, 22 Jan 2023 01:48:49 +0100 Subject: [PATCH 15/19] add Certificate Signing Request (CSR) parse action --- src/core/config/Categories.json | 3 +- src/core/operations/ParseCSR.mjs | 268 ++++++++++++++++++++++++++++ tests/operations/index.mjs | 1 + tests/operations/tests/ParseCSR.mjs | 215 ++++++++++++++++++++++ 4 files changed, 486 insertions(+), 1 deletion(-) create mode 100644 src/core/operations/ParseCSR.mjs create mode 100644 tests/operations/tests/ParseCSR.mjs diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index 2dd9f29f..6b0b727c 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -179,7 +179,8 @@ "RSA Verify", "RSA Encrypt", "RSA Decrypt", - "Parse SSH Host Key" + "Parse SSH Host Key", + "Parse CSR" ] }, { diff --git a/src/core/operations/ParseCSR.mjs b/src/core/operations/ParseCSR.mjs new file mode 100644 index 00000000..15baa2c0 --- /dev/null +++ b/src/core/operations/ParseCSR.mjs @@ -0,0 +1,268 @@ +/** + * @author jkataja + * @copyright Crown Copyright 2023 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import forge from "node-forge"; +import Utils from "../Utils.mjs"; + +/** + * Parse CSR operation + */ +class ParseCSR extends Operation { + + /** + * ParseCSR constructor + */ + constructor() { + super(); + + this.name = "Parse CSR"; + this.module = "PublicKey"; + this.description = "Parse Certificate Signing Request (CSR) for an X.509 certificate"; + this.infoURL = "https://en.wikipedia.org/wiki/Certificate_signing_request"; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + "name": "Input format", + "type": "option", + "value": ["PEM"] + }, + { + "name": "Strict ASN.1 value lengths", + "type": "boolean", + "value": true + } + ]; + this.checks = [ + { + "pattern": "^-+BEGIN CERTIFICATE REQUEST-+\\r?\\n[\\da-z+/\\n\\r]+-+END CERTIFICATE REQUEST-+\\r?\\n?$", + "flags": "i", + "args": ["PEM"] + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} Human-readable description of a Certificate Signing Request (CSR). + */ + run(input, args) { + if (!input.length) { + return "No input"; + } + + const csr = forge.pki.certificationRequestFromPem(input, args[1]); + + // RSA algorithm is the only one supported for CSR in node-forge as of 1.3.1 + return `Version: ${1 + csr.version} (0x${Utils.hex(csr.version)}) +Subject${formatSubject(csr.subject)} +Subject Alternative Names${formatSubjectAlternativeNames(csr)} +Public Key + Algorithm: RSA + Length: ${csr.publicKey.n.bitLength()} bits + Modulus: ${formatMultiLine(chop(csr.publicKey.n.toString(16).replace(/(..)/g, "$&:")))} + Exponent: ${csr.publicKey.e} (0x${Utils.hex(csr.publicKey.e)}) +Signature + Algorithm: ${forge.pki.oids[csr.signatureOid]} + Signature: ${formatMultiLine(Utils.strToByteArray(csr.signature).map(b => Utils.hex(b)).join(":"))} +Extensions${formatExtensions(csr)}`; + } +} + +/** + * Format Subject of the request as a multi-line string + * @param {*} subject CSR Subject + * @returns Multi-line string describing Subject + */ +function formatSubject(subject) { + let out = "\n"; + + for (const attribute of subject.attributes) { + out += ` ${attribute.shortName} = ${attribute.value}\n`; + } + + return chop(out); +} + + +/** + * Format Subject Alternative Names from the name `subjectAltName` extension + * @param {*} extension CSR object + * @returns Multi-line string describing Subject Alternative Names + */ +function formatSubjectAlternativeNames(csr) { + let out = "\n"; + + for (const attribute of csr.attributes) { + for (const extension of attribute.extensions) { + if (extension.name === "subjectAltName") { + const names = []; + for (const altName of extension.altNames) { + switch (altName.type) { + case 1: + names.push(`EMAIL: ${altName.value}`); + break; + case 2: + names.push(`DNS: ${altName.value}`); + break; + case 6: + names.push(`URI: ${altName.value}`); + break; + case 7: + names.push(`IP: ${altName.ip}`); + break; + default: + names.push(`(unable to format type ${altName.type} name)\n`); + } + } + out += indent(2, names); + } + } + } + + return chop(out); +} + +/** + * Format known extensions of a CSR + * @param {*} csr CSR object + * @returns Multi-line string describing attributes + */ +function formatExtensions(csr) { + let out = "\n"; + + for (const attribute of csr.attributes) { + for (const extension of attribute.extensions) { + // formatted separately + if (extension.name === "subjectAltName") { + continue; + } + out += ` ${extension.name}${(extension.critical ? " CRITICAL" : "")}:\n`; + let parts = []; + switch (extension.name) { + case "basicConstraints" : + parts = describeBasicConstraints(extension); + break; + case "keyUsage" : + parts = describeKeyUsage(extension); + break; + case "extKeyUsage" : + parts = describeExtendedKeyUsage(extension); + break; + default : + parts = ["(unable to format extension)"]; + } + out += indent(4, parts); + } + } + + return chop(out); +} + + +/** + * Format hex string onto multiple lines + * @param {*} longStr + * @returns Hex string as a multi-line hex string + */ +function formatMultiLine(longStr) { + const lines = []; + + for (let remain = longStr ; remain !== "" ; remain = remain.substring(48)) { + lines.push(remain.substring(0, 48)); + } + + return lines.join("\n "); +} + +/** + * Describe Basic Constraints + * @see RFC 5280 4.2.1.9. Basic Constraints https://www.ietf.org/rfc/rfc5280.txt + * @param {*} extension CSR extension with the name `basicConstraints` + * @returns Array of strings describing Basic Constraints + */ +function describeBasicConstraints(extension) { + const constraints = []; + + constraints.push(`CA = ${extension.cA}`); + if (extension.pathLenConstraint !== undefined) constraints.push(`PathLenConstraint = ${extension.pathLenConstraint}`); + + return constraints; +} + +/** + * Describe Key Usage extension permitted use cases + * @see RFC 5280 4.2.1.3. Key Usage https://www.ietf.org/rfc/rfc5280.txt + * @param {*} extension CSR extension with the name `keyUsage` + * @returns Array of strings describing Key Usage extension permitted use cases + */ +function describeKeyUsage(extension) { + const usage = []; + + if (extension.digitalSignature) usage.push("Digital signature"); + if (extension.nonRepudiation) usage.push("Non-repudiation"); + if (extension.keyEncipherment) usage.push("Key encipherment"); + if (extension.dataEncipherment) usage.push("Data encipherment"); + if (extension.keyAgreement) usage.push("Key agreement"); + if (extension.keyCertSign) usage.push("Key certificate signing"); + if (extension.cRLSign) usage.push("CRL signing"); + if (extension.encipherOnly) usage.push("Encipher only"); + if (extension.decipherOnly) usage.push("Decipher only"); + + if (usage.length === 0) usage.push("(none)"); + + return usage; +} + +/** + * Describe Extended Key Usage extension permitted use cases + * @see RFC 5280 4.2.1.12. Extended Key Usage https://www.ietf.org/rfc/rfc5280.txt + * @param {*} extension CSR extension with the name `extendedKeyUsage` + * @returns Array of strings describing Extended Key Usage extension permitted use cases + */ +function describeExtendedKeyUsage(extension) { + const usage = []; + + if (extension.serverAuth) usage.push("TLS Web Server Authentication"); + if (extension.clientAuth) usage.push("TLS Web Client Authentication"); + if (extension.codeSigning) usage.push("Code signing"); + if (extension.emailProtection) usage.push("E-mail Protection (S/MIME)"); + if (extension.timeStamping) usage.push("Trusted Timestamping"); + if (extension.msCodeInd) usage.push("Microsoft Individual Code Signing"); + if (extension.msCodeCom) usage.push("Microsoft Commercial Code Signing"); + if (extension.msCTLSign) usage.push("Microsoft Trust List Signing"); + if (extension.msSGC) usage.push("Microsoft Server Gated Crypto"); + if (extension.msEFS) usage.push("Microsoft Encrypted File System"); + if (extension.nsSGC) usage.push("Netscape Server Gated Crypto"); + + if (usage.length === 0) usage.push("(none)"); + + return usage; +} + +/** + * Join an array of strings and add leading spaces to each line. + * @param {*} n How many leading spaces + * @param {*} parts Array of strings + * @returns Joined and indented string. + */ +function indent(n, parts) { + const fluff = " ".repeat(n); + return fluff + parts.join("\n" + fluff) + "\n"; +} + +/** + * Remove last character from a string. + * @param {*} s String + * @returns Chopped string. + */ +function chop(s) { + return s.substring(0, s.length - 1); +} + +export default ParseCSR; diff --git a/tests/operations/index.mjs b/tests/operations/index.mjs index 9f9be2b7..3851e8d9 100644 --- a/tests/operations/index.mjs +++ b/tests/operations/index.mjs @@ -147,6 +147,7 @@ import "./tests/Typex.mjs"; import "./tests/UnescapeString.mjs"; import "./tests/Unicode.mjs"; import "./tests/YARA.mjs"; +import "./tests/ParseCSR.mjs"; const testStatus = { allTestsPassing: true, diff --git a/tests/operations/tests/ParseCSR.mjs b/tests/operations/tests/ParseCSR.mjs new file mode 100644 index 00000000..1ba7e73f --- /dev/null +++ b/tests/operations/tests/ParseCSR.mjs @@ -0,0 +1,215 @@ +/** + * Parse CSR tests. + * + * @author jkataja + * @copyright Crown Copyright 2023 + * @license Apache-2.0 + */ + +import TestRegister from "../../lib/TestRegister.mjs"; + +// openssl req -newkey rsa:1024 -keyout test-rsa-1024.key -out test-rsa-1024.csr \ +// -subj "/C=CH/ST=Zurich/L=Zurich/O=Example RE/OU=IT Department/CN=example.com" \ +// -addext "subjectAltName = DNS:example.com,DNS:www.example.com" \ +// -addext "basicConstraints = critical,CA:FALSE" \ +// -addext "keyUsage = critical,digitalSignature,keyEncipherment" \ +// -addext "extendedKeyUsage = serverAuth" +const IN_EXAMPLE_COM_RSA_1024 = `-----BEGIN CERTIFICATE REQUEST----- +MIICHzCCAYgCAQAwcjELMAkGA1UEBhMCQ0gxDzANBgNVBAgMBlp1cmljaDEPMA0G +A1UEBwwGWnVyaWNoMRMwEQYDVQQKDApFeGFtcGxlIFJFMRYwFAYDVQQLDA1JVCBE +ZXBhcnRtZW50MRQwEgYDVQQDDAtleGFtcGxlLmNvbTCBnzANBgkqhkiG9w0BAQEF +AAOBjQAwgYkCgYEArrTrLI6FkzjX8FZfclt2ox1Dz7KRwt5f6ffZic7twLAKJ4ao +/H3APjwoFVUXGjiNj/XF2RlId4UxB1b6CgWjujBb9W51rTdvfWLyAHsrLcptpVz+ +V9Y8X9kEFCRGGDyG5+X+Nu6COzTpUPDj4bIIX/uPk3fDYDEqLClVy8/VS48CAwEA +AaBtMGsGCSqGSIb3DQEJDjFeMFwwJwYDVR0RBCAwHoILZXhhbXBsZS5jb22CD3d3 +dy5leGFtcGxlLmNvbTAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIFoDATBgNV +HSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0BAQsFAAOBgQB0mUlPgt6pt/kjD0pz +OUNk5e9nBFQYQGuGIHGYbPX3mi4Wd9vUCdPixtPSTunHWs2cxX2nM8+MdcNTY+7Q +NFgFNIvSXhbqMYoHAAApMHJOxiWpBFdYKp3tESnlgh2lUh7lQtmOjD4a1dzfU8PU +oViyp+UJGasN2WRd+4VtaPw64w== +-----END CERTIFICATE REQUEST-----`; + +const OUT_EXAMPLE_COM_RSA_1024 = `Version: 1 (0x00) +Subject + C = CH + ST = Zurich + L = Zurich + O = Example RE + OU = IT Department + CN = example.com +Subject Alternative Names + DNS: example.com + DNS: www.example.com +Public Key + Algorithm: RSA + Length: 1024 bits + Modulus: ae:b4:eb:2c:8e:85:93:38:d7:f0:56:5f:72:5b:76:a3: + 1d:43:cf:b2:91:c2:de:5f:e9:f7:d9:89:ce:ed:c0:b0: + 0a:27:86:a8:fc:7d:c0:3e:3c:28:15:55:17:1a:38:8d: + 8f:f5:c5:d9:19:48:77:85:31:07:56:fa:0a:05:a3:ba: + 30:5b:f5:6e:75:ad:37:6f:7d:62:f2:00:7b:2b:2d:ca: + 6d:a5:5c:fe:57:d6:3c:5f:d9:04:14:24:46:18:3c:86: + e7:e5:fe:36:ee:82:3b:34:e9:50:f0:e3:e1:b2:08:5f: + fb:8f:93:77:c3:60:31:2a:2c:29:55:cb:cf:d5:4b:8f + Exponent: 65537 (0x10001) +Signature + Algorithm: sha256WithRSAEncryption + Signature: 74:99:49:4f:82:de:a9:b7:f9:23:0f:4a:73:39:43:64: + e5:ef:67:04:54:18:40:6b:86:20:71:98:6c:f5:f7:9a: + 2e:16:77:db:d4:09:d3:e2:c6:d3:d2:4e:e9:c7:5a:cd: + 9c:c5:7d:a7:33:cf:8c:75:c3:53:63:ee:d0:34:58:05: + 34:8b:d2:5e:16:ea:31:8a:07:00:00:29:30:72:4e:c6: + 25:a9:04:57:58:2a:9d:ed:11:29:e5:82:1d:a5:52:1e: + e5:42:d9:8e:8c:3e:1a:d5:dc:df:53:c3:d4:a1:58:b2: + a7:e5:09:19:ab:0d:d9:64:5d:fb:85:6d:68:fc:3a:e3 +Extensions + basicConstraints CRITICAL: + CA = false + keyUsage CRITICAL: + Digital signature + Key encipherment + extKeyUsage: + TLS Web Server Authentication`; + +// openssl req -newkey rsa:2048 -keyout test-rsa-2048.key -out test-rsa-2048.csr \ +// -subj "/C=CH/ST=Zurich/L=Zurich/O=Example RE/OU=IT Department/CN=example.com" \ +// -addext "subjectAltName = DNS:example.com,DNS:www.example.com" \ +// -addext "basicConstraints = critical,CA:FALSE" \ +// -addext "keyUsage = critical,digitalSignature,keyEncipherment" \ +// -addext "extendedKeyUsage = serverAuth" +const IN_EXAMPLE_COM_RSA_2048 = `-----BEGIN CERTIFICATE REQUEST----- +MIIDJDCCAgwCAQAwcjELMAkGA1UEBhMCQ0gxDzANBgNVBAgMBlp1cmljaDEPMA0G +A1UEBwwGWnVyaWNoMRMwEQYDVQQKDApFeGFtcGxlIFJFMRYwFAYDVQQLDA1JVCBE +ZXBhcnRtZW50MRQwEgYDVQQDDAtleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAKPogLmWPuK/IGdct2v/3MFKVaVeKp2Hl5at/zDFLCAe +51bwh7BqNVJEci4ApwlXA1WVmQPBFBJlYwQZVjz5UAN2CmNHxud5nV03YmZ2/Iml +RzpKcZMPqU+liJCC04L+XIbOdx+Vz52dF++Cc+FuSFq803yW+qefK8JsJNO9KuPx +RLYKSAADa9MIJisru1PzcBAOcimOmNnFWuo+LKsd4lU30OExDdKHwtyt62Mj1c3o +lO1JjvkjtWWjwHI+0EgTjvkeXlcUYZvvLlysdKERMRozvMTGqqoHWCgWl+Rq9Z6P +TgNsRO4CKug1Zwmh8y6acZ7sYb/dar8HOeqJnc0pCv8CAwEAAaBtMGsGCSqGSIb3 +DQEJDjFeMFwwJwYDVR0RBCAwHoILZXhhbXBsZS5jb22CD3d3dy5leGFtcGxlLmNv +bTAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEF +BQcDATANBgkqhkiG9w0BAQsFAAOCAQEAG0cjfRBY1pBzu+jf7yMQrK5mQrh72air +VuXHmochmyUxyt0G7ovnNhKEr+X9snShJLi5qlyvnb2roiwlCmuwGIZxErN1svQL +Z3kQNZgH+Vyu5IRL2DlPs5AAxVmzPpbnbXNhMHyAK/ziLcU031O1PoCpxwfvPsjW +HWOCjbZUVaJnxdp8AHqImoGAiVhJwc37feFvb2UQlLedUypQkPg/poNWduaRDoj8 +m9cpVxuxGLtONBnohzohnFECytSXWEXPIj8L9SpYK97G02nJYYCAcb5BF11Alfux +sNxtsr6zgPaLRrvOBT11WxJVKerbhfezAJ3naem1eM3VLxCGWwMwxg== +-----END CERTIFICATE REQUEST-----`; + +const OUT_EXAMPLE_COM_RSA_2048 = `Version: 1 (0x00) +Subject + C = CH + ST = Zurich + L = Zurich + O = Example RE + OU = IT Department + CN = example.com +Subject Alternative Names + DNS: example.com + DNS: www.example.com +Public Key + Algorithm: RSA + Length: 2048 bits + Modulus: a3:e8:80:b9:96:3e:e2:bf:20:67:5c:b7:6b:ff:dc:c1: + 4a:55:a5:5e:2a:9d:87:97:96:ad:ff:30:c5:2c:20:1e: + e7:56:f0:87:b0:6a:35:52:44:72:2e:00:a7:09:57:03: + 55:95:99:03:c1:14:12:65:63:04:19:56:3c:f9:50:03: + 76:0a:63:47:c6:e7:79:9d:5d:37:62:66:76:fc:89:a5: + 47:3a:4a:71:93:0f:a9:4f:a5:88:90:82:d3:82:fe:5c: + 86:ce:77:1f:95:cf:9d:9d:17:ef:82:73:e1:6e:48:5a: + bc:d3:7c:96:fa:a7:9f:2b:c2:6c:24:d3:bd:2a:e3:f1: + 44:b6:0a:48:00:03:6b:d3:08:26:2b:2b:bb:53:f3:70: + 10:0e:72:29:8e:98:d9:c5:5a:ea:3e:2c:ab:1d:e2:55: + 37:d0:e1:31:0d:d2:87:c2:dc:ad:eb:63:23:d5:cd:e8: + 94:ed:49:8e:f9:23:b5:65:a3:c0:72:3e:d0:48:13:8e: + f9:1e:5e:57:14:61:9b:ef:2e:5c:ac:74:a1:11:31:1a: + 33:bc:c4:c6:aa:aa:07:58:28:16:97:e4:6a:f5:9e:8f: + 4e:03:6c:44:ee:02:2a:e8:35:67:09:a1:f3:2e:9a:71: + 9e:ec:61:bf:dd:6a:bf:07:39:ea:89:9d:cd:29:0a:ff + Exponent: 65537 (0x10001) +Signature + Algorithm: sha256WithRSAEncryption + Signature: 1b:47:23:7d:10:58:d6:90:73:bb:e8:df:ef:23:10:ac: + ae:66:42:b8:7b:d9:a8:ab:56:e5:c7:9a:87:21:9b:25: + 31:ca:dd:06:ee:8b:e7:36:12:84:af:e5:fd:b2:74:a1: + 24:b8:b9:aa:5c:af:9d:bd:ab:a2:2c:25:0a:6b:b0:18: + 86:71:12:b3:75:b2:f4:0b:67:79:10:35:98:07:f9:5c: + ae:e4:84:4b:d8:39:4f:b3:90:00:c5:59:b3:3e:96:e7: + 6d:73:61:30:7c:80:2b:fc:e2:2d:c5:34:df:53:b5:3e: + 80:a9:c7:07:ef:3e:c8:d6:1d:63:82:8d:b6:54:55:a2: + 67:c5:da:7c:00:7a:88:9a:81:80:89:58:49:c1:cd:fb: + 7d:e1:6f:6f:65:10:94:b7:9d:53:2a:50:90:f8:3f:a6: + 83:56:76:e6:91:0e:88:fc:9b:d7:29:57:1b:b1:18:bb: + 4e:34:19:e8:87:3a:21:9c:51:02:ca:d4:97:58:45:cf: + 22:3f:0b:f5:2a:58:2b:de:c6:d3:69:c9:61:80:80:71: + be:41:17:5d:40:95:fb:b1:b0:dc:6d:b2:be:b3:80:f6: + 8b:46:bb:ce:05:3d:75:5b:12:55:29:ea:db:85:f7:b3: + 00:9d:e7:69:e9:b5:78:cd:d5:2f:10:86:5b:03:30:c6 +Extensions + basicConstraints CRITICAL: + CA = false + keyUsage CRITICAL: + Digital signature + Key encipherment + extKeyUsage: + TLS Web Server Authentication`; + +// openssl genpkey -genparam -algorithm ec -pkeyopt ec_paramgen_curve:P-256 -out test-ec-param.pem +// openssl req -newkey ec:test-ec-param.pem -keyout test-ec.key -out test-ec.csr \ +// -subj "/C=CH/ST=Zurich/L=Zurich/O=Example RE/OU=IT Department/CN=example.com" \ +// -addext "subjectAltName = DNS:example.com,DNS:www.example.com" \ +// -addext "basicConstraints = critical,CA:FALSE" \ +// -addext "keyUsage = critical,digitalSignature,keyEncipherment" \ +// -addext "extendedKeyUsage = serverAuth" +const IN_EXAMPLE_COM_EC = `-----BEGIN CERTIFICATE REQUEST----- +MIIBmzCCAUECAQAwcjELMAkGA1UEBhMCQ0gxDzANBgNVBAgMBlp1cmljaDEPMA0G +A1UEBwwGWnVyaWNoMRMwEQYDVQQKDApFeGFtcGxlIFJFMRYwFAYDVQQLDA1JVCBE +ZXBhcnRtZW50MRQwEgYDVQQDDAtleGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqG +SM49AwEHA0IABAmpYXNh+L9E0Q3sLhrO+MF1XgKCfqJntrOyIkrGwoiQftHbJWTA +6duxQhU/3d9B+SN/ibeKY+xeiNBrs2eTYZ6gbTBrBgkqhkiG9w0BCQ4xXjBcMCcG +A1UdEQQgMB6CC2V4YW1wbGUuY29tgg93d3cuZXhhbXBsZS5jb20wDAYDVR0TAQH/ +BAIwADAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwCgYIKoZI +zj0EAwIDSAAwRQIgQkum/qaLzE3QZ3WD00uLpalUn113FObd7rM5Mr3HQwQCIQCr +7OjzYI9v7qIJp/E9N16XfJN87G2ZVIZ4FuPXVjokCQ== +-----END CERTIFICATE REQUEST-----`; + +const OUT_EXAMPLE_COM_EC = `Parse CSR - Cannot read public key. OID is not RSA.`; + +TestRegister.addTests([ + { + name: "Parse CSR: Example Certificate Signing Request (CSR) with RSA 1024", + input: IN_EXAMPLE_COM_RSA_1024, + expectedOutput: OUT_EXAMPLE_COM_RSA_1024, + recipeConfig: [ + { + "op": "Parse CSR", + "args": ["PEM", true] + } + ] + }, + { + name: "Parse CSR: Example Certificate Signing Request (CSR) with RSA 2048", + input: IN_EXAMPLE_COM_RSA_2048, + expectedOutput: OUT_EXAMPLE_COM_RSA_2048, + recipeConfig: [ + { + "op": "Parse CSR", + "args": ["PEM", true] + } + ] + }, + // RSA algorithm is the only one supported for CSR in node-forge as of 1.3.1 + { + name: "Parse CSR: Example Certificate Signing Request (CSR) with EC 256", + input: IN_EXAMPLE_COM_EC, + expectedError: true, + expectedOutput: OUT_EXAMPLE_COM_EC, + recipeConfig: [ + { + "op": "Parse CSR", + "args": ["PEM", true] + } + ] + } +]); From 8d4ad6ae75a26f0270f6bd4297097c15410aa52b Mon Sep 17 00:00:00 2001 From: mshwed Date: Mon, 1 Apr 2024 22:22:43 -0400 Subject: [PATCH 16/19] Minor changes. Added test cases. --- src/core/operations/ExtractHashes.mjs | 4 +- tests/operations/index.mjs | 1 + tests/operations/tests/ExtractHashes.mjs | 77 ++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 tests/operations/tests/ExtractHashes.mjs diff --git a/src/core/operations/ExtractHashes.mjs b/src/core/operations/ExtractHashes.mjs index 3f15e53c..386aab0e 100644 --- a/src/core/operations/ExtractHashes.mjs +++ b/src/core/operations/ExtractHashes.mjs @@ -52,9 +52,7 @@ class ExtractHashes extends Operation { const results = []; let hashCount = 0; - const hashLength = args[0]; - const searchAllHashes = args[1]; - const showDisplayTotal = args[2]; + const [hashLength, searchAllHashes, showDisplayTotal] = args; // Convert character length to bit length let hashBitLengths = [(hashLength / 2) * 8]; diff --git a/tests/operations/index.mjs b/tests/operations/index.mjs index 9f9be2b7..17298700 100644 --- a/tests/operations/index.mjs +++ b/tests/operations/index.mjs @@ -62,6 +62,7 @@ import "./tests/DefangIP.mjs"; import "./tests/ELFInfo.mjs"; import "./tests/Enigma.mjs"; import "./tests/ExtractEmailAddresses.mjs"; +import "./tests/ExtractHashes.mjs"; import "./tests/Float.mjs"; import "./tests/FileTree.mjs"; import "./tests/FletcherChecksum.mjs"; diff --git a/tests/operations/tests/ExtractHashes.mjs b/tests/operations/tests/ExtractHashes.mjs new file mode 100644 index 00000000..1dfb1ff2 --- /dev/null +++ b/tests/operations/tests/ExtractHashes.mjs @@ -0,0 +1,77 @@ +/** + * ExtractHashes tests. + * + * @author mshwed [m@ttshwed.com] + * @copyright Crown Copyright 2024 + * @license Apache-2.0 + */ +import TestRegister from "../../lib/TestRegister.mjs"; + +TestRegister.addTests([ + { + name: "Extract MD5 hash", + input: "The quick brown fox jumps over the lazy dog\n\nMD5: 9e107d9d372bb6826bd81d3542a419d6", + expectedOutput: "9e107d9d372bb6826bd81d3542a419d6", + recipeConfig: [ + { + "op": "Extract Hashes", + "args": [32, false, false] + }, + ], + }, + { + name: "Extract SHA1 hash", + input: "The quick brown fox jumps over the lazy dog\n\nSHA1: 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12", + expectedOutput: "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12", + recipeConfig: [ + { + "op": "Extract Hashes", + "args": [40, false, false] + }, + ], + }, + { + name: "Extract SHA256 hash", + input: "The quick brown fox jumps over the lazy dog\n\nSHA256: d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592", + expectedOutput: "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592", + recipeConfig: [ + { + "op": "Extract Hashes", + "args": [64, false, false] + }, + ], + }, + { + name: "Extract SHA512 hash", + input: "The quick brown fox jumps over the lazy dog\n\nSHA512: 07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6", + expectedOutput: "07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6", + recipeConfig: [ + { + "op": "Extract Hashes", + "args": [128, false, false] + }, + ], + }, + { + name: "Extract all hashes", + input: "The quick brown fox jumps over the lazy dog\n\nMD5: 9e107d9d372bb6826bd81d3542a419d6\nSHA1: 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12\nSHA256: d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592", + expectedOutput: "9e107d9d372bb6826bd81d3542a419d6\n2fd4e1c67a2d28fced849ee1bb76e7391b93eb12\nd7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592", + recipeConfig: [ + { + "op": "Extract Hashes", + "args": [0, true, false] + }, + ], + }, + { + name: "Extract hashes with total count", + input: "The quick brown fox jumps over the lazy dog\n\nMD5: 9e107d9d372bb6826bd81d3542a419d6\nSHA1: 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12\nSHA256: d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592", + expectedOutput: "Total Results: 3\n\n9e107d9d372bb6826bd81d3542a419d6\n2fd4e1c67a2d28fced849ee1bb76e7391b93eb12\nd7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592", + recipeConfig: [ + { + "op": "Extract Hashes", + "args": [0, true, true] + }, + ], + } +]); From 077b11e33bc9e1015147380309cd964f52bd657c Mon Sep 17 00:00:00 2001 From: mshwed Date: Mon, 1 Apr 2024 22:30:18 -0400 Subject: [PATCH 17/19] Fixed op name in test --- tests/operations/tests/ExtractHashes.mjs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/operations/tests/ExtractHashes.mjs b/tests/operations/tests/ExtractHashes.mjs index 1dfb1ff2..fe739418 100644 --- a/tests/operations/tests/ExtractHashes.mjs +++ b/tests/operations/tests/ExtractHashes.mjs @@ -14,7 +14,7 @@ TestRegister.addTests([ expectedOutput: "9e107d9d372bb6826bd81d3542a419d6", recipeConfig: [ { - "op": "Extract Hashes", + "op": "Extract hashes", "args": [32, false, false] }, ], @@ -25,7 +25,7 @@ TestRegister.addTests([ expectedOutput: "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12", recipeConfig: [ { - "op": "Extract Hashes", + "op": "Extract hashes", "args": [40, false, false] }, ], @@ -36,7 +36,7 @@ TestRegister.addTests([ expectedOutput: "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592", recipeConfig: [ { - "op": "Extract Hashes", + "op": "Extract hashes", "args": [64, false, false] }, ], @@ -47,7 +47,7 @@ TestRegister.addTests([ expectedOutput: "07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6", recipeConfig: [ { - "op": "Extract Hashes", + "op": "Extract hashes", "args": [128, false, false] }, ], @@ -58,7 +58,7 @@ TestRegister.addTests([ expectedOutput: "9e107d9d372bb6826bd81d3542a419d6\n2fd4e1c67a2d28fced849ee1bb76e7391b93eb12\nd7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592", recipeConfig: [ { - "op": "Extract Hashes", + "op": "Extract hashes", "args": [0, true, false] }, ], @@ -69,7 +69,7 @@ TestRegister.addTests([ expectedOutput: "Total Results: 3\n\n9e107d9d372bb6826bd81d3542a419d6\n2fd4e1c67a2d28fced849ee1bb76e7391b93eb12\nd7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592", recipeConfig: [ { - "op": "Extract Hashes", + "op": "Extract hashes", "args": [0, true, true] }, ], From fda77cf37a60b00782bc3976cef222c8ce252c7b Mon Sep 17 00:00:00 2001 From: Janne Kataja Date: Tue, 2 Apr 2024 21:30:59 +0200 Subject: [PATCH 18/19] add option to show Parse CSR only supports RSA --- src/core/operations/ParseCSR.mjs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/core/operations/ParseCSR.mjs b/src/core/operations/ParseCSR.mjs index 15baa2c0..ad891902 100644 --- a/src/core/operations/ParseCSR.mjs +++ b/src/core/operations/ParseCSR.mjs @@ -31,6 +31,11 @@ class ParseCSR extends Operation { "type": "option", "value": ["PEM"] }, + { + "name": "Key type", + "type": "option", + "value": ["RSA"] + }, { "name": "Strict ASN.1 value lengths", "type": "boolean", From c7952715028a3382420d4d2b6c9314c9f416784e Mon Sep 17 00:00:00 2001 From: a3957273 <89583054+a3957273@users.noreply.github.com> Date: Tue, 2 Apr 2024 20:27:48 +0000 Subject: [PATCH 19/19] Change output to 'html' --- src/core/operations/DateTimeDelta.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/operations/DateTimeDelta.mjs b/src/core/operations/DateTimeDelta.mjs index c923374d..35090606 100644 --- a/src/core/operations/DateTimeDelta.mjs +++ b/src/core/operations/DateTimeDelta.mjs @@ -24,7 +24,7 @@ class DateTimeDelta extends Operation { this.description = "Calculates a new DateTime value given an input DateTime value and a time difference (delta) from the input DateTime value."; this.infoURL = ""; this.inputType = "string"; - this.outputType = "string"; + this.outputType = "html"; this.args = [ { "name": "Built in formats",