diff --git a/package-lock.json b/package-lock.json
index de3bc9bb..208c7003 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2330,6 +2330,14 @@
"integrity": "sha1-eePVhlU0aQn+bw9Fpd5oEDspTSA=",
"dev": true
},
+ "encoding": {
+ "version": "0.1.12",
+ "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz",
+ "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=",
+ "requires": {
+ "iconv-lite": "0.4.19"
+ }
+ },
"end-of-stream": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.0.tgz",
@@ -3414,8 +3422,7 @@
"graceful-fs": {
"version": "4.1.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
- "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
- "dev": true
+ "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg="
},
"grunt": {
"version": "1.0.1",
@@ -4064,8 +4071,7 @@
"iconv-lite": {
"version": "0.4.19",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz",
- "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==",
- "dev": true
+ "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ=="
},
"icss-replace-symbols": {
"version": "1.1.0",
@@ -4172,8 +4178,7 @@
"imurmurhash": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
- "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
- "dev": true
+ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o="
},
"indent-string": {
"version": "2.1.0",
@@ -4536,8 +4541,7 @@
"is-stream": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
- "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
- "dev": true
+ "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
},
"is-svg": {
"version": "2.1.0",
@@ -5554,6 +5558,15 @@
"lower-case": "1.1.4"
}
},
+ "node-fetch": {
+ "version": "1.7.3",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz",
+ "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==",
+ "requires": {
+ "encoding": "0.1.12",
+ "is-stream": "1.1.0"
+ }
+ },
"node-forge": {
"version": "0.6.33",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.6.33.tgz",
@@ -5599,6 +5612,14 @@
}
}
},
+ "node-localstorage": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/node-localstorage/-/node-localstorage-1.3.0.tgz",
+ "integrity": "sha1-LkNqro3Mms6XtDxlwWwNV3vgpVw=",
+ "requires": {
+ "write-file-atomic": "1.3.4"
+ }
+ },
"node-md6": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/node-md6/-/node-md6-0.1.0.tgz",
@@ -5771,6 +5792,15 @@
"mimic-fn": "1.1.0"
}
},
+ "openpgp": {
+ "version": "2.5.11",
+ "resolved": "https://registry.npmjs.org/openpgp/-/openpgp-2.5.11.tgz",
+ "integrity": "sha1-02yBnAkY4BLH0egSbkVRvAofJzg=",
+ "requires": {
+ "node-fetch": "1.7.3",
+ "node-localstorage": "1.3.0"
+ }
+ },
"opn": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/opn/-/opn-5.1.0.tgz",
@@ -7892,6 +7922,11 @@
"is-fullwidth-code-point": "2.0.0"
}
},
+ "slide": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz",
+ "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc="
+ },
"sntp": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/sntp/-/sntp-2.0.2.tgz",
@@ -9257,6 +9292,16 @@
"mkdirp": "0.5.1"
}
},
+ "write-file-atomic": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz",
+ "integrity": "sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8=",
+ "requires": {
+ "graceful-fs": "4.1.11",
+ "imurmurhash": "0.1.4",
+ "slide": "1.1.6"
+ }
+ },
"xml-char-classes": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/xml-char-classes/-/xml-char-classes-1.0.0.tgz",
diff --git a/package.json b/package.json
index 1c10572a..6c6f5885 100644
--- a/package.json
+++ b/package.json
@@ -89,6 +89,7 @@
"moment": "^2.19.2",
"moment-timezone": "^0.5.14",
"node-md6": "^0.1.0",
+ "openpgp": "^2.5.11",
"otp": "^0.1.3",
"sladex-blowfish": "^0.8.1",
"sortablejs": "^1.7.0",
diff --git a/src/core/config/OperationConfig.js b/src/core/config/OperationConfig.js
index 9caa4f91..14d0a4f0 100755
--- a/src/core/config/OperationConfig.js
+++ b/src/core/config/OperationConfig.js
@@ -27,6 +27,7 @@ import MAC from "../operations/MAC.js";
import MorseCode from "../operations/MorseCode.js";
import NetBIOS from "../operations/NetBIOS.js";
import PublicKey from "../operations/PublicKey.js";
+import PGP from "../operations/PGP.js";
import Punycode from "../operations/Punycode.js";
import Rotate from "../operations/Rotate.js";
import SeqUtils from "../operations/SeqUtils.js";
@@ -3845,6 +3846,353 @@ const OperationConfig = {
}
]
},
+ "PGP Encrypt": {
+ module: "PGP",
+ description: [
+ "Input: the message you want to encrypt.",
+ "
",
+ "Arguments: the ASCII-armoured PGP public key of the recipient.",
+ "
",
+ "Pretty Good Privacy is an encryption standard (OpenPGP) used for encrypting, decrypting, and signing messages.",
+ "
",
+ "This function relies on OpenPGP.js for the implementation of PGP.",
+ "
",
+ "See more at https://openpgpjs.org/",
+ ].join("\n"),
+ inputType: "string",
+ outputType: "string",
+ args: [
+ {
+ name: "Public key",
+ type: "text",
+ value: "",
+ },
+ ]
+ },
+ "PGP Decrypt": {
+ module: "PGP",
+ description: [
+ "Input: the ASCII-armoured PGP message you want to decrypt.",
+ "
",
+ "Arguments: the ASCII-armoured PGP private key of the recipient, ",
+ "(and the private key password if necessary).",
+ "
",
+ "Pretty Good Privacy is an encryption standard (OpenPGP) used for encrypting, decrypting, and signing messages.",
+ "
",
+ "This function relies on OpenPGP.js for the implementation of PGP.
See more at https://openpgpjs.org/",
+ ].join("\n"),
+ inputType: "string",
+ outputType: "string",
+ args: [
+ {
+ name: "Private key",
+ type: "text",
+ value: "",
+ },
+ {
+ name: "Private key password",
+ type: "string",
+ value: "",
+ },
+ ]
+ },
+ "PGP Sign": {
+ module: "PGP",
+ description: [
+ "Input: the cleartext you want to sign.",
+ "
",
+ "Arguments: the ASCII-armoured PGP public key of the recipient, ",
+ "the ASCII-armoured private key of the signer (and the private key password if necessary).",
+ "
",
+ "This operation uses PGP to produce an encrypted digital signature.",
+ "
",
+ "Pretty Good Privacy is an encryption standard (OpenPGP) used for encrypting, decrypting, and signing messages.",
+ "
",
+ "This function relies on OpenPGP.js for the implementation of PGP.",
+ "
",
+ "See more at https://openpgpjs.org/",
+ ].join("\n"),
+ inputType: "string",
+ outputType: "string",
+ args: [
+ {
+ name: "Public key",
+ type: "text",
+ value: "",
+ },
+ {
+ name: "Private key",
+ type: "text",
+ value: "",
+ },
+ {
+ name: "Private key password",
+ type: "string",
+ value: "",
+ },
+ ]
+ },
+ "PGP Verify": {
+ module: "PGP",
+ description: [
+ "Input: the ASCII-armoured encrypted PGP message you want to verify.",
+ "
",
+ "Arguments: the ASCII-armoured PGP public key of the signer, ",
+ "the ASCII-armoured private key of the recipient (and the private key password if necessary).",
+ "
",
+ "This operation uses PGP to decrypt and verify an encrypted digital signature.",
+ "
",
+ "Pretty Good Privacy is an encryption standard (OpenPGP) used for encrypting, decrypting, and signing messages.",
+ "
",
+ "This function relies on OpenPGP.js for the implementation of PGP.",
+ "
",
+ "See more at https://openpgpjs.org/",
+ ].join("\n"),
+ inputType: "string",
+ outputType: "string",
+ args: [
+ {
+ name: "Public key",
+ type: "text",
+ value: "",
+ },
+ {
+ name: "Private key",
+ type: "text",
+ value: "",
+ },
+ {
+ name: "Private key password",
+ type: "string",
+ value: "",
+ },
+ ]
+ },
+ "Sign PGP Detached": {
+ module: "PGP",
+ description: [
+ "Input: the cleartext you want to sign.",
+ "
",
+ "Arguments: the ASCII-armoured PGP private key of the signer, ",
+ " (and the private key password if necessary).",
+ "
",
+ "This operation uses PGP to produce a cleartext message and its digital signature. ",
+ "It outputs 3 files as HTML: ",
+ "the cleartext message (msg), ",
+ "the ASCII-armoured signature (msg.asc), and ",
+ "the raw bytes of the signature (msg.sig).",
+ "
",
+ "Pretty Good Privacy is an encryption standard (OpenPGP) used for encrypting, decrypting, and signing messages.",
+ "
",
+ "This function relies on OpenPGP.js for the implementation of PGP.",
+ "
",
+ "See more at https://openpgpjs.org/",
+ ].join("\n"),
+ inputType: "string",
+ outputType: "HTML",
+ args: [
+ {
+ name: "Private key",
+ type: "text",
+ value: "",
+ },
+ {
+ name: "Private key password",
+ type: "string",
+ value: "",
+ },
+ ]
+ },
+ "Verify PGP Detached": {
+ module: "PGP",
+ description: [
+ "Input: the cleartext of the message you want to verify.",
+ "
",
+ "Arguments: the ASCII-armoured PGP public key of the sender, ",
+ "the ASCII-armoured signature of the message.",
+ "
",
+ "This operation uses PGP to verify a detached cleartext PGP signature.",
+ "
",
+ "Pretty Good Privacy is an encryption standard (OpenPGP) used for encrypting, decrypting, and signing messages.",
+ "
",
+ "This function relies on OpenPGP.js for the implementation of PGP.",
+ "
",
+ "See more at https://openpgpjs.org/",
+ ].join("\n"),
+ inputType: "string",
+ outputType: "string",
+ args: [
+ {
+ name: "Public key",
+ type: "text",
+ value: "",
+ },
+ {
+ name: "Signature",
+ type: "text",
+ value: "",
+ },
+ ]
+ },
+ "Sign PGP Cleartext": {
+ module: "PGP",
+ description: [
+ "Input: the cleartext of the message you want to sign.",
+ "
",
+ "Arguments: the ASCII-armoured PGP private key of the signer, ",
+ "(and the private key password if necessary).",
+ "
",
+ "This operation uses PGP to produce a digital signature.",
+ "
",
+ "Pretty Good Privacy is an encryption standard (OpenPGP) used for encrypting, decrypting, and signing messages.",
+ "
",
+ "This function relies on OpenPGP.js for the implementation of PGP.",
+ "
",
+ "See more at https://openpgpjs.org/",
+ ].join("\n"),
+ inputType: "string",
+ outputType: "string",
+ args: [
+ {
+ name: "Private key",
+ type: "text",
+ value: "",
+ },
+ {
+ name: "Private key password",
+ type: "string",
+ value: "",
+ },
+ ]
+ },
+ "Verify PGP Cleartext": {
+ module: "PGP",
+ description: [
+ "Input: the ASCII-armoured cleartext signature you want to verify.",
+ "
",
+ "Arguments: the ASCII-armoured PGP public key of the sender.",
+ "
",
+ "This operation uses PGP to verify a cleartext digital signature.",
+ "
",
+ "Pretty Good Privacy is an encryption standard (OpenPGP) used for encrypting, decrypting, and signing messages.",
+ "
",
+ "This function relies on OpenPGP.js for the implementation of PGP.",
+ "
",
+ "See more at https://openpgpjs.org/",
+ ].join("\n"),
+ inputType: "string",
+ outputType: "string",
+ args: [
+ {
+ name: "Public key",
+ type: "text",
+ value: "",
+ },
+ ]
+ },
+ "Generate PGP Key Pair": {
+ module: "PGP",
+ description: [
+ "Input is ignored.",
+ "
",
+ "This operation generates a PGP key pair.",
+ "
",
+ "Pretty Good Privacy is an encryption standard (OpenPGP) used for encrypting, decrypting, and signing messages.",
+ "
",
+ "This function relies on OpenPGP.js for the implementation of PGP.",
+ "
",
+ "See more at https://openpgpjs.org/",
+ ].join("\n"),
+ inputType: "string",
+ outputType: "string",
+ args: [
+ {
+ name: "Password",
+ type: "string",
+ value: "",
+ },
+ {
+ name: "Key size",
+ type: "option",
+ value: ["1024", "2048", "4096"],
+ },
+ {
+ name: "Name",
+ type: "string",
+ value: "",
+ },
+ {
+ name: "Email",
+ type: "string",
+ value: "",
+ },
+ ]
+ },
+ "Detach PGP Cleartext": {
+ module: "PGP",
+ description: [
+ "Input: the ASCII-armoured cleartext signature you want to verify.",
+ "
",
+ "This operation will detach the cleartext message from the signature.",
+ "It outputs 3 files as HTML: ",
+ "the cleartext message (msg), ",
+ "the ASCII-armoured signature (msg.asc), and ",
+ "the raw bytes of the signature (msg.sig).",
+ "
",
+ "Pretty Good Privacy is an encryption standard (OpenPGP) used for encrypting, decrypting, and signing messages.",
+ "
",
+ "This function relies on OpenPGP.js for the implementation of PGP.",
+ "
",
+ "See more at https://openpgpjs.org/",
+ ].join("\n"),
+ inputType: "string",
+ outputType: "HTML",
+ args: [
+ ],
+ },
+ "Add PGP ASCII Armour": {
+ module: "PGP",
+ description: [
+ "Input: the raw PGP bytes of the message or key that you want to add ASCII-armour to.",
+ "
",
+ "Arguments: the kind of the raw bytes: message / public key / private key.",
+ "
",
+ "This operation will output the ASCII-armoured input.",
+ "
",
+ "Pretty Good Privacy is an encryption standard (OpenPGP) used for encrypting, decrypting, and signing messages.",
+ "
",
+ "This function relies on OpenPGP.js for the implementation of PGP.",
+ "
",
+ "See more at https://openpgpjs.org/",
+ ].join("\n"),
+ inputType: "byteArray",
+ outputType: "string",
+ args: [
+ {
+ name: "Armour type",
+ type: "option",
+ value: PGP.ARMOUR_TYPES,
+ },
+ ],
+ },
+ "Remove PGP ASCII Armour": {
+ module: "PGP",
+ description: [
+ "Input: the ASCII-armoured PGP message or key that you want to remove the ASCII-armour from.",
+ "
",
+ "This operation will output the raw bytes of the PGP packets.",
+ "
",
+ "Pretty Good Privacy is an encryption standard (OpenPGP) used for encrypting, decrypting, and signing messages.",
+ "
",
+ "This function relies on OpenPGP.js for the implementation of PGP.",
+ "
",
+ "See more at https://openpgpjs.org/",
+ ].join("\n"),
+ inputType: "string",
+ outputType: "byteArray",
+ args: [
+ ],
+ },
};
diff --git a/src/core/config/modules/OpModules.js b/src/core/config/modules/OpModules.js
index 3f3963c3..74ccdbc5 100644
--- a/src/core/config/modules/OpModules.js
+++ b/src/core/config/modules/OpModules.js
@@ -17,6 +17,7 @@ import HashingModule from "./Hashing.js";
import HTTPModule from "./HTTP.js";
import ImageModule from "./Image.js";
import JSBNModule from "./JSBN.js";
+import PGPModule from "./PublicKey.js";
import PublicKeyModule from "./PublicKey.js";
import ShellcodeModule from "./Shellcode.js";
import URLModule from "./URL.js";
@@ -33,6 +34,7 @@ Object.assign(
HTTPModule,
ImageModule,
JSBNModule,
+ PGPModule,
PublicKeyModule,
ShellcodeModule,
URLModule
diff --git a/src/core/config/modules/PGP.js b/src/core/config/modules/PGP.js
new file mode 100644
index 00000000..a50d5eb1
--- /dev/null
+++ b/src/core/config/modules/PGP.js
@@ -0,0 +1,36 @@
+import PGP from "../../operations/PGP.js";
+
+/**
+ * PGP module.
+ *
+ * Libraries:
+ * - openpgp
+ * - crypto-js
+ *
+ * @author tlwr [toby@toby.codes]
+ * @copyright Crown Copyright 2017
+ * @license Apache-2.0
+ */
+let OpModules = typeof self === "undefined" ? {} : self.OpModules || {};
+
+OpModules.PGP = {
+ "PGP Encrypt": PGP.runEncrypt,
+ "PGP Decrypt": PGP.runDecrypt,
+
+ "PGP Sign": PGP.runSign,
+ "PGP Verify": PGP.runVerify,
+
+ "Sign PGP Detached": PGP.runSignDetached,
+ "Verify PGP Detached": PGP.runVerifyDetached,
+
+ "Sign PGP Cleartext": PGP.runSignCleartext,
+ "Verify PGP Cleartext": PGP.runVerifyCleartext,
+
+ "Generate PGP Key Pair": PGP.runGenKeyPair,
+ "Detach PGP Cleartext": PGP.runVerifyCleartext,
+
+ "Add PGP ASCII Armour": PGP.runAddArmour,
+ "Remove PGP ASCII Armour": PGP.runAddArmour,
+};
+
+export default OpModules;
diff --git a/src/core/operations/PGP.js b/src/core/operations/PGP.js
new file mode 100644
index 00000000..a7a73296
--- /dev/null
+++ b/src/core/operations/PGP.js
@@ -0,0 +1,596 @@
+import * as openpgp from "imports-loader?window=>self!openpgp";
+import Utils from "../Utils.js";
+
+/**
+ * PGP operations.
+ *
+ * @author tlwr [toby@toby.codes]
+ * @copyright Crown Copyright 2017
+ * @license Apache-2.0
+ *
+ * @namespace
+ */
+
+const PGP = {
+ /**
+ * @constant
+ * @default
+ */
+ ARMOUR_TYPES: [
+ "Message",
+ "Public key",
+ "Private key",
+ ],
+
+
+ /**
+ * @constant
+ * @default
+ */
+ ARMOUR_TYPE_MAPPING: {
+ "Message": 3,
+ "Public key": 4,
+ "Private key": 5,
+ },
+
+
+ /**
+ * Encrypts the input using PGP.
+ *
+ * @param {string} input - plaintext to encrypt
+ * @param {Object[]} args
+ * @returns {string}
+ */
+ runEncrypt: function (plaintext, args) {
+ let publicKey = args[0],
+ publicKeys;
+
+ try {
+ publicKeys = openpgp.key.readArmored(publicKey).keys;
+ } catch (err) {
+ throw "Cannot read public key: " + err;
+ }
+
+ let options = {
+ data: plaintext,
+ publicKeys: publicKeys,
+ };
+
+ return openpgp.encrypt(options)
+ .then(ciphertext => ciphertext.data)
+ .catch(function(err) {
+ throw "Could not encrypt text: " + err;
+ });
+ },
+
+
+ /**
+ * Decrypts the input using PGP.
+ *
+ * @param {string} input - ciphertext to decrypt
+ * @param {Object[]} args
+ * @returns {string}
+ */
+ runDecrypt: function (input, args) {
+ let privateKey = args[0],
+ password = args[1],
+ message;
+
+ try {
+ privateKey = openpgp.key.readArmored(privateKey).keys[0];
+ } catch (err) {
+ throw "Cannot read private key: " + err;
+ }
+
+ try {
+ message = openpgp.message.readArmored(input);
+ } catch (err) {
+ throw "Cannot read message: " + err;
+ }
+
+ let options = {
+ message: message,
+ privateKey: privateKey,
+ };
+
+ if (password) {
+ privateKey.decrypt(password);
+ }
+ if (privateKey.primaryKey.encrypted !== null) {
+ throw "Could not decrypt private key.";
+ }
+
+ return openpgp.decrypt(options)
+ .then(plaintext => plaintext.data)
+ .catch(function(err) {
+ throw "Could not decrypt message: " + err;
+ });
+ },
+
+
+ /**
+ * Signs the input using PGP.
+ *
+ * @param {string} input - data to be signed
+ * @param {Object[]} args
+ * @returns {string}
+ */
+ runSign: function (input, args) {
+ let publicKey = args[0],
+ privateKey = args[1],
+ password = args[2],
+ publicKeys,
+ privateKeys;
+
+ try {
+ publicKeys = openpgp.key.readArmored(publicKey).keys;
+ } catch (err) {
+ throw "Could not read public key: " + err;
+ }
+
+ try {
+ privateKeys = openpgp.key.readArmored(privateKey).keys;
+ } catch (err) {
+ throw "Could not read private key: " + err;
+ }
+
+ if (password) {
+ privateKeys[0].decrypt(password);
+ }
+ if (privateKeys[0].primaryKey.encrypted !== null) {
+ throw "Could not decrypt private key.";
+ }
+
+ let options = {
+ data: input,
+ publicKeys: publicKeys,
+ privateKeys: privateKeys,
+ };
+
+ return openpgp.encrypt(options)
+ .then(signedData => signedData.data)
+ .catch(function(err) {
+ throw "Could not sign input: " + err;
+ });
+ },
+
+
+ /**
+ * Verifies the signed input using PGP.
+ *
+ * @param {string} input - signed input to verify
+ * @param {Object[]} args
+ * @returns {string} - the original message, and a summary of the verification process
+ */
+ runVerify: function (input, args) {
+ let publicKey = args[0],
+ privateKey = args[1],
+ password = args[2],
+ publicKeys,
+ privateKeys,
+ message;
+
+ try {
+ publicKeys = openpgp.key.readArmored(publicKey).keys;
+ } catch (err) {
+ throw "Could not read public key: " + err;
+ }
+
+ try {
+ privateKeys = openpgp.key.readArmored(privateKey).keys;
+ } catch (err) {
+ throw "Could not read private key: " + err;
+ }
+
+ if (password) {
+ privateKeys[0].decrypt(password);
+ }
+ if (privateKeys[0].primaryKey.encrypted !== null) {
+ throw "Could not decrypt private key.";
+ }
+
+ try {
+ message = openpgp.message.readArmored(input);
+ } catch (err) {
+ throw "Could not read encrypted message: " + err;
+ }
+
+ let packetContainingAlgorithms = message.packets.filterByTag(
+ openpgp.enums.packet.publicKeyEncryptedSessionKey
+ )[0];
+
+ let verification = {
+ verified: false,
+ pkAlgorithm: packetContainingAlgorithms.publicKeyAlgorithm,
+ sessionAlgorithm: packetContainingAlgorithms.sessionKeyAlgorithm,
+ author: publicKeys[0].users[0].userId.userid,
+ recipient: privateKeys[0].users[0].userId.userid,
+ keyID: "",
+ message: "",
+ };
+
+ return openpgp.decrypt({
+ message: message,
+ publicKeys: publicKeys,
+ privateKey: privateKeys[0],
+ })
+ .then(decrypted => {
+ if (decrypted.signatures) {
+ // valid is either true or null, casting required.
+ verification.verified = !!decrypted.signatures[0].valid;
+ verification.keyID = decrypted.signatures[0].keyid.toHex();
+ }
+
+ return [
+ "Verified: " + verification.verified,
+ "Key ID: " + verification.keyID,
+ "Encrypted for: " + verification.recipient,
+ "Signed by: " + verification.author,
+ "Signed with: " +
+ verification.pkAlgorithm +
+ "/" +
+ verification.sessionAlgorithm,
+ "\n",
+ decrypted.data,
+ ].join("\n");
+
+ })
+ .catch(function(err) {
+ throw "Could not decrypt and verify message: " + err;
+ });
+ },
+
+
+ /**
+ * Signs the input using PGP and outputs the plaintext, the raw PGP signature, and the ASCII armoured signature files.
+ *
+ * @param {string} input - data to be signed
+ * @param {Object[]} args
+ * @returns {HTML} - HTML file display of message, armoured signature, and bytes signature
+ */
+ runSignDetached: function (input, args) {
+ let privateKey = args[0],
+ password = args[1],
+ privateKeys;
+
+ try {
+ privateKeys = openpgp.key.readArmored(privateKey).keys;
+ } catch (err) {
+ throw "Could not read private key: " + err;
+ }
+
+ if (password) {
+ privateKeys[0].decrypt(password);
+ }
+ if (privateKeys[0].primaryKey.encrypted !== null) {
+ throw "Could not decrypt private key.";
+ }
+
+ let bytes = openpgp.util.str2Uint8Array(input);
+ let message = openpgp.message.fromBinary(bytes);
+
+ let signedMessage = message.sign(privateKeys);
+ let signature = signedMessage.packets.filterByTag(openpgp.enums.packet.signature);
+ let rawSignatureBytes = signature.write();
+
+ let armouredMessage = openpgp.armor.encode(
+ openpgp.enums.armor.message,
+ rawSignatureBytes
+ );
+ armouredMessage = armouredMessage.replace(
+ "-----BEGIN PGP MESSAGE-----\r\n",
+ "-----BEGIN PGP SIGNATURE-----\r\n"
+ );
+ armouredMessage = armouredMessage.replace(
+ "-----END PGP MESSAGE-----\r\n",
+ "-----END PGP SIGNATURE-----\r\n"
+ );
+
+ let files = [{
+ fileName: "msg",
+ size: input.length,
+ contents: input,
+ bytes: bytes,
+ }, {
+ fileName: "msg.asc",
+ size: armouredMessage.length,
+ contents: armouredMessage,
+ bytes: openpgp.util.str2Uint8Array(armouredMessage),
+ }, {
+ fileName: "msg.sig",
+ size: rawSignatureBytes.length,
+ contents: openpgp.util.Uint8Array2str(rawSignatureBytes),
+ bytes: rawSignatureBytes,
+ }];
+
+ return Utils.displayFilesAsHTML(files);
+ },
+
+
+ /**
+ * Verifies the detached signature and input using PGP.
+ *
+ * @param {string} input - signed input to verify
+ * @param {Object[]} args
+ * @returns {string} - the original message, and a summary of the verification process
+ */
+ runVerifyDetached: function (input, args) {
+ let publicKey = args[0],
+ armouredSignature = args[1],
+ publicKeys,
+ message;
+
+ try {
+ publicKeys = openpgp.key.readArmored(publicKey).keys;
+ } catch (err) {
+ throw "Could not read public key: " + err;
+ }
+
+ try {
+ message = openpgp.message.readSignedContent(
+ input,
+ armouredSignature
+ );
+ } catch (err) {
+ throw "Could not read armoured signature or message: " + err;
+ }
+
+ let packetContainingSignature = message.packets.filterByTag(
+ openpgp.enums.packet.signature
+ )[0];
+
+ let verification = {
+ verified: false,
+ pkAlgorithm: publicKeys[0].primaryKey.algorithm,
+ author: publicKeys[0].users[0].userId.userid,
+ date: packetContainingSignature.created,
+ keyID: "",
+ message: "",
+ };
+
+ return Promise.resolve(message.verify(publicKeys))
+ .then(function(signatures) {
+ if (signatures && signatures.length) {
+ verification.verified = !!signatures[0].valid;
+ verification.keyID = signatures[0].keyid.toHex();
+ }
+
+ return [
+ "Verified: " + verification.verified,
+ "Key ID: " + verification.keyID,
+ "Signed on: " + verification.date,
+ "Signed by: " + verification.author,
+ "Signed with: " + verification.pkAlgorithm,
+ "\n",
+ input,
+ ].join("\n");
+
+ })
+ .catch(function(err) {
+ throw "Could not verify message: " + err;
+ });
+ },
+
+
+ /**
+ * Clearsigns the input using PGP.
+ *
+ * @param {string} input - data to be signed
+ * @param {Object[]} args
+ * @returns {string}
+ */
+ runSignCleartext: function (input, args) {
+ let privateKey = args[0],
+ password = args[1],
+ privateKeys;
+
+ try {
+ privateKeys = openpgp.key.readArmored(privateKey).keys;
+ } catch (err) {
+ throw "Could not read private key: " + err;
+ }
+
+ if (password) {
+ privateKeys[0].decrypt(password);
+ }
+ if (privateKeys[0].primaryKey.encrypted !== null) {
+ throw "Could not decrypt private key.";
+ }
+
+ let options = {
+ data: input,
+ privateKeys: privateKeys,
+ };
+
+ return openpgp.sign(options)
+ .then(signedData => signedData.data)
+ .catch(function(err) {
+ throw "Could not clearsign input: " + err;
+ });
+ },
+
+
+ /**
+ * Verifies the clearsigned input using PGP.
+ *
+ * @param {string} input - signed input to verify
+ * @param {Object[]} args
+ * @returns {string} - the original message, and a summary of the verification process
+ */
+ runVerifyCleartext: function (input, args) {
+ let publicKey = args[0],
+ publicKeys,
+ message;
+
+ try {
+ publicKeys = openpgp.key.readArmored(publicKey).keys;
+ } catch (err) {
+ throw "Could not read public key: " + err;
+ }
+
+ try {
+ message = openpgp.cleartext.readArmored(input);
+ } catch (err) {
+ throw "Could not read input message: " + err;
+ }
+
+ let packetContainingSignature = message.packets.filterByTag(
+ openpgp.enums.packet.signature
+ )[0];
+
+ let verification = {
+ verified: false,
+ pkAlgorithm: publicKeys[0].primaryKey.algorithm,
+ author: publicKeys[0].users[0].userId.userid,
+ date: packetContainingSignature.created,
+ keyID: "",
+ message: message.text,
+ };
+
+ return openpgp.verify({
+ message: message,
+ publicKeys: publicKeys,
+ })
+ .then(verifiedData => {
+ if (verifiedData.signatures) {
+ // valid is either true or null, casting required.
+ verification.verified = !!verifiedData.signatures[0].valid;
+ verification.keyID = verifiedData.signatures[0].keyid.toHex();
+ }
+
+ return [
+ "Verified: " + verification.verified,
+ "Key ID: " + verification.keyID,
+ "Signed on: " + verification.date,
+ "Signed by: " + verification.author,
+ "Signed with: " + verification.pkAlgorithm,
+ "\n",
+ verification.message,
+ ].join("\n");
+ })
+ .catch(function(err) {
+ throw "Could not verify message: " + err;
+ });
+ },
+
+
+ /**
+ * Generates a PGP key pair.
+ *
+ * @param {string} input is ignored
+ * @param {Object[]} args
+ * @returns {string} - armoured public key and private key separated by whitespace.
+ */
+ runGenKeyPair: function (input, args) {
+ let password = args[0],
+ keySize = parseInt(args[1], 10),
+ name = args[2],
+ email = args[3];
+
+ let options = {
+ numBits: keySize,
+ userIds: [{name: name, email: email}],
+ };
+
+ if (password) {
+ options.passphrase = password;
+ }
+
+ return openpgp.generateKey(options)
+ .then(key => {
+ return [
+ key.publicKeyArmored,
+ key.privateKeyArmored,
+ ].join(""); // Preceding and trailing newlines are already generated.
+ })
+ .catch(function(err) {
+ throw "Could not generate key pair: " + err;
+ });
+ },
+
+
+ /**
+ * Turns a PGP clearsigned message into a detached signature.
+ *
+ * @param {string} input
+ * @param {Object[]} args
+ * @returns {HTML} - HTML file display of message, armoured signature, and bytes signature
+ */
+ runDetachClearsig: function (input, args) {
+ let message;
+
+ try {
+ message = openpgp.cleartext.readArmored(input);
+ } catch (err) {
+ throw "Could not read input message: " + err;
+ }
+
+ let cleartext = message.getText();
+ let clearbytes = openpgp.util.str2Uint8Array(cleartext);
+
+ let signature = message.packets.filterByTag(openpgp.enums.packet.signature);
+ let rawSignatureBytes = signature.write();
+
+ let armouredMessage = openpgp.armor.encode(
+ openpgp.enums.armor.message,
+ rawSignatureBytes
+ );
+ armouredMessage = armouredMessage.replace(
+ "-----BEGIN PGP MESSAGE-----\r\n",
+ "-----BEGIN PGP SIGNATURE-----\r\n"
+ );
+ armouredMessage = armouredMessage.replace(
+ "-----END PGP MESSAGE-----\r\n",
+ "-----END PGP SIGNATURE-----\r\n"
+ );
+
+ let files = [{
+ fileName: "msg",
+ size: cleartext.length,
+ contents: cleartext,
+ bytes: clearbytes,
+ }, {
+ fileName: "msg.asc",
+ size: armouredMessage.length,
+ contents: armouredMessage,
+ bytes: openpgp.util.str2Uint8Array(armouredMessage),
+ }, {
+ fileName: "msg.sig",
+ size: rawSignatureBytes.length,
+ contents: openpgp.util.Uint8Array2str(rawSignatureBytes),
+ bytes: rawSignatureBytes,
+ }];
+
+ return Utils.displayFilesAsHTML(files);
+ },
+
+
+ /**
+ * Turns raw PGP bytes into an ASCII armoured string.
+ *
+ * @param {byteArray} input
+ * @param {Object[]} args
+ * @returns {string} - armoured public key and private key separated by whitespace.
+ */
+ runAddArmour: function (input, args) {
+ let armourType = PGP.ARMOUR_TYPE_MAPPING[args[0]];
+ return openpgp.armor.encode(armourType, input);
+ },
+
+
+ /**
+ * Turns an ASCII armoured string into raw PGP bytes.
+ *
+ * @param {string} input
+ * @param {Object[]} args
+ * @returns {byteArray}
+ */
+ runRemoveArmour: function (input, args) {
+ let decoded = openpgp.armor.decode(input);
+ let uint8bytes = decoded.data;
+ let bytes = Array.prototype.slice.call(uint8bytes);
+ return bytes;
+ },
+};
+
+export default PGP;
diff --git a/test/index.js b/test/index.js
index 773a5b14..327861c1 100644
--- a/test/index.js
+++ b/test/index.js
@@ -25,6 +25,7 @@ import "./tests/operations/Hash.js";
import "./tests/operations/Image.js";
import "./tests/operations/MorseCode.js";
import "./tests/operations/MS.js";
+import "./tests/operations/PGP.js";
import "./tests/operations/StrUtils.js";
import "./tests/operations/SeqUtils.js";
diff --git a/test/tests/operations/PGP.js b/test/tests/operations/PGP.js
new file mode 100644
index 00000000..265722e1
--- /dev/null
+++ b/test/tests/operations/PGP.js
@@ -0,0 +1,457 @@
+/**
+ * PGP tests.
+ *
+ * @author tlwr [toby@toby.codes]
+ *
+ * @copyright Crown Copyright 2017
+ * @license Apache-2.0
+ */
+import TestRegister from "../../TestRegister.js";
+
+const CYBERCHEF_GENERATED_KEY_PAIRS = [
+ {
+ name: "CyberChef 1",
+ size: 1024,
+ pub: [
+ "-----BEGIN PGP PUBLIC KEY BLOCK-----",
+ "Version: OpenPGP.js v2.3.6",
+ "Comment: http://openpgpjs.org",
+ "",
+ "xo0EWMQszAEEAMY6F0o6jL6TrVVXDkqJwNVJRR6tQKr+LIt7plEJoaTRVDfL",
+ "1jetdhPg+YiE7xZI8ygf6fhsrot4ccUN1QdtwedAz6GH0xjFzpL1i4/7/f3U",
+ "ItJ0p1MO4Amy8Tei/AtXXMTy/YwE77V1AMcv7OYFw9va5S0PD87XoKK6rx7z",
+ "GFMTABEBAAHNAjw+wrUEEAEIACkFAljELMwGCwkHCAMCCRAar/puuym6vQQV",
+ "CAIKAxYCAQIZAQIbAwIeAQAA8/QEAKDVde34L3rvFECzUOFPA5w4w4gbwkg+",
+ "YwPa084WvMTdo/wBEiEhj+7P+/5eN/U96yuHD48+Cmm5AHBaaf+K1b2LbNe7",
+ "3PP5rV1rMcooUGeIhq7SFw0BdPZTLoCNbkBKFCpvrS/F4SuUQF7g+fVyOyve",
+ "zVWew+E41ZC3vsDd63Y3zo0EWMQszAEEANYNy0yka1+c3Oe2U1GqoAHXv05p",
+ "VnlHAZ+28JGs8Thq5ns0K8bxI+Fn9CFpPO7Vofrr40V3vweoJVK2Eiq2gN/X",
+ "QdxPHckcpYbFKTAZIXt2MAZfb027JxWZid5lyYSCwvY+BK7x5X4jdY5KfbKu",
+ "7WDivOkq8MhomSiX+QYDV8qrABEBAAHCnwQYAQgAEwUCWMQszAkQGq/6brsp",
+ "ur0CGwwAAIjWA/9WhpbfM+oA08m5XwXgCkuRfTymIkexzn17dZOngTzaGcbK",
+ "vpS3QN164XNu229JNKTrsdgn5zeeq3AqhQ63hTMbePajvUYSssHPqKB8qQlp",
+ "OUY/rcFEUXMirIkKBGByYBmlz56Ai855wJoSOrZJA6yfnGepyV5ChcG/cEmB",
+ "dH/6bA==",
+ "=4nW6",
+ "-----END PGP PUBLIC KEY BLOCK-----",
+ ].join("\n"),
+ sec: [
+ "-----BEGIN PGP PRIVATE KEY BLOCK-----",
+ "Version: OpenPGP.js v2.3.6",
+ "Comment: http://openpgpjs.org",
+ "",
+ "xcEYBFjELMwBBADGOhdKOoy+k61VVw5KicDVSUUerUCq/iyLe6ZRCaGk0VQ3",
+ "y9Y3rXYT4PmIhO8WSPMoH+n4bK6LeHHFDdUHbcHnQM+hh9MYxc6S9YuP+/39",
+ "1CLSdKdTDuAJsvE3ovwLV1zE8v2MBO+1dQDHL+zmBcPb2uUtDw/O16Ciuq8e",
+ "8xhTEwARAQABAAP6A0jnJeW+e1H7J1Tf+cA6n84tBQsd7Td1CYKtCN69/Psz",
+ "CBGqpRWMxVuPBwIc7COdU+bje6hhZBJE4F0QUKUy91iQRssy4MzOYmZbdZaa",
+ "eTT81MdYb6QPYdTvPBVxjeLJBL7mKB+hM2Z8SvtJMDBdLlprf/XIdZKxD/NB",
+ "R+q66OECAPPsaMb+Yv1F30pEJZkATWvUSQS57HzWoBaNGxGkDqcik7+2q3DU",
+ "fWe0586HfMFQ3ba1ziNy2SWYJDAqMAe0QekCANAKgQJwww75GGK1RwNFZRoJ",
+ "Sb/Jzx3RVbwy1xqfVbadTuvf2+oSBLy/+eGXglwrok08e2BvYWMmhB+uJSJb",
+ "M5sCAItUBCJqTszPQPZdIOi7rGomnL2fijBDAUz+kWAWBPcIf8zzexKl7Ebq",
+ "dxc621BD5xjDjE7x1Z5XX/Rd2Lt+PvOdyM0CPD7CtQQQAQgAKQUCWMQszAYL",
+ "CQcIAwIJEBqv+m67Kbq9BBUIAgoDFgIBAhkBAhsDAh4BAADz9AQAoNV17fgv",
+ "eu8UQLNQ4U8DnDjDiBvCSD5jA9rTzha8xN2j/AESISGP7s/7/l439T3rK4cP",
+ "jz4KabkAcFpp/4rVvYts17vc8/mtXWsxyihQZ4iGrtIXDQF09lMugI1uQEoU",
+ "Km+tL8XhK5RAXuD59XI7K97NVZ7D4TjVkLe+wN3rdjfHwRgEWMQszAEEANYN",
+ "y0yka1+c3Oe2U1GqoAHXv05pVnlHAZ+28JGs8Thq5ns0K8bxI+Fn9CFpPO7V",
+ "ofrr40V3vweoJVK2Eiq2gN/XQdxPHckcpYbFKTAZIXt2MAZfb027JxWZid5l",
+ "yYSCwvY+BK7x5X4jdY5KfbKu7WDivOkq8MhomSiX+QYDV8qrABEBAAEAA/0e",
+ "rqd/eunxMJjxlc7nm9+HpBdF9A9zHtx6ukxNdU62WYxkCJxlzdbozm/OAjm7",
+ "ul+XigxvvrRhMpb2/iYofTSHnj+6yGGghCic6BtstJOU7qepMrX+IKh3TNEp",
+ "YNU8z0E1fSd9fMOx1hnTZwaTroii9CzM0i4YH3pSjze7Ir7cIQIA8Cg8sBmG",
+ "IDhe7SBq5xcG2V4iNqiK5gHXbQrcit9/XJFqIeda5Ec7lRjpa6vG5f1xeT1w",
+ "KdBil2L4prnD6XDAEwIA5Cy51YIjizFyKormqQNGR1fdAl+6T/qReUcw5Cmw",
+ "cDU7tUujZwZz/utmjOcadq8JR2LG6rNwLzeMgDNCCKAOCQH/RX0h3eLXcpWq",
+ "jGBH3mJbukSLH/98ybP5LV+4jg0q5iXOOjUIXxFsPElyZZHUBvpoRrKbRG/f",
+ "PzOpx7akqEOuDJ/Dwp8EGAEIABMFAljELMwJEBqv+m67Kbq9AhsMAACI1gP/",
+ "VoaW3zPqANPJuV8F4ApLkX08piJHsc59e3WTp4E82hnGyr6Ut0DdeuFzbttv",
+ "STSk67HYJ+c3nqtwKoUOt4UzG3j2o71GErLBz6igfKkJaTlGP63BRFFzIqyJ",
+ "CgRgcmAZpc+egIvOecCaEjq2SQOsn5xnqcleQoXBv3BJgXR/+mw=",
+ "=8R+g",
+ "-----END PGP PRIVATE KEY BLOCK-----",
+ ].join("\n"),
+ },
+];
+
+const PGP_TEST_KEY_PAIRS = [
+ {
+ keyID: "a9510d8fd7e352f5",
+ name: "CyberChef nopw 1024 ",
+ size: 1024,
+ pub: [
+ "-----BEGIN PGP PUBLIC KEY BLOCK-----",
+ "",
+ "mI0EWL7mbwEEANVcA5s+pXliwZBZXvfjy69JlPkX8dWRTZLuqZPz5XKGb9E1RKxQ",
+ "jELZ9bBIv/t0HDoiwh1XJok3SRMPzLPHK9lLXaa/l7716CkRddTvkd3cjFA3yAEL",
+ "X97+4nPVIajYUPDy6ovCrRru2bXyW2cjHKErlI0GJ37Hbbpj/GXSQL6HABEBAAG0",
+ "JUN5YmVyQ2hlZiBub3B3IDEwMjQgPHRvYnlAdG9ieS5jb2Rlcz6ItwQTAQgAIQUC",
+ "WL7mbwIbAwULCQgHAgYVCAkKCwIEFgIDAQIeAQIXgAAKCRCpUQ2P1+NS9ZhxA/49",
+ "sXqWYoi34HMtHfVejPpPSXrFxY+ZjgM1cMVe5m4cumBeZVVYaEH9/3xDlrhfrlMi",
+ "xCRGNqfIRwavIbNWyBshrjVnZ1PR/hvp2P3tV0ciV51lJi6ApO46fsmsWZw84cOA",
+ "ejQ1giBjuLuu4du52+MVbcko2yEJ2tOS2WMPnYO7RbiNBFi+5m8BBAClMs6KZuXd",
+ "2mhmz3vGcczlA0vv2k7lZjdT7LmbYLt/ir7Hdqg7z7l84wO1qPNQc6pRkLVd1rMX",
+ "8fh+RtLUVAuvATpRJCAdaeslcxaH7o0p5DbjrRmiDmnaLDl/S0xMhI137XaKdUS7",
+ "ZRuGFZVfqXeFerpbjrlUlhzAcHua8aAmHQARAQABiJ8EGAEIAAkFAli+5m8CGwwA",
+ "CgkQqVENj9fjUvUA6AP/b9jZvaQ7w6mdlCvCrFpfp3vBZN1E0vLIMdRKRMmNR8D7",
+ "pmZ4RcmMJxjVTLkB6Uc90+9Tbb2ysykQaTTw3YdpmyoGmy3qgH3opd/IdZzEAJyL",
+ "oBC+u8G7nATB58m4xmBYL1G5hn8nCBbNAiz1rrbXmWmVExQCVAXp7T50vPBdyFY=",
+ "=xCxV",
+ "-----END PGP PUBLIC KEY BLOCK-----",
+ ].join("\n"),
+ sec: [
+ "-----BEGIN PGP PRIVATE KEY BLOCK-----",
+ "",
+ "lQHYBFi+5m8BBADVXAObPqV5YsGQWV7348uvSZT5F/HVkU2S7qmT8+Vyhm/RNUSs",
+ "UIxC2fWwSL/7dBw6IsIdVyaJN0kTD8yzxyvZS12mv5e+9egpEXXU75Hd3IxQN8gB",
+ "C1/e/uJz1SGo2FDw8uqLwq0a7tm18ltnIxyhK5SNBid+x226Y/xl0kC+hwARAQAB",
+ "AAP7BLFYuDDhPrQDIgsdyzzsuIDPbj6G9z9+hsN/sLrZlEFbBt67c95+Sbzm6h1O",
+ "SdgcoZiPgJig0L3OyR1kO5ypBG4jhSgbaTKRHjP4KsOWoPuXmL1p8XLzZHOGp3hS",
+ "/recAxhqdbbO7uim+nbaPdmby9v0XrMAkFkBTU+D+ZlmC3ECAODTUZ7i+vRD6R3x",
+ "NzN2uhomWy94I7SkugTjcTw6BrzvdffFKtW7Yp6MbPdCpRIhuKy/QhG1LCUGwJKQ",
+ "vvNe5z8CAPLxrsx6jiFHpzAtUBYNBY5M3t805OYRFbs3mJ3LgsUP0wVOnODqo5TA",
+ "anevkFoakvcKJ8d0OlbO0/ewm4wd3rkB+wRQrllfYFfLqGzUlZDP15NKoHFk8T/w",
+ "LWg6nDm8pxXlhptaA8V4rVK1HrrPU56GBbzXftqL6iDpbYh9ZPR/U/qoXLQlQ3li",
+ "ZXJDaGVmIG5vcHcgMTAyNCA8dG9ieUB0b2J5LmNvZGVzPoi3BBMBCAAhBQJYvuZv",
+ "AhsDBQsJCAcCBhUICQoLAgQWAgMBAh4BAheAAAoJEKlRDY/X41L1mHED/j2xepZi",
+ "iLfgcy0d9V6M+k9JesXFj5mOAzVwxV7mbhy6YF5lVVhoQf3/fEOWuF+uUyLEJEY2",
+ "p8hHBq8hs1bIGyGuNWdnU9H+G+nY/e1XRyJXnWUmLoCk7jp+yaxZnDzhw4B6NDWC",
+ "IGO4u67h27nb4xVtySjbIQna05LZYw+dg7tFnQHYBFi+5m8BBAClMs6KZuXd2mhm",
+ "z3vGcczlA0vv2k7lZjdT7LmbYLt/ir7Hdqg7z7l84wO1qPNQc6pRkLVd1rMX8fh+",
+ "RtLUVAuvATpRJCAdaeslcxaH7o0p5DbjrRmiDmnaLDl/S0xMhI137XaKdUS7ZRuG",
+ "FZVfqXeFerpbjrlUlhzAcHua8aAmHQARAQABAAP8C0IAnaGbME4WMkzDyHIbPqTF",
+ "s9qX6NMumbthVLY4C4jhgnH9egH9x9sn9rpvm7/Iz2vXUvCdiNgLu/3zQoFYawsn",
+ "zpTQREm6CyITOLxyc5TrckodSlx6eoCezvnTzI/PvXrUSSqEP9c9hvcLuKm+aeZz",
+ "fclhPfDOL/EQx337aeECAMU0UXXb95hQqSdRMcsGkpoAlAIEM664/S9eBvXrJYWw",
+ "1Pfgms7Axi/tZ4ebkc3urRW/YKAt423Ixmdd5rOwIDECANZzoOU8LxreLcLQOoA9",
+ "SWswRWUeyQTvH4yskT2iIXen22CO1pp7ruy07vSxHE+yyR3t2ZHKPJU864J39d4k",
+ "da0CAJS838KMD8h+Zv1C/jhKkYjpnDRuE+Lj7qVNHCJqsFSzpJAbJ09VpwSGbUso",
+ "Ptc/oyXgzb91+sLKfsIwGa7ZysarEIifBBgBCAAJBQJYvuZvAhsMAAoJEKlRDY/X",
+ "41L1AOgD/2/Y2b2kO8OpnZQrwqxaX6d7wWTdRNLyyDHUSkTJjUfA+6ZmeEXJjCcY",
+ "1Uy5AelHPdPvU229srMpEGk08N2HaZsqBpst6oB96KXfyHWcxACci6AQvrvBu5wE",
+ "wefJuMZgWC9RuYZ/JwgWzQIs9a6215lplRMUAlQF6e0+dLzwXchW",
+ "=S56e",
+ "-----END PGP PRIVATE KEY BLOCK-----",
+ ].join("\n"),
+ },
+ {
+ keyID: "02da58ca894c4cc7",
+ name: "CyberChef pw 1024 ",
+ size: 1024,
+ password: "2NSRJYTzgsTVJfih",
+ pub: [
+ "-----BEGIN PGP PUBLIC KEY BLOCK-----",
+ "",
+ "mI0EWL7mswEEAMcw0PSzmNfh4MkGwejsyreXb34FqEjYMc1GmswvC5uuLp0KzbC6",
+ "HecV1GyyPQ7kKshWVLloShN3KtgSZF7DJ8/Hioiv4Q5HJYPY4AYwqECi+/C4W1FA",
+ "tJEbItdEIxw0IgHOX64X5kMptVV9J5bGc7DqkqUHgapXJI+yLZel0s83ABEBAAG0",
+ "I0N5YmVyQ2hlZiBwdyAxMDI0IDx0b2J5QHRvYnkuY29kZXM+iLcEEwEIACEFAli+",
+ "5rMCGwMFCwkIBwIGFQgJCgsCBBYCAwECHgECF4AACgkQAtpYyolMTMeOGwP+NvLU",
+ "GHhHaIFwI+VMB655CiD6QuRWnurcrXq7qZYl3flyBehhZdtgGBx9vynffElEFEFz",
+ "cbqzv8unkDTRdPqTA0gM2wOaC/L6Kuy4ErjQD7A4i5rC/IG0ja+3DQeKLShGGtaD",
+ "bG0H0mJl7gzlqR3/fxgLxi/JaCtqapjtZDF/GTC4jQRYvuazAQQA5oNC4NeWKBKU",
+ "m9H/QZyxKRWGaaQRKLrmSGVkQgJlzo3pnNjJMFUaMcQaJve+PZGay7y9sCOFpumf",
+ "6v1ERY+qw4ZOyCRnRqHJOxdLrbTPSmOwIUYkYFkNzARGpdy/FqWCByXDXea5qsb1",
+ "DJRT9WUte3Bbx1YvzsqrZMqsExgwgdcAEQEAAYifBBgBCAAJBQJYvuazAhsMAAoJ",
+ "EALaWMqJTEzH7woEAKIKQS8bEf8iHaVf7aGEWWOShN10gb+xpWD4V5r8H6hlNpIk",
+ "xwQEbj8glTJBEJoD5xO1tdrHmOJ7BVO1d7otdgXpjBAOxn0ngW4MAB8BO+Qa5U/t",
+ "M+6yuL8REwE5YUnvIyhgvhiHsBhlLeMNXtwCrF94WyDzyb+hwVwwi/PFtI0y",
+ "=djdC",
+ "-----END PGP PUBLIC KEY BLOCK-----",
+ ].join("\n"),
+ sec: [
+ "-----BEGIN PGP PRIVATE KEY BLOCK-----",
+ "",
+ "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",
+ "=j2j0",
+ "-----END PGP PRIVATE KEY BLOCK-----",
+ ].join("\n"),
+ },
+];
+
+PGP_TEST_KEY_PAIRS.forEach(function(keyPair) {
+ if (keyPair.password) {
+ TestRegister.addTests(
+ ["", "nottherightpassword"].map(function(incorrectPW) {
+ let testName = "PGP Encrypt, PGP Decrypt: ensure error for incorrect password (pw [$pw], $ks, $name)";
+ testName = testName.replace("$ks", keyPair.size);
+ testName = testName.replace("$pw", incorrectPW);
+
+ return {
+ name: testName,
+ input: "hello world",
+ expectedError: true,
+ recipeConfig: [
+ {
+ op: "PGP Encrypt",
+ args: [keyPair.pub],
+ },
+ {
+ op: "PGP Decrypt",
+ args: [keyPair.sec, incorrectPW],
+ },
+ ],
+ };
+ })
+ );
+ }
+});
+
+["", "hello world"].forEach(function(input) {
+ TestRegister.addTests(
+ PGP_TEST_KEY_PAIRS.map(function(keyPair) {
+ let testName = "PGP Encrypt, PGP Decrypt ($pw, $ks) '$input'";
+ testName = testName.replace("$ks", keyPair.size);
+ testName = testName.replace("$pw", keyPair.password ? "pw" : "no pw");
+ testName = testName.replace("$input", input);
+
+ return {
+ name: testName,
+ input: input,
+ expectedOutput: input,
+ recipeConfig: [
+ {
+ op: "PGP Encrypt",
+ args: [keyPair.pub],
+ },
+ {
+ op: "PGP Decrypt",
+ args: [keyPair.sec, keyPair.password],
+ },
+ ],
+ };
+ })
+ );
+});
+
+TestRegister.addTests([{
+ name: "PGP Encrypt, PGP Decrypt: fails when incorrect password, empty string (1024)",
+ input: "",
+ expectedError: true,
+ recipeConfig: [
+ {
+ op: "PGP Encrypt",
+ args: [PGP_TEST_KEY_PAIRS[1].pub],
+ },
+ {
+ op: "PGP Decrypt",
+ args: [PGP_TEST_KEY_PAIRS[1].sec, "gibberish"],
+ },
+ ],
+}]);
+
+TestRegister.addTests([{
+ name: "PGP Encrypt, PGP Decrypt: fails when incorrect password, hello world (1024)",
+ input: "hello world",
+ expectedError: true,
+ recipeConfig: [
+ {
+ op: "PGP Encrypt",
+ args: [PGP_TEST_KEY_PAIRS[1].pub],
+ },
+ {
+ op: "PGP Decrypt",
+ args: [PGP_TEST_KEY_PAIRS[1].sec, "gibberish"],
+ },
+ ],
+}]);
+
+["hello world"].forEach(function(input) {
+ [
+ [PGP_TEST_KEY_PAIRS[0], PGP_TEST_KEY_PAIRS[1]],
+ [PGP_TEST_KEY_PAIRS[1], PGP_TEST_KEY_PAIRS[0]],
+ ].forEach(function(pairOfKeyPairs) {
+ let alice = pairOfKeyPairs[0],
+ bob = pairOfKeyPairs[1];
+
+ let testName = "PGP Sign ($alice), PGP Verify ($bob) '$input'";
+ testName = testName.replace("$alice", alice.name);
+ testName = testName.replace("$bob", bob.name);
+ testName = testName.replace("$input", input);
+
+ TestRegister.addTests([{
+ name: testName,
+ input: input,
+ expectedOutput: [
+ "Verified: true",
+ "Key ID: " + alice.keyID,
+ "Encrypted for: " + bob.name,
+ "Signed by: " + alice.name,
+ "Signed with: rsa_encrypt_sign/aes256",
+ "\n",
+ input,
+ ].join("\n"),
+ recipeConfig: [
+ {
+ op: "PGP Sign",
+ args: [bob.pub, alice.sec, alice.password],
+ },
+ {
+ op: "PGP Verify",
+ args: [alice.pub, bob.sec, bob.password],
+ },
+ ],
+ }]);
+ });
+});
+
+["", "hello world"].forEach(function(input) {
+ TestRegister.addTests(
+ PGP_TEST_KEY_PAIRS.map(function(keyPair) {
+ let testName = "Sign PGP Cleartext, Verify PGP Cleartext ($pw, $ks) '$input'";
+ testName = testName.replace("$ks", keyPair.size);
+ testName = testName.replace("$pw", keyPair.password ? "pw" : "no pw");
+ testName = testName.replace("$input", input);
+
+ return {
+ name: testName,
+ input: input,
+ expectedOutput: [
+ "Verified: true",
+ "Key ID: " + keyPair.keyID,
+ "Signed by: " + keyPair.name,
+ "Signed with: rsa_encrypt_sign",
+ "\n",
+ input,
+ ].join("\n"),
+ recipeConfig: [
+ {
+ op: "Sign PGP Cleartext",
+ args: [keyPair.sec, keyPair.password],
+ },
+ {
+ op: "Verify PGP Cleartext",
+ args: [keyPair.pub],
+ },
+ {
+ op: "Find / Replace",
+ args: [
+ {option: "Regex", string: "Signed on: .*\r?\n"},
+ "",
+ true,
+ false,
+ false,
+ ],
+ },
+ ],
+ };
+ })
+ );
+});
+
+TestRegister.addTests(CYBERCHEF_GENERATED_KEY_PAIRS.map(function(keyPair) {
+ let testName = "Remove PGP ASCII Armour, Add PGP ASCII Armour: Public Key '$name'";
+ testName = testName.replace("$name", keyPair.name);
+
+ return {
+ name: testName,
+ input: keyPair.pub,
+ expectedOutput: keyPair.pub,
+ ignoreWhitespace: true,
+ recipeConfig: [
+ {
+ op: "Remove PGP ASCII Armour",
+ args: [],
+ },
+ {
+ op: "Add PGP ASCII Armour",
+ args: ["Public key"],
+ },
+ ],
+ };
+}));
+
+TestRegister.addTests(CYBERCHEF_GENERATED_KEY_PAIRS.map(function(keyPair) {
+ let testName = "Remove PGP ASCII Armour, Add PGP ASCII Armour: Private Key '$name'";
+ testName = testName.replace("$name", keyPair.name);
+
+ return {
+ name: testName,
+ input: keyPair.sec,
+ expectedOutput: keyPair.sec,
+ ignoreWhitespace: true,
+ recipeConfig: [
+ {
+ op: "Remove PGP ASCII Armour",
+ args: [],
+ },
+ {
+ op: "Add PGP ASCII Armour",
+ args: ["Private key"],
+ },
+ ],
+ };
+}));
+
+PGP_TEST_KEY_PAIRS.forEach(function(keyPair) {
+ TestRegister.addTests(
+ ["", "hello world"].map(function(message, messageIndex) {
+ let testName = "PGP Encrypt, Remove PGP ASCII Armour, Add PGP ASCII Armour, PGP Decrypt: Message $message '$name'";
+ testName = testName.replace("$message", messageIndex);
+ testName = testName.replace("$name", keyPair.name);
+
+ return {
+ name: testName,
+ input: message,
+ expectedOutput: message,
+ ignoreWhitespace: true,
+ recipeConfig: [
+ {
+ op: "PGP Encrypt",
+ args: [keyPair.pub],
+ },
+ {
+ op: "Remove PGP ASCII Armour",
+ args: [],
+ },
+ {
+ op: "To Hex",
+ args: ["None"],
+ },
+ {
+ op: "From Hex",
+ args: ["None"],
+ },
+ {
+ op: "Add PGP ASCII Armour",
+ args: ["Message"],
+ },
+ {
+ op: "PGP Decrypt",
+ args: [keyPair.sec, keyPair.password],
+ },
+ ],
+ };
+ })
+ );
+});
diff --git a/webpack.config.js b/webpack.config.js
index 204635b1..2a040407 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -58,7 +58,10 @@ module.exports = {
},
{
test: /MetaConfig\.js$/,
- loader: "val-loader"
+ use: [
+ { loader: "val-loader" },
+ { loader: "imports-loader?self=>this" }
+ ]
},
{
test: /\.css$/,