CyberChef/src/core/operations/PGP.js

204 lines
6.1 KiB
JavaScript
Raw Normal View History

/*eslint camelcase: ["error", {properties: "never"}]*/
import * as kbpgp from "kbpgp";
2017-12-21 14:23:31 +00:00
import promisify from "es6-promisify";
const ECC_SIZES = ["256", "384"];
const RSA_SIZES = ["1024", "2048", "4096"];
const KEY_SIZES = RSA_SIZES.concat(ECC_SIZES);
const KEY_TYPES = ["RSA", "ECC"];
/**
* PGP operations.
*
* @author tlwr [toby@toby.codes]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*
* @namespace
*/
const PGP = {
KEY_SIZES: KEY_SIZES,
/**
* Validate PGP Key Size
* @param {string} keySize
* @returns {Integer}
*/
validateKeySize(keySize, keyType) {
2017-11-26 20:13:49 +00:00
if (KEY_SIZES.indexOf(keySize) < 0) {
throw `Invalid key size ${keySize}, must be in ${JSON.stringify(KEY_SIZES)}`;
}
if (keyType === "ecc") {
if (ECC_SIZES.indexOf(keySize) >= 0) {
return parseInt(keySize, 10);
} else {
throw `Invalid key size ${keySize}, must be in ${JSON.stringify(ECC_SIZES)} for ECC`;
}
} else {
if (RSA_SIZES.indexOf(keySize) >= 0) {
return parseInt(keySize, 10);
} else {
throw `Invalid key size ${keySize}, must be in ${JSON.stringify(RSA_SIZES)} for RSA`;
}
}
},
/**
* Get size of subkey
* @param {Integer} keySize
* @returns {Integer}
*/
getSubkeySize(keySize) {
2017-11-26 20:13:49 +00:00
return {
1024: 1024,
2048: 1024,
4096: 2048,
256: 256,
384: 256,
}[keySize];
},
KEY_TYPES: KEY_TYPES,
/**
* Validate PGP Key Type
* @param {string} keyType
* @returns {string}
*/
validateKeyType(keyType) {
if (KEY_TYPES.indexOf(keyType) >= 0) return keyType.toLowerCase();
2017-11-26 20:13:49 +00:00
throw `Invalid key type ${keyType}, must be in ${JSON.stringify(KEY_TYPES)}`;
},
/**
* Generate PGP Key Pair operation.
*
* @author tlwr [toby@toby.codes]
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
runGenerateKeyPair(input, args) {
2017-11-26 20:13:49 +00:00
let keyType = args[0],
keySize = args[1],
password = args[2],
name = args[3],
email = args[4];
keyType = PGP.validateKeyType(keyType);
keySize = PGP.validateKeySize(keySize, keyType);
let userIdentifier = "";
if (name) userIdentifier += name;
if (email) userIdentifier += ` <${email}>`;
let flags = kbpgp.const.openpgp.certify_keys;
flags = flags | kbpgp.const.openpgp.sign_data;
flags = flags | kbpgp.const.openpgp.auth;
flags = flags | kbpgp.const.openpgp.encrypt_comm;
flags = flags | kbpgp.const.openpgp.encrypt_storage;
let keyGenerationOptions = {
userid: userIdentifier,
ecc: keyType === "ecc",
primary: {
nbits: keySize,
flags: flags,
expire_in: 0
2017-11-26 20:13:49 +00:00
},
subkeys: [{
nbits: PGP.getSubkeySize(keySize),
flags: kbpgp.const.openpgp.sign_data,
expire_in: 86400 * 365 * 8
2017-11-26 20:13:49 +00:00
}, {
nbits: PGP.getSubkeySize(keySize),
flags: kbpgp.const.openpgp.encrypt_comm | kbpgp.const.openpgp.encrypt_storage,
expire_in: 86400 * 365 * 2
2017-11-26 20:13:49 +00:00
}],
};
2017-12-21 14:23:31 +00:00
return new Promise(async (resolve, reject) => {
try {
const unsignedKey = await promisify(kbpgp.KeyManager.generate)(keyGenerationOptions);
await promisify(unsignedKey.sign, unsignedKey)({});
let signedKey = unsignedKey;
let privateKeyExportOptions = {};
if (password) privateKeyExportOptions.passphrase = password;
const privateKey = await promisify(signedKey.export_pgp_private, signedKey)(privateKeyExportOptions);
const publicKey = await promisify(signedKey.export_pgp_public, signedKey)({});
resolve(privateKey + "\n" + publicKey);
} catch (err) {
reject(`Error from kbpgp whilst generating key pair: ${err}`);
}
2017-11-26 20:13:49 +00:00
});
},
async runEncrypt(input, args) {
let plaintextMessage = input,
plainPubKey = args[0];
let key, encryptedMessage;
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,
});
} catch (err) {
2018-01-12 11:45:16 +00:00
throw `Couldn't encrypt message with provided public key: ${err}`;
}
2018-01-12 11:45:16 +00:00
return encryptedMessage.toString();
},
async runDecrypt(input, args) {
let encryptedMessage = input,
privateKey = args[0],
passphrase = args[1],
keyring = new kbpgp.keyring.KeyRing();
let key, plaintextMessage;
try {
key = await promisify(kbpgp.KeyManager.import_from_armored_pgp)({
armored: privateKey,
});
if (key.is_pgp_locked() && passphrase) {
if (passphrase) {
await promisify(key.unlock_pgp, key)({
passphrase
});
} else if (!passphrase) {
throw "Did not provide passphrase with locked private key.";
}
}
} catch (err) {
throw `Could not import private key: ${err}`;
}
keyring.add_key_manager(key);
try {
plaintextMessage = await promisify(kbpgp.unbox)({
armored: encryptedMessage,
keyfetch: keyring,
});
} catch (err) {
2018-01-12 11:45:16 +00:00
throw `Couldn't decrypt message with provided private key: ${err}`;
}
2018-01-12 11:45:16 +00:00
return plaintextMessage.toString();
},
};
export default PGP;