소스 검색

Merge branch 'j433866-ssh-host-key'

n1474335 5 년 전
부모
커밋
06b385563c
5개의 변경된 파일220개의 추가작업 그리고 2개의 파일을 삭제
  1. 3 1
      src/core/config/Categories.json
  2. 150 0
      src/core/operations/ParseSSHHostKey.mjs
  3. 1 1
      tests/node/tests/nodeApi.mjs
  4. 1 0
      tests/operations/index.mjs
  5. 65 0
      tests/operations/tests/ParseSSHHostKey.mjs

+ 3 - 1
src/core/config/Categories.json

@@ -122,7 +122,8 @@
             "PGP Encrypt",
             "PGP Decrypt",
             "PGP Encrypt and Sign",
-            "PGP Decrypt and Verify"
+            "PGP Decrypt and Verify",
+            "Parse SSH Host Key"
         ]
     },
     {
@@ -166,6 +167,7 @@
             "Parse IP range",
             "Parse IPv6 address",
             "Parse IPv4 header",
+            "Parse SSH Host Key",
             "Parse URI",
             "URL Encode",
             "URL Decode",

+ 150 - 0
src/core/operations/ParseSSHHostKey.mjs

@@ -0,0 +1,150 @@
+/**
+ * @author j433866 [j433866@gmail.com]
+ * @copyright Crown Copyright 2019
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+import OperationError from "../errors/OperationError";
+import Utils from "../Utils";
+import { fromBase64 } from "../lib/Base64";
+import { fromHex, toHexFast } from "../lib/Hex";
+
+/**
+ * Parse SSH Host Key operation
+ */
+class ParseSSHHostKey extends Operation {
+
+    /**
+     * ParseSSHHostKey constructor
+     */
+    constructor() {
+        super();
+
+        this.name = "Parse SSH Host Key";
+        this.module = "Default";
+        this.description = "Parses a SSH host key and extracts fields from it.<br>The key type can be:<ul><li>ssh-rsa</li><li>ssh-dss</li><li>ecdsa-sha2</li></ul>The key format can be either Hex or Base64.";
+        this.infoURL = "https://wikipedia.org/wiki/Secure_Shell";
+        this.inputType = "string";
+        this.outputType = "string";
+        this.args = [
+            {
+                name: "Input Format",
+                type: "option",
+                value: [
+                    "Auto",
+                    "Base64",
+                    "Hex"
+                ]
+            }
+        ];
+    }
+
+    /**
+     * @param {string} input
+     * @param {Object[]} args
+     * @returns {string}
+     */
+    run(input, args) {
+        const [inputFormat] = args,
+            inputKey = this.convertKeyToBinary(input.trim(), inputFormat),
+            fields = this.parseKey(inputKey),
+            keyType = Utils.byteArrayToChars(fromHex(fields[0]), "");
+
+        let output = `Key type: ${keyType}`;
+
+        if (keyType === "ssh-rsa") {
+            output += `\nExponent: 0x${fields[1]}`;
+            output += `\nModulus: 0x${fields[2]}`;
+        } else if (keyType === "ssh-dss") {
+            output += `\np: 0x${fields[1]}`;
+            output += `\nq: 0x${fields[2]}`;
+            output += `\ng: 0x${fields[3]}`;
+            output += `\ny: 0x${fields[4]}`;
+        } else if (keyType.startsWith("ecdsa-sha2")) {
+            output += `\nCurve: ${Utils.byteArrayToChars(fromHex(fields[1]))}`;
+            output += `\nPoint: 0x${fields.slice(2)}`;
+        } else {
+            output += "\nUnsupported key type.";
+            output += `\nParameters: ${fields.slice(1)}`;
+        }
+
+        return output;
+    }
+
+    /**
+     * Converts the key to binary format from either hex or base64
+     *
+     * @param {string} inputKey
+     * @param {string} inputFormat
+     * @returns {byteArray}
+     */
+    convertKeyToBinary(inputKey, inputFormat) {
+        const keyPattern = new RegExp(/^(?:[ssh]|[ecdsa-sha2])\S+\s+(\S*)/),
+            keyMatch = inputKey.match(keyPattern);
+
+        if (keyMatch) {
+            inputKey = keyMatch[1];
+        }
+
+        if (inputFormat === "Auto") {
+            inputFormat = this.detectKeyFormat(inputKey);
+        }
+        if (inputFormat === "Hex") {
+            return fromHex(inputKey);
+        } else if (inputFormat === "Base64") {
+            return fromBase64(inputKey, null, "byteArray");
+        } else {
+            throw new OperationError("Invalid input format.");
+        }
+    }
+
+
+    /**
+     * Detects if the key is base64 or hex encoded
+     *
+     * @param {string} inputKey
+     * @returns {string}
+     */
+    detectKeyFormat(inputKey) {
+        const hexPattern = new RegExp(/^(?:[\dA-Fa-f]{2}[ ,;:]?)+$/);
+        const b64Pattern = new RegExp(/^\s*(?:[A-Za-z\d+/]{4})+(?:[A-Za-z\d+/]{2}==|[A-Za-z\d+/]{3}=)?\s*$/);
+
+        if (hexPattern.test(inputKey)) {
+            return "Hex";
+        } else if (b64Pattern.test(inputKey)) {
+            return "Base64";
+        } else {
+            throw new OperationError("Unable to detect input key format.");
+        }
+    }
+
+
+    /**
+     * Parses fields from the key
+     *
+     * @param {byteArray} key
+     */
+    parseKey(key) {
+        const fields = [];
+        while (key.length > 0) {
+            const lengthField = key.slice(0, 4);
+            let decodedLength = 0;
+            for (let i = 0; i < lengthField.length; i++) {
+                decodedLength += lengthField[i];
+                decodedLength = decodedLength << 8;
+            }
+            decodedLength = decodedLength >> 8;
+            // Break if length wasn't decoded correctly
+            if (decodedLength <= 0) break;
+
+            fields.push(toHexFast(key.slice(4, 4 + decodedLength)));
+            key = key.slice(4 + decodedLength);
+        }
+
+        return fields;
+    }
+
+}
+
+export default ParseSSHHostKey;

+ 1 - 1
tests/node/tests/nodeApi.mjs

@@ -136,7 +136,7 @@ TestRegister.addApiTests([
 
     it("chef.help: returns multiple results", () => {
         const result = chef.help("base 64");
-        assert.strictEqual(result.length, 10);
+        assert.strictEqual(result.length, 11);
     }),
 
     it("chef.help: looks in description for matches too", () => {

+ 1 - 0
tests/operations/index.mjs

@@ -86,6 +86,7 @@ import "./tests/Typex";
 import "./tests/BLAKE2b";
 import "./tests/BLAKE2s";
 import "./tests/Protobuf";
+import "./tests/ParseSSHHostKey";
 
 // Cannot test operations that use the File type yet
 //import "./tests/SplitColourChannels";

+ 65 - 0
tests/operations/tests/ParseSSHHostKey.mjs

@@ -0,0 +1,65 @@
+/**
+ * Parse SSH Host Key tests
+ *
+ * @author j433866 [j433866@gmail.com]
+ * @copyright Crown Copyright 2019
+ * @license Apache-2.0
+ */
+import TestRegister from "../../lib/TestRegister.mjs";
+
+TestRegister.addTests([
+    {
+        name: "SSH Host Key: RSA",
+        input: "AAAAB3NzaC1yc2EAAAADAQABAAABAQDiJZ/9W9Ix/Dk9b+K4E+RGCug1AtkGXaJ9vNIY0YHFHLpWsB8DAuh/cGEI9TLbL1gzR2wG+RJNQ2EAQVWe6ypkK63Jm4zw4re+vhEiszpnP889J0h5N9yzyTndesrl4d3cQtv861FcKDPxUJbRALdtl6gwOB7BCL8gsXJLLVLO4EesrbPXD454qpVt7CgJXEXByOFjcIm3XwkdOnXMPHHnMSD7EIN1SvQMD6PfIDrbDd6KQt5QXW/Rc/BsfX5cbUIV1QW5A/GbepXHHKmWRtLC2J/mH3hW2Zq/hITPEaJdG1CtIilQmJaZGXpfGIwFeb0Av9pSL926arZZ6vDi9ctF",
+        expectedOutput: `Key type: ssh-rsa
+Exponent: 0x010001
+Modulus: 0x00e2259ffd5bd231fc393d6fe2b813e4460ae83502d9065da27dbcd218d181c51cba56b01f0302e87f706108f532db2f5833476c06f9124d43610041559eeb2a642badc99b8cf0e2b7bebe1122b33a673fcf3d27487937dcb3c939dd7acae5e1dddc42dbfceb515c2833f15096d100b76d97a830381ec108bf20b1724b2d52cee047acadb3d70f8e78aa956dec28095c45c1c8e1637089b75f091d3a75cc3c71e73120fb1083754af40c0fa3df203adb0dde8a42de505d6fd173f06c7d7e5c6d4215d505b903f19b7a95c71ca99646d2c2d89fe61f7856d99abf8484cf11a25d1b50ad222950989699197a5f188c0579bd00bfda522fddba6ab659eaf0e2f5cb45`,
+        recipeConfig: [
+            {
+                op: "Parse SSH Host Key",
+                args: ["Base64"]
+            }
+        ]
+    },
+    {
+        name: "SSH Host Key: DSA",
+        input: "AAAAB3NzaC1kc3MAAACBAMnoZCOzvaQqs//9mxK2USZvJBc7b1dFJiBcV80abN6maE+203pTRPIPCpPt0deQxv4YN3dSHoodEcArWxs1QRAIuRsQIvsUP7chovzGnxP84XWK5sbfrseD0vxZ7UR0NaAFPcSgeXcWC1SG9uvrAJQlyp4DBy+fKuqiYmwaz0bHAAAAFQCXNJ4yiE1V7LpCU2V1JKbqDvICMwAAAIB/5aR1iBOeyCVpj0dP3YZmoxd9R7FCC/0UuOf0lx4E6WHT6Z2QuPBhc2mpNDq2M0VF9oJfVWgcfG8r1rlXaCYODSacGcbnW5VKQ+LKkkALmg4h8jFCHReUC+Hmia/v8LyDwPO1wK6ETn7a3m80yM7gAU5ZNurVIVVP2lB65mjEsQAAAIA3ct9YRB6iUCvOD45sZM1C9oTC24Ttmaou0GcpWx3h0/iZ8mbil1cjaO9frRNZ/vSSVWEhEDNG8gwkjZWlvnJL3y1XUxbMll4WbmI/Q1kzKwopceaFwMbYTPKDg6L1RtCMUxSUyKsFk1c4SpEPlDS7DApZs5PgmWgMd/u6vwMXyg==",
+        expectedOutput: `Key type: ssh-dss
+p: 0x00c9e86423b3bda42ab3fffd9b12b651266f24173b6f574526205c57cd1a6cdea6684fb6d37a5344f20f0a93edd1d790c6fe183777521e8a1d11c02b5b1b35411008b91b1022fb143fb721a2fcc69f13fce1758ae6c6dfaec783d2fc59ed447435a0053dc4a07977160b5486f6ebeb009425ca9e03072f9f2aeaa2626c1acf46c7
+q: 0x0097349e32884d55ecba4253657524a6ea0ef20233
+g: 0x7fe5a47588139ec825698f474fdd8666a3177d47b1420bfd14b8e7f4971e04e961d3e99d90b8f0617369a9343ab6334545f6825f55681c7c6f2bd6b95768260e0d269c19c6e75b954a43e2ca92400b9a0e21f231421d17940be1e689afeff0bc83c0f3b5c0ae844e7edade6f34c8cee0014e5936ead521554fda507ae668c4b1
+y: 0x3772df58441ea2502bce0f8e6c64cd42f684c2db84ed99aa2ed067295b1de1d3f899f266e297572368ef5fad1359fef492556121103346f20c248d95a5be724bdf2d575316cc965e166e623f4359332b0a2971e685c0c6d84cf28383a2f546d08c531494c8ab059357384a910f9434bb0c0a59b393e099680c77fbbabf0317ca`,
+        recipeConfig: [
+            {
+                op: "Parse SSH Host Key",
+                args: ["Base64"]
+            }
+        ]
+    },
+    {
+        name: "SSH Host Key: ECDSA",
+        input: "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBGxZWSAGJyJQoVBwFCpr420eRUZDE/kw2YWm5vDro8050DZ1ZzqIuYaNl0BGzMcRTeasGtJuI8G84ZQQSgca3C4=",
+        expectedOutput: `Key type: ecdsa-sha2-nistp256
+Curve: nistp256
+Point: 0x046c59592006272250a15070142a6be36d1e45464313f930d985a6e6f0eba3cd39d03675673a88b9868d974046ccc7114de6ac1ad26e23c1bce194104a071adc2e`,
+        recipeConfig: [
+            {
+                op: "Parse SSH Host Key",
+                args: ["Base64"]
+            }
+        ]
+    },
+    {
+        name: "SSH Host Key: Extract key",
+        input: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDiJZ/9W9Ix/Dk9b+K4E+RGCug1AtkGXaJ9vNIY0YHFHLpWsB8DAuh/cGEI9TLbL1gzR2wG+RJNQ2EAQVWe6ypkK63Jm4zw4re+vhEiszpnP889J0h5N9yzyTndesrl4d3cQtv861FcKDPxUJbRALdtl6gwOB7BCL8gsXJLLVLO4EesrbPXD454qpVt7CgJXEXByOFjcIm3XwkdOnXMPHHnMSD7EIN1SvQMD6PfIDrbDd6KQt5QXW/Rc/BsfX5cbUIV1QW5A/GbepXHHKmWRtLC2J/mH3hW2Zq/hITPEaJdG1CtIilQmJaZGXpfGIwFeb0Av9pSL926arZZ6vDi9ctF test@test",
+        expectedOutput: `Key type: ssh-rsa
+Exponent: 0x010001
+Modulus: 0x00e2259ffd5bd231fc393d6fe2b813e4460ae83502d9065da27dbcd218d181c51cba56b01f0302e87f706108f532db2f5833476c06f9124d43610041559eeb2a642badc99b8cf0e2b7bebe1122b33a673fcf3d27487937dcb3c939dd7acae5e1dddc42dbfceb515c2833f15096d100b76d97a830381ec108bf20b1724b2d52cee047acadb3d70f8e78aa956dec28095c45c1c8e1637089b75f091d3a75cc3c71e73120fb1083754af40c0fa3df203adb0dde8a42de505d6fd173f06c7d7e5c6d4215d505b903f19b7a95c71ca99646d2c2d89fe61f7856d99abf8484cf11a25d1b50ad222950989699197a5f188c0579bd00bfda522fddba6ab659eaf0e2f5cb45`,
+        recipeConfig: [
+            {
+                op: "Parse SSH Host Key",
+                args: ["Base64"]
+            }
+        ]
+    }
+]);