Procházet zdrojové kódy

Ported x86 Disassembler & PGP ops

Matt C před 7 roky
rodič
revize
2b0c327001

+ 116 - 0
src/core/lib/PGP.mjs

@@ -0,0 +1,116 @@
+/**
+ * PGP functions.
+ *
+ * @author tlwr [toby@toby.codes]
+ * @author Matt C [matt@artemisbot.uk]
+ * @author n1474335 [n1474335@gmail.com]
+ *
+ * @copyright Crown Copyright 2018
+ * @license Apache-2.0
+ *
+ */
+
+import * as kbpgp from "kbpgp";
+import { promisify } from "es6-promisify";
+
+/**
+ * Progress callback
+ *
+ */
+export const ASP = kbpgp.ASP({
+    "progress_hook": info => {
+        let msg = "";
+
+        switch (info.what) {
+            case "guess":
+                msg = "Guessing a prime";
+                break;
+            case "fermat":
+                msg = "Factoring prime using Fermat's factorization method";
+                break;
+            case "mr":
+                msg = "Performing Miller-Rabin primality test";
+                break;
+            case "passed_mr":
+                msg = "Passed Miller-Rabin primality test";
+                break;
+            case "failed_mr":
+                msg = "Failed Miller-Rabin primality test";
+                break;
+            case "found":
+                msg = "Prime found";
+                break;
+            default:
+                msg = `Stage: ${info.what}`;
+        }
+
+        if (ENVIRONMENT_IS_WORKER())
+            self.sendStatusMessage(msg);
+    }
+});
+
+/**
+ * Get size of subkey
+ *
+ * @param {number} keySize
+ * @returns {number}
+ */
+export function getSubkeySize(keySize) {
+    return {
+        1024: 1024,
+        2048: 1024,
+        4096: 2048,
+        256:   256,
+        384:   256,
+    }[keySize];
+}
+
+/**
+* Import private key and unlock if necessary
+*
+* @param {string} privateKey
+* @param {string} [passphrase]
+* @returns {Object}
+*/
+export async function importPrivateKey(privateKey, passphrase) {
+    try {
+        const key = await promisify(kbpgp.KeyManager.import_from_armored_pgp)({
+            armored: privateKey,
+            opts: {
+                "no_check_keys": true
+            }
+        });
+        if (key.is_pgp_locked()) {
+            if (passphrase) {
+                await promisify(key.unlock_pgp.bind(key))({
+                    passphrase
+                });
+            } else {
+                throw "Did not provide passphrase with locked private key.";
+            }
+        }
+        return key;
+    } catch (err) {
+        throw `Could not import private key: ${err}`;
+    }
+}
+
+/**
+ * Import public key
+ *
+ * @param {string} publicKey
+ * @returns {Object}
+ */
+export async function importPublicKey (publicKey) {
+    try {
+        const key = await promisify(kbpgp.KeyManager.import_from_armored_pgp)({
+            armored: publicKey,
+            opts: {
+                "no_check_keys": true
+            }
+        });
+        return key;
+    } catch (err) {
+        throw `Could not import public key: ${err}`;
+    }
+}

+ 127 - 0
src/core/operations/DisassembleX86.mjs

@@ -0,0 +1,127 @@
+/**
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2017
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+import disassemble from "../vendor/DisassembleX86-64.js";
+/**
+ * Disassemble x86 operation
+ */
+class DisassembleX86 extends Operation {
+
+    /**
+     * DisassembleX86 constructor
+     */
+    constructor() {
+        super();
+
+        this.name = "Disassemble x86";
+        this.module = "Shellcode";
+        this.description = "Disassembly is the process of translating machine language into assembly language.<br><br>This operation supports 64-bit, 32-bit and 16-bit code written for Intel or AMD x86 processors. It is particularly useful for reverse engineering shellcode.<br><br>Input should be in hexadecimal.";
+        this.inputType = "string";
+        this.outputType = "string";
+        this.args = [
+            {
+                "name": "Bit mode",
+                "type": "option",
+                "value": ["64", "32", "16"]
+            },
+            {
+                "name": "Compatibility",
+                "type": "option",
+                "value": [
+                    "Full x86 architecture",
+                    "Knights Corner",
+                    "Larrabee",
+                    "Cyrix",
+                    "Geode",
+                    "Centaur",
+                    "X86/486"
+                ]
+            },
+            {
+                "name": "Code Segment (CS)",
+                "type": "number",
+                "value": 16
+            },
+            {
+                "name": "Offset (IP)",
+                "type": "number",
+                "value": 0
+            },
+            {
+                "name": "Show instruction hex",
+                "type": "boolean",
+                "value": true
+            },
+            {
+                "name": "Show instruction position",
+                "type": "boolean",
+                "value": true
+            }
+        ];
+    }
+
+    /**
+     * @param {string} input
+     * @param {Object[]} args
+     * @returns {string}
+     */
+    run(input, args) {
+        const mode = args[0],
+            compatibility = args[1],
+            codeSegment = args[2],
+            offset = args[3],
+            showInstructionHex = args[4],
+            showInstructionPos = args[5];
+
+        switch (mode) {
+            case "64":
+                disassemble.setBitMode(2);
+                break;
+            case "32":
+                disassemble.setBitMode(1);
+                break;
+            case "16":
+                disassemble.setBitMode(0);
+                break;
+            default:
+                throw "Invalid mode value";
+        }
+
+        switch (compatibility) {
+            case "Full x86 architecture":
+                disassemble.CompatibilityMode(0);
+                break;
+            case "Knights Corner":
+                disassemble.CompatibilityMode(1);
+                break;
+            case "Larrabee":
+                disassemble.CompatibilityMode(2);
+                break;
+            case "Cyrix":
+                disassemble.CompatibilityMode(3);
+                break;
+            case "Geode":
+                disassemble.CompatibilityMode(4);
+                break;
+            case "Centaur":
+                disassemble.CompatibilityMode(5);
+                break;
+            case "X86/486":
+                disassemble.CompatibilityMode(6);
+                break;
+        }
+
+        disassemble.SetBasePosition(codeSegment + ":" + offset);
+        disassemble.setShowInstructionHex(showInstructionHex);
+        disassemble.setShowInstructionPos(showInstructionPos);
+        disassemble.LoadBinCode(input.replace(/\s/g, ""));
+        return disassemble.LDisassemble();
+    }
+
+}
+
+export default DisassembleX86;

+ 114 - 0
src/core/operations/GeneratePGPKeyPair.mjs

@@ -0,0 +1,114 @@
+/**
+ * @author tlwr [toby@toby.codes]
+ * @author Matt C [matt@artemisbot.uk]
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2017
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+import * as kbpgp from "kbpgp";
+import { promisify } from "es6-promisify";
+import { getSubkeySize, ASP } from "../lib/PGP";
+/**
+ * Generate PGP Key Pair operation
+ */
+class GeneratePGPKeyPair extends Operation {
+
+    /**
+     * GeneratePGPKeyPair constructor
+     */
+    constructor() {
+        super();
+
+        this.name = "Generate PGP Key Pair";
+        this.module = "PGP";
+        this.description = "Generates a new public/private PGP key pair. Supports RSA and Eliptic Curve (EC) keys.";
+        this.inputType = "string";
+        this.outputType = "string";
+        this.args = [
+            {
+                "name": "Key type",
+                "type": "option",
+                "value": ["RSA-1024", "RSA-2048", "RSA-4096", "ECC-256", "ECC-384"]
+            },
+            {
+                "name": "Password (optional)",
+                "type": "string",
+                "value": ""
+            },
+            {
+                "name": "Name (optional)",
+                "type": "string",
+                "value": ""
+            },
+            {
+                "name": "Email (optional)",
+                "type": "string",
+                "value": ""
+            }
+        ];
+    }
+
+    /**
+     * @param {string} input
+     * @param {Object[]} args
+     * @returns {string}
+     */
+    run(input, args) {
+        const [keyType, keySize] = args[0].split("-"),
+            password = args[1],
+            name = args[2],
+            email = args[3];
+        let userIdentifier = "";
+
+        if (name) userIdentifier += name;
+        if (email) userIdentifier += ` <${email}>`;
+
+        let flags = kbpgp.const.openpgp.certify_keys;
+        flags |= kbpgp.const.openpgp.sign_data;
+        flags |= kbpgp.const.openpgp.auth;
+        flags |= kbpgp.const.openpgp.encrypt_comm;
+        flags |= kbpgp.const.openpgp.encrypt_storage;
+
+        const keyGenerationOptions = {
+            userid: userIdentifier,
+            ecc: keyType === "ecc",
+            primary: {
+                "nbits": keySize,
+                "flags": flags,
+                "expire_in": 0
+            },
+            subkeys: [{
+                "nbits": getSubkeySize(keySize),
+                "flags": kbpgp.const.openpgp.sign_data,
+                "expire_in": 86400 * 365 * 8
+            }, {
+                "nbits": getSubkeySize(keySize),
+                "flags": kbpgp.const.openpgp.encrypt_comm | kbpgp.const.openpgp.encrypt_storage,
+                "expire_in": 86400 * 365 * 2
+            }],
+            asp: ASP
+        };
+
+        return new Promise(async (resolve, reject) => {
+            try {
+                const unsignedKey = await promisify(kbpgp.KeyManager.generate)(keyGenerationOptions);
+                await promisify(unsignedKey.sign.bind(unsignedKey))({});
+
+                const signedKey = unsignedKey,
+                    privateKeyExportOptions = {};
+
+                if (password) privateKeyExportOptions.passphrase = password;
+                const privateKey = await promisify(signedKey.export_pgp_private.bind(signedKey))(privateKeyExportOptions);
+                const publicKey = await promisify(signedKey.export_pgp_public.bind(signedKey))({});
+                resolve(privateKey + "\n" + publicKey.trim());
+            } catch (err) {
+                reject(`Error whilst generating key pair: ${err}`);
+            }
+        });
+    }
+
+}
+
+export default GeneratePGPKeyPair;

+ 74 - 0
src/core/operations/PGPDecrypt.mjs

@@ -0,0 +1,74 @@
+/**
+ * @author tlwr [toby@toby.codes]
+ * @copyright Crown Copyright 2017
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+import * as kbpgp from "kbpgp";
+import { promisify } from "es6-promisify";
+import { ASP, importPrivateKey } from "../lib/PGP";
+
+/**
+ * PGP Decrypt operation
+ */
+class PGPDecrypt extends Operation {
+
+    /**
+     * PGPDecrypt constructor
+     */
+    constructor() {
+        super();
+
+        this.name = "PGP Decrypt";
+        this.module = "PGP";
+        this.description = "Input: the ASCII-armoured PGP message you want to decrypt.\n<br><br>\nArguments: the ASCII-armoured PGP private key of the recipient, \n(and the private key password if necessary).\n<br><br>\nPretty Good Privacy is an encryption standard (OpenPGP) used for encrypting, decrypting, and signing messages.\n<br><br>\nThis function uses the Keybase implementation of PGP.";
+        this.inputType = "string";
+        this.outputType = "string";
+        this.args = [
+            {
+                "name": "Private key of recipient",
+                "type": "text",
+                "value": ""
+            },
+            {
+                "name": "Private key passphrase",
+                "type": "string",
+                "value": ""
+            }
+        ];
+    }
+
+    /**
+     * @param {string} input
+     * @param {Object[]} args
+     * @returns {string}
+     */
+    async run(input, args) {
+        const encryptedMessage = input,
+            privateKey = args[0],
+            passphrase = args[1],
+            keyring = new kbpgp.keyring.KeyRing();
+        let plaintextMessage;
+
+        if (!privateKey) return "Enter the private key of the recipient.";
+
+        const key = await importPrivateKey(privateKey, passphrase);
+        keyring.add_key_manager(key);
+
+        try {
+            plaintextMessage = await promisify(kbpgp.unbox)({
+                armored: encryptedMessage,
+                keyfetch: keyring,
+                asp: ASP
+            });
+        } catch (err) {
+            throw `Couldn't decrypt message with provided private key: ${err}`;
+        }
+
+        return plaintextMessage.toString();
+    }
+
+}
+
+export default PGPDecrypt;

+ 111 - 0
src/core/operations/PGPDecryptAndVerify.mjs

@@ -0,0 +1,111 @@
+/**
+ * @author tlwr [toby@toby.codes]
+ * @copyright Crown Copyright 2017
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+import * as kbpgp from "kbpgp";
+import { promisify } from "es6-promisify";
+import { ASP, importPrivateKey, importPublicKey } from "../lib/PGP";
+
+/**
+ * PGP Decrypt and Verify operation
+ */
+class PGPDecryptAndVerify extends Operation {
+
+    /**
+     * PGPDecryptAndVerify constructor
+     */
+    constructor() {
+        super();
+
+        this.name = "PGP Decrypt and Verify";
+        this.module = "PGP";
+        this.description = "Input: the ASCII-armoured encrypted PGP message you want to verify.\n<br><br>\nArguments: the ASCII-armoured PGP public key of the signer, \nthe ASCII-armoured private key of the recipient (and the private key password if necessary).\n<br><br>\nThis operation uses PGP to decrypt and verify an encrypted digital signature.\n<br><br>\nPretty Good Privacy is an encryption standard (OpenPGP) used for encrypting, decrypting, and signing messages.\n<br><br>\nThis function uses the Keybase implementation of PGP.";
+        this.inputType = "string";
+        this.outputType = "string";
+        this.args = [
+            {
+                "name": "Public key of signer",
+                "type": "text",
+                "value": ""
+            },
+            {
+                "name": "Private key of recipient",
+                "type": "text",
+                "value": ""
+            },
+            {
+                "name": "Private key password",
+                "type": "string",
+                "value": ""
+            }
+        ];
+    }
+
+    /**
+     * @param {string} input
+     * @param {Object[]} args
+     * @returns {string}
+     */
+    async run(input, args) {
+        const signedMessage = input,
+            publicKey = args[0],
+            privateKey = args[1],
+            passphrase = args[2],
+            keyring = new kbpgp.keyring.KeyRing();
+        let unboxedLiterals;
+
+        if (!publicKey) return "Enter the public key of the signer.";
+        if (!privateKey) return "Enter the private key of the recipient.";
+        const privKey = await importPrivateKey(privateKey, passphrase);
+        const pubKey = await importPublicKey(publicKey);
+        keyring.add_key_manager(privKey);
+        keyring.add_key_manager(pubKey);
+
+        try {
+            unboxedLiterals = await promisify(kbpgp.unbox)({
+                armored: signedMessage,
+                keyfetch: keyring,
+                asp: ASP
+            });
+            const ds = unboxedLiterals[0].get_data_signer();
+            if (ds) {
+                const km = ds.get_key_manager();
+                if (km) {
+                    const signer = km.get_userids_mark_primary()[0].components;
+                    let text = "Signed by ";
+                    if (signer.email || signer.username || signer.comment) {
+                        if (signer.username) {
+                            text += `${signer.username} `;
+                        }
+                        if (signer.comment) {
+                            text += `${signer.comment} `;
+                        }
+                        if (signer.email) {
+                            text += `<${signer.email}>`;
+                        }
+                        text += "\n";
+                    }
+                    text += [
+                        `PGP fingerprint: ${km.get_pgp_fingerprint().toString("hex")}`,
+                        `Signed on ${new Date(ds.sig.hashed_subpackets[0].time * 1000).toUTCString()}`,
+                        "----------------------------------\n"
+                    ].join("\n");
+                    text += unboxedLiterals.toString();
+                    return text.trim();
+                } else {
+                    return "Could not identify a key manager.";
+                }
+            } else {
+                return "The data does not appear to be signed.";
+            }
+        } catch (err) {
+            return `Couldn't verify message: ${err}`;
+        }
+    }
+
+}
+
+export default PGPDecryptAndVerify;

+ 72 - 0
src/core/operations/PGPEncrypt.mjs

@@ -0,0 +1,72 @@
+/**
+ * @author tlwr [toby@toby.codes]
+ * @copyright Crown Copyright 2017
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+import * as kbpgp from "kbpgp";
+import { promisify } from "es6-promisify";
+import { ASP } from "../lib/PGP";
+/**
+ * PGP Encrypt operation
+ */
+class PGPEncrypt extends Operation {
+
+    /**
+     * PGPEncrypt constructor
+     */
+    constructor() {
+        super();
+
+        this.name = "PGP Encrypt";
+        this.module = "PGP";
+        this.description = "Input: the message you want to encrypt.\n<br><br>\nArguments: the ASCII-armoured PGP public key of the recipient.\n<br><br>\nPretty Good Privacy is an encryption standard (OpenPGP) used for encrypting, decrypting, and signing messages.\n<br><br>\nThis function uses the Keybase implementation of PGP.";
+        this.inputType = "string";
+        this.outputType = "string";
+        this.args = [
+            {
+                "name": "Public key of recipient",
+                "type": "text",
+                "value": ""
+            }
+        ];
+    }
+
+    /**
+     * @param {string} input
+     * @param {Object[]} args
+     * @returns {string}
+     */
+    async run(input, args) {
+        const plaintextMessage = input,
+            plainPubKey = args[0];
+        let key,
+            encryptedMessage;
+
+        if (!plainPubKey) return "Enter the public key of the recipient.";
+
+        try {
+            key = await promisify(kbpgp.KeyManager.import_from_armored_pgp)({
+                armored: plainPubKey,
+            });
+        } catch (err) {
+            throw `Could not import public key: ${err}`;
+        }
+
+        try {
+            encryptedMessage = await promisify(kbpgp.box)({
+                "msg": plaintextMessage,
+                "encrypt_for": key,
+                "asp": ASP
+            });
+        } catch (err) {
+            throw `Couldn't encrypt message with provided public key: ${err}`;
+        }
+
+        return encryptedMessage.toString();
+    }
+
+}
+
+export default PGPEncrypt;

+ 80 - 0
src/core/operations/PGPEncryptAndSign.mjs

@@ -0,0 +1,80 @@
+/**
+ * @author tlwr [toby@toby.codes]
+ * @copyright Crown Copyright 2017
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+import * as kbpgp from "kbpgp";
+import { promisify } from "es6-promisify";
+import { ASP, importPrivateKey, importPublicKey } from "../lib/PGP";
+
+/**
+ * PGP Encrypt and Sign operation
+ */
+class PGPEncryptAndSign extends Operation {
+
+    /**
+     * PGPEncryptAndSign constructor
+     */
+    constructor() {
+        super();
+
+        this.name = "PGP Encrypt and Sign";
+        this.module = "PGP";
+        this.description = "Input: the cleartext you want to sign.\n<br><br>\nArguments: the ASCII-armoured private key of the signer (plus the private key password if necessary)\nand the ASCII-armoured PGP public key of the recipient.\n<br><br>\nThis operation uses PGP to produce an encrypted digital signature.\n<br><br>\nPretty Good Privacy is an encryption standard (OpenPGP) used for encrypting, decrypting, and signing messages.\n<br><br>\nThis function uses the Keybase implementation of PGP.";
+        this.inputType = "string";
+        this.outputType = "string";
+        this.args = [
+            {
+                "name": "Private key of signer",
+                "type": "text",
+                "value": ""
+            },
+            {
+                "name": "Private key passphrase",
+                "type": "string",
+                "value": ""
+            },
+            {
+                "name": "Public key of recipient",
+                "type": "text",
+                "value": ""
+            }
+        ];
+    }
+
+    /**
+     * @param {string} input
+     * @param {Object[]} args
+     * @returns {string}
+     */
+    async run(input, args) {
+        const message = input,
+            privateKey = args[0],
+            passphrase = args[1],
+            publicKey = args[2];
+        let signedMessage;
+
+        if (!privateKey) return "Enter the private key of the signer.";
+        if (!publicKey) return "Enter the public key of the recipient.";
+        const privKey = await importPrivateKey(privateKey, passphrase);
+        const pubKey = await importPublicKey(publicKey);
+
+        try {
+            signedMessage = await promisify(kbpgp.box)({
+                "msg": message,
+                "encrypt_for": pubKey,
+                "sign_with": privKey,
+                "asp": ASP
+            });
+        } catch (err) {
+            throw `Couldn't sign message: ${err}`;
+        }
+
+        return signedMessage;
+    }
+
+}
+
+export default PGPEncryptAndSign;