123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364 |
- import * as kbpgp from "kbpgp";
- import {promisify} from "es6-promisify";
- /**
- * PGP operations.
- *
- * @author tlwr [toby@toby.codes]
- * @author Matt C [matt@artemisbot.uk]
- * @author n1474335 [n1474335@gmail.com]
- * @copyright Crown Copyright 2017
- * @license Apache-2.0
- *
- * @namespace
- */
- const PGP = {
- /**
- * @constant
- * @default
- */
- KEY_TYPES: ["RSA-1024", "RSA-2048", "RSA-4096", "ECC-256", "ECC-384"],
- /**
- * Get size of subkey
- *
- * @private
- * @param {number} keySize
- * @returns {number}
- */
- _getSubkeySize(keySize) {
- return {
- 1024: 1024,
- 2048: 1024,
- 4096: 2048,
- 256: 256,
- 384: 256,
- }[keySize];
- },
- /**
- * Progress callback
- *
- * @private
- */
- _ASP: new 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);
- }
- }),
- /**
- * Import private key and unlock if necessary
- *
- * @private
- * @param {string} privateKey
- * @param {string} [passphrase]
- * @returns {Object}
- */
- async _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
- *
- * @private
- * @param {string} publicKey
- * @returns {Object}
- */
- async _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}`;
- }
- },
- /**
- * Generate PGP Key Pair operation.
- *
- * @param {string} input
- * @param {Object[]} args
- * @returns {string}
- */
- runGenerateKeyPair(input, args) {
- let [keyType, keySize] = args[0].split("-"),
- password = args[1],
- name = args[2],
- email = args[3],
- 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;
- let keyGenerationOptions = {
- userid: userIdentifier,
- ecc: keyType === "ecc",
- primary: {
- "nbits": keySize,
- "flags": flags,
- "expire_in": 0
- },
- subkeys: [{
- "nbits": PGP._getSubkeySize(keySize),
- "flags": kbpgp.const.openpgp.sign_data,
- "expire_in": 86400 * 365 * 8
- }, {
- "nbits": PGP._getSubkeySize(keySize),
- "flags": kbpgp.const.openpgp.encrypt_comm | kbpgp.const.openpgp.encrypt_storage,
- "expire_in": 86400 * 365 * 2
- }],
- asp: PGP._ASP
- };
- return new Promise(async (resolve, reject) => {
- try {
- const unsignedKey = await promisify(kbpgp.KeyManager.generate)(keyGenerationOptions);
- await promisify(unsignedKey.sign.bind(unsignedKey))({});
- let signedKey = unsignedKey;
- let 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}`);
- }
- });
- },
- /**
- * PGP Encrypt operation.
- *
- * @param {string} input
- * @param {Object[]} args
- * @returns {string}
- */
- async runEncrypt(input, args) {
- let plaintextMessage = input,
- plainPubKey = args[0],
- 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": PGP._ASP
- });
- } catch (err) {
- throw `Couldn't encrypt message with provided public key: ${err}`;
- }
- return encryptedMessage.toString();
- },
- /**
- * PGP Decrypt operation.
- *
- * @param {string} input
- * @param {Object[]} args
- * @returns {string}
- */
- async runDecrypt(input, args) {
- let encryptedMessage = input,
- privateKey = args[0],
- passphrase = args[1],
- keyring = new kbpgp.keyring.KeyRing(),
- plaintextMessage;
- if (!privateKey) return "Enter the private key of the recipient.";
- const key = await PGP._importPrivateKey(privateKey, passphrase);
- keyring.add_key_manager(key);
- try {
- plaintextMessage = await promisify(kbpgp.unbox)({
- armored: encryptedMessage,
- keyfetch: keyring,
- asp: PGP._ASP
- });
- } catch (err) {
- throw `Couldn't decrypt message with provided private key: ${err}`;
- }
- return plaintextMessage.toString();
- },
- /**
- * PGP Sign Message operation.
- *
- * @param {string} input
- * @param {Object[]} args
- * @returns {string}
- */
- async runSign(input, args) {
- let message = input,
- privateKey = args[0],
- passphrase = args[1],
- publicKey = args[2],
- signedMessage;
- if (!privateKey) return "Enter the private key of the signer.";
- if (!publicKey) return "Enter the public key of the recipient.";
- const privKey = await PGP._importPrivateKey(privateKey, passphrase);
- const pubKey = await PGP._importPublicKey(publicKey);
- try {
- signedMessage = await promisify(kbpgp.box)({
- "msg": message,
- "encrypt_for": pubKey,
- "sign_with": privKey,
- "asp": PGP._ASP
- });
- } catch (err) {
- throw `Couldn't sign message: ${err}`;
- }
- return signedMessage;
- },
- /**
- * PGP Verify Message operation.
- *
- * @param {string} input
- * @param {Object[]} args
- * @returns {string}
- */
- async runVerify(input, args) {
- let signedMessage = input,
- publicKey = args[0],
- privateKey = args[1],
- passphrase = args[2],
- keyring = new kbpgp.keyring.KeyRing(),
- unboxedLiterals;
- if (!publicKey) return "Enter the public key of the signer.";
- if (!privateKey) return "Enter the private key of the recipient.";
- const privKey = await PGP._importPrivateKey(privateKey, passphrase);
- const pubKey = await PGP._importPublicKey(publicKey);
- keyring.add_key_manager(privKey);
- keyring.add_key_manager(pubKey);
- try {
- unboxedLiterals = await promisify(kbpgp.unbox)({
- armored: signedMessage,
- keyfetch: keyring,
- asp: PGP._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 PGP;
|