diff --git a/Gruntfile.js b/Gruntfile.js index 0a7505b5..6e61f5de 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -107,9 +107,12 @@ module.exports = function(grunt) { transform: [ ["babelify", { global: true, + // Only babelify chai-as-promised in node_modules + only: /^(?:.*\/node_modules\/chai-as-promised\/|(?!.*\/node_modules\/)).*$/, plugins: ["transform-async-to-generator", "syntax-async-functions", "transform-regenerator", + "transform-runtime", "transform-remove-strict-mode"], ignore: ['*.min.js'], presets: ["env"] diff --git a/src/crypto/pkcs1.js b/src/crypto/pkcs1.js index 71719651..c0cc29cf 100644 --- a/src/crypto/pkcs1.js +++ b/src/crypto/pkcs1.js @@ -50,13 +50,15 @@ hash_headers[11] = [0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, * @param {Integer} length Length of the padding in bytes * @return {String} Padding as string */ -function getPkcs1Padding(length) { +async function getPkcs1Padding(length) { let result = ''; - let randomByte; while (result.length < length) { - randomByte = random.getRandomBytes(1)[0]; - if (randomByte !== 0) { - result += String.fromCharCode(randomByte); + // eslint-disable-next-line no-await-in-loop + const randomBytes = await random.getRandomBytes(length - result.length); + for (let i = 0; i < randomBytes.length; i++) { + if (randomBytes[i] !== 0) { + result += String.fromCharCode(randomBytes[i]); + } } } return result; @@ -69,9 +71,9 @@ export default { * create a EME-PKCS1-v1_5 padding (See {@link https://tools.ietf.org/html/rfc4880#section-13.1.1|RFC 4880 13.1.1}) * @param {String} M message to be encoded * @param {Integer} k the length in octets of the key modulus - * @return {String} EME-PKCS1 padded message + * @return {Promise} EME-PKCS1 padded message */ - encode: function(M, k) { + encode: async function(M, k) { const mLen = M.length; // length checking if (mLen > k - 11) { @@ -79,15 +81,14 @@ export default { } // Generate an octet string PS of length k - mLen - 3 consisting of // pseudo-randomly generated nonzero octets - const PS = getPkcs1Padding(k - mLen - 3); + const PS = await getPkcs1Padding(k - mLen - 3); // Concatenate PS, the message M, and other padding to form an // encoded message EM of length k octets as EM = 0x00 || 0x02 || PS || 0x00 || M. - const EM = String.fromCharCode(0) + - String.fromCharCode(2) + - PS + - String.fromCharCode(0) + - M; - return EM; + return String.fromCharCode(0) + + String.fromCharCode(2) + + PS + + String.fromCharCode(0) + + M; }, /** * decodes a EME-PKCS1-v1_5 padding (See {@link https://tools.ietf.org/html/rfc4880#section-13.1.2|RFC 4880 13.1.2}) diff --git a/src/crypto/public_key/dsa.js b/src/crypto/public_key/dsa.js index ee1c5e16..f30fc9d8 100644 --- a/src/crypto/public_key/dsa.js +++ b/src/crypto/public_key/dsa.js @@ -48,7 +48,7 @@ export default { * g, p, q, x are all BN * returns { r: BN, s: BN } */ - sign: function(hash_algo, m, g, p, q, x) { + sign: async function(hash_algo, m, g, p, q, x) { let k; let r; let s; @@ -73,7 +73,8 @@ export default { // or s = 0 if signatures are generated properly. while (true) { // See Appendix B here: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf - k = random.getRandomBN(one, q); // returns in [1, q-1] + // eslint-disable-next-line no-await-in-loop + k = await random.getRandomBN(one, q); // returns in [1, q-1] r = gred.redPow(k).fromRed().toRed(redq); // (g**k mod p) mod q if (zero.cmp(r) === 0) { continue; @@ -96,7 +97,7 @@ export default { * p, q, g, y are all BN * returns BN */ - verify: function(hash_algo, r, s, m, p, q, g, y) { + verify: async function(hash_algo, r, s, m, p, q, g, y) { if (zero.ucmp(r) >= 0 || r.ucmp(q) >= 0 || zero.ucmp(s) >= 0 || s.ucmp(q) >= 0) { util.print_debug("invalid DSA Signature"); diff --git a/src/crypto/public_key/elgamal.js b/src/crypto/public_key/elgamal.js index b48402e6..678b0561 100644 --- a/src/crypto/public_key/elgamal.js +++ b/src/crypto/public_key/elgamal.js @@ -33,13 +33,13 @@ export default { * m, p, g, y are all BN * returns { c1: BN, c2: BN } */ - encrypt: function(m, p, g, y) { + encrypt: async function(m, p, g, y) { const redp = new BN.red(p); const mred = m.toRed(redp); const gred = g.toRed(redp); const yred = y.toRed(redp); // See Section 11.5 here: https://crypto.stanford.edu/~dabo/cryptobook/BonehShoup_0_4.pdf - const k = random.getRandomBN(zero, p); // returns in [0, p-1] + const k = await random.getRandomBN(zero, p); // returns in [0, p-1] return { c1: gred.redPow(k).fromRed(), c2: yred.redPow(k).redMul(mred).fromRed() @@ -50,7 +50,7 @@ export default { * c1, c2, p, x are all BN * returns BN */ - decrypt: function(c1, c2, p, x) { + decrypt: async function(c1, c2, p, x) { const redp = new BN.red(p); const c1red = c1.toRed(redp); const c2red = c2.toRed(redp); diff --git a/src/crypto/public_key/elliptic/curves.js b/src/crypto/public_key/elliptic/curves.js index cd1dd8ed..3508002c 100644 --- a/src/crypto/public_key/elliptic/curves.js +++ b/src/crypto/public_key/elliptic/curves.js @@ -178,7 +178,7 @@ Curve.prototype.genKeyPair = async function () { if (!keyPair || !keyPair.priv) { // elliptic fallback const r = await this.curve.genKeyPair({ - entropy: util.Uint8Array_to_str(random.getRandomBytes(32)) + entropy: util.Uint8Array_to_str(await random.getRandomBytes(32)) }); const compact = this.curve.curve.type === 'edwards' || this.curve.curve.type === 'mont'; if (this.keyType === enums.publicKey.eddsa) { diff --git a/src/crypto/public_key/prime.js b/src/crypto/public_key/prime.js index 53339f1a..95f232c9 100644 --- a/src/crypto/public_key/prime.js +++ b/src/crypto/public_key/prime.js @@ -37,15 +37,16 @@ export default { * @param {Integer} k Optional number of iterations of Miller-Rabin test * @return BN */ -function randomProbablePrime(bits, e, k) { +async function randomProbablePrime(bits, e, k) { const min = new BN(1).shln(bits - 1); - let n = random.getRandomBN(min, min.shln(1)); + let n = await random.getRandomBN(min, min.shln(1)); if (n.isEven()) { n.iaddn(1); // force odd } - while (!isProbablePrime(n, e, k)) { + // eslint-disable-next-line no-await-in-loop + while (!await isProbablePrime(n, e, k)) { n.iaddn(2); // If reached the maximum, go back to the minimum. if (n.bitLength() > bits) { @@ -62,17 +63,17 @@ function randomProbablePrime(bits, e, k) { * @param {Integer} k Optional number of iterations of Miller-Rabin test * @return {boolean} */ -function isProbablePrime(n, e, k) { +async function isProbablePrime(n, e, k) { if (e && !n.subn(1).gcd(e).eqn(1)) { return false; } if (!fermat(n)) { return false; } - if (!millerRabin(n, k, () => new BN(lowprimes[Math.random() * lowprimes.length | 0]))) { + if (!await millerRabin(n, k, () => new BN(lowprimes[Math.random() * lowprimes.length | 0]))) { return false; } - if (!millerRabin(n, k)) { + if (!await millerRabin(n, k)) { return false; } // TODO implement the Lucas test @@ -138,7 +139,7 @@ const lowprimes = [ * @param {Function} rand Optional function to generate potential witnesses * @return {boolean} */ -function millerRabin(n, k, rand) { +async function millerRabin(n, k, rand) { const len = n.bitLength(); const red = BN.mont(n); const rone = new BN(1).toRed(red); @@ -155,7 +156,8 @@ function millerRabin(n, k, rand) { const d = n.shrn(s); for (; k > 0; k--) { - let a = rand ? rand() : random.getRandomBN(new BN(2), n1); + // eslint-disable-next-line no-await-in-loop + let a = rand ? rand() : await random.getRandomBN(new BN(2), n1); let x = a.toRed(red).redPow(d); if (x.eq(rone) || x.eq(rn1)) diff --git a/src/crypto/public_key/rsa.js b/src/crypto/public_key/rsa.js index baae76ca..ac5c9e2f 100644 --- a/src/crypto/public_key/rsa.js +++ b/src/crypto/public_key/rsa.js @@ -55,7 +55,7 @@ export default { * @param d private MPI part as BN * @return BN */ - sign: function(m, n, e, d) { + sign: async function(m, n, e, d) { if (n.cmp(m) <= 0) { throw new Error('Data too large.'); } @@ -70,7 +70,7 @@ export default { * @param e public MPI part as BN * @return BN */ - verify: function(s, n, e) { + verify: async function(s, n, e) { if (n.cmp(s) <= 0) { throw new Error('Data too large.'); } @@ -85,7 +85,7 @@ export default { * @param e public MPI part as BN * @return BN */ - encrypt: function(m, n, e) { + encrypt: async function(m, n, e) { if (n.cmp(m) <= 0) { throw new Error('Data too large.'); } @@ -104,7 +104,7 @@ export default { * @param u RSA u as BN * @return {BN} The decrypted value of the message */ - decrypt: function(m, n, e, d, p, q, u) { + decrypt: async function(m, n, e, d, p, q, u) { if (n.cmp(m) <= 0) { throw new Error('Data too large.'); } @@ -117,7 +117,7 @@ export default { let blinder; let unblinder; if (config.rsa_blinding) { - unblinder = random.getRandomBN(new BN(2), n).toRed(nred); + unblinder = (await random.getRandomBN(new BN(2), n)).toRed(nred); blinder = unblinder.redInvm().redPow(e); m = m.toRed(nred).redMul(blinder).fromRed(); } @@ -204,8 +204,8 @@ export default { // RSA keygen fallback using 40 iterations of the Miller-Rabin test // See https://stackoverflow.com/a/6330138 for justification // Also see section C.3 here: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST - let p = prime.randomProbablePrime(B - (B >> 1), E, 40); - let q = prime.randomProbablePrime(B >> 1, E, 40); + let p = await prime.randomProbablePrime(B - (B >> 1), E, 40); + let q = await prime.randomProbablePrime(B >> 1, E, 40); if (p.cmp(q) < 0) { [p, q] = [q, p]; diff --git a/src/crypto/signature.js b/src/crypto/signature.js index 28ed2d92..8b77c6d2 100644 --- a/src/crypto/signature.js +++ b/src/crypto/signature.js @@ -34,7 +34,7 @@ export default { const m = msg_MPIs[0].toBN(); const n = pub_MPIs[0].toBN(); const e = pub_MPIs[1].toBN(); - const EM = publicKey.rsa.verify(m, n, e); + const EM = await publicKey.rsa.verify(m, n, e); const EM2 = pkcs1.emsa.encode(hash_algo, util.Uint8Array_to_str(data), n.byteLength()); return util.Uint8Array_to_hex(EM) === EM2; } @@ -88,7 +88,7 @@ export default { const d = key_params[2].toBN(); data = util.Uint8Array_to_str(data); const m = new BN(pkcs1.emsa.encode(hash_algo, data, n.byteLength()), 16); - const signature = publicKey.rsa.sign(m, n, e, d); + const signature = await publicKey.rsa.sign(m, n, e, d); return util.Uint8Array_to_MPI(signature); } case enums.publicKey.dsa: { @@ -96,7 +96,7 @@ export default { const q = key_params[1].toBN(); const g = key_params[2].toBN(); const x = key_params[4].toBN(); - const signature = publicKey.dsa.sign(hash_algo, data, g, p, q, x); + const signature = await publicKey.dsa.sign(hash_algo, data, g, p, q, x); return util.concatUint8Array([ util.Uint8Array_to_MPI(signature.r), util.Uint8Array_to_MPI(signature.s) diff --git a/src/key.js b/src/key.js index cbf7d99c..5af81553 100644 --- a/src/key.js +++ b/src/key.js @@ -380,35 +380,32 @@ Key.prototype.getEncryptionKeyPacket = function(keyId, date=new Date()) { * Encrypts all secret key and subkey packets * @param {String} passphrase */ -Key.prototype.encrypt = function(passphrase) { +Key.prototype.encrypt = async function(passphrase) { if (!this.isPrivate()) { throw new Error("Nothing to encrypt in a public key"); } const keys = this.getAllKeyPackets(); - for (let i = 0; i < keys.length; i++) { - keys[i].encrypt(passphrase); - keys[i].clearPrivateParams(); - } + await Promise.all(keys.map(async function(packet) { + await packet.encrypt(passphrase); + await packet.clearPrivateParams(); + return packet; + })); + return true; }; /** * Decrypts all secret key and subkey packets * @param {String} passphrase - * @return {Boolean} true if all key and subkey packets decrypted successfully + * @return {Promise} true if all key and subkey packets decrypted successfully */ -Key.prototype.decrypt = function(passphrase) { - if (this.isPrivate()) { - const keys = this.getAllKeyPackets(); - for (let i = 0; i < keys.length; i++) { - const success = keys[i].decrypt(passphrase); - if (!success) { - return false; - } - } - } else { +Key.prototype.decrypt = async function(passphrase) { + if (!this.isPrivate()) { throw new Error("Nothing to decrypt in a public key"); } + + const keys = this.getAllKeyPackets(); + await Promise.all(keys.map(packet => packet.decrypt(passphrase))); return true; }; @@ -1254,46 +1251,48 @@ export function generate(options) { * @return {module:key~Key} * @static */ -export function reformat(options) { +export async function reformat(options) { let secretKeyPacket; let secretSubkeyPacket; - return Promise.resolve().then(() => { - options.keyType = options.keyType || enums.publicKey.rsa_encrypt_sign; - if (options.keyType !== enums.publicKey.rsa_encrypt_sign) { // RSA Encrypt-Only and RSA Sign-Only are deprecated and SHOULD NOT be generated - throw new Error('Only RSA Encrypt or Sign supported'); - } - if (!options.privateKey.decrypt()) { - throw new Error('Key not decrypted'); - } + options.keyType = options.keyType || enums.publicKey.rsa_encrypt_sign; + if (options.keyType !== enums.publicKey.rsa_encrypt_sign) { // RSA Encrypt-Only and RSA Sign-Only are deprecated and SHOULD NOT be generated + throw new Error('Only RSA Encrypt or Sign supported'); + } - if (!options.passphrase) { // Key without passphrase is unlocked by definition - options.unlocked = true; + try { + await options.privateKey.decrypt(); + } + catch(err) { + throw new Error('Key not decrypted'); + } + + if (!options.passphrase) { // Key without passphrase is unlocked by definition + options.unlocked = true; + } + if (util.isString(options.userIds)) { + options.userIds = [options.userIds]; + } + const packetlist = options.privateKey.toPacketlist(); + for (let i = 0; i < packetlist.length; i++) { + if (packetlist[i].tag === enums.packet.secretKey) { + secretKeyPacket = packetlist[i]; + options.keyType = secretKeyPacket.algorithm; + } else if (packetlist[i].tag === enums.packet.secretSubkey) { + secretSubkeyPacket = packetlist[i]; + options.subkeyType = secretSubkeyPacket.algorithm; } - if (util.isString(options.userIds)) { - options.userIds = [options.userIds]; - } - const packetlist = options.privateKey.toPacketlist(); - for (let i = 0; i < packetlist.length; i++) { - if (packetlist[i].tag === enums.packet.secretKey) { - secretKeyPacket = packetlist[i]; - options.keyType = secretKeyPacket.algorithm; - } else if (packetlist[i].tag === enums.packet.secretSubkey) { - secretSubkeyPacket = packetlist[i]; - options.subkeyType = secretSubkeyPacket.algorithm; - } - } - if (!secretKeyPacket) { - throw new Error('Key does not contain a secret key packet'); - } - return wrapKeyObject(secretKeyPacket, secretSubkeyPacket, options); - }); + } + if (!secretKeyPacket) { + throw new Error('Key does not contain a secret key packet'); + } + return wrapKeyObject(secretKeyPacket, secretSubkeyPacket, options); } async function wrapKeyObject(secretKeyPacket, secretSubkeyPacket, options) { // set passphrase protection if (options.passphrase) { - secretKeyPacket.encrypt(options.passphrase); + await secretKeyPacket.encrypt(options.passphrase); if (secretSubkeyPacket) { secretSubkeyPacket.encrypt(options.passphrase); } diff --git a/src/message.js b/src/message.js index 9109b804..40788a4a 100644 --- a/src/message.js +++ b/src/message.js @@ -262,7 +262,7 @@ Message.prototype.encrypt = function(keys, passwords, sessionKey, wildcard=false } if (!sessionKey) { - sessionKey = crypto.generateSessionKey(symAlgo); + sessionKey = await crypto.generateSessionKey(symAlgo); } msg = await encryptSessionKey(sessionKey, symAlgo, keys, passwords, wildcard, date); diff --git a/src/openpgp.js b/src/openpgp.js index bbe9f658..a7c0d048 100644 --- a/src/openpgp.js +++ b/src/openpgp.js @@ -179,6 +179,26 @@ export function decryptKey({ privateKey, passphrase }) { }).catch(onError.bind(null, 'Error decrypting private key')); } +/** + * Lock a private key with your passphrase. + * @param {Key} privateKey the private key that is to be decrypted + * @param {String} passphrase the user's passphrase chosen during key generation + * @return {Key} the locked private key + */ +export function encryptKey({ privateKey, passphrase }) { + if (asyncProxy) { // use web worker if available + return asyncProxy.delegate('encryptKey', { privateKey, passphrase }); + } + + return Promise.resolve().then(async function() { + await privateKey.encrypt(passphrase); + + return { + key: privateKey + }; + }).catch(onError.bind(null, 'Error decrypting private key')); +} + /////////////////////////////////////////// // // diff --git a/src/packet/public_key_encrypted_session_key.js b/src/packet/public_key_encrypted_session_key.js index 5342b649..a14a67cb 100644 --- a/src/packet/public_key_encrypted_session_key.js +++ b/src/packet/public_key_encrypted_session_key.js @@ -112,7 +112,7 @@ PublicKeyEncryptedSessionKey.prototype.encrypt = async function (key) { if (algo === enums.publicKey.ecdh) { toEncrypt = new type_mpi(crypto.pkcs5.encode(data)); } else { - toEncrypt = new type_mpi(crypto.pkcs1.eme.encode(data, key.params[0].byteLength())); + toEncrypt = new type_mpi(await crypto.pkcs1.eme.encode(data, key.params[0].byteLength())); } this.encrypted = await crypto.publicKeyEncrypt( diff --git a/src/packet/secret_key.js b/src/packet/secret_key.js index dc9d7a50..e7046f52 100644 --- a/src/packet/secret_key.js +++ b/src/packet/secret_key.js @@ -81,7 +81,7 @@ function parse_cleartext_params(hash_algorithm, cleartext, algorithm) { const hash = util.Uint8Array_to_str(hashfn(cleartext)); if (hash !== hashtext) { - return new Error("Hash mismatch."); + return new Error("Incorrect key passphrase"); } const algo = enums.write(enums.publicKey, algorithm); @@ -173,7 +173,7 @@ SecretKey.prototype.write = function () { * This can be used to remove passphrase protection after calling decrypt(). * @param {String} passphrase */ -SecretKey.prototype.encrypt = function (passphrase) { +SecretKey.prototype.encrypt = async function (passphrase) { if (this.isDecrypted && !passphrase) { this.encrypted = null; return; @@ -182,11 +182,12 @@ SecretKey.prototype.encrypt = function (passphrase) { } const s2k = new type_s2k(); + s2k.salt = await crypto.random.getRandomBytes(8); const symmetric = 'aes256'; const cleartext = write_cleartext_params('sha1', this.algorithm, this.params); const key = produceEncryptionKey(s2k, passphrase, symmetric); const blockLen = crypto.cipher[symmetric].blockSize; - const iv = crypto.random.getRandomBytes(blockLen); + const iv = await crypto.random.getRandomBytes(blockLen); const arr = [new Uint8Array([254, enums.write(enums.symmetric, symmetric)])]; arr.push(s2k.write()); @@ -213,7 +214,7 @@ function produceEncryptionKey(s2k, passphrase, algorithm) { * @return {Boolean} True if the passphrase was correct or param already * decrypted; false if not */ -SecretKey.prototype.decrypt = function (passphrase) { +SecretKey.prototype.decrypt = async function (passphrase) { if (this.isDecrypted) { return true; } @@ -261,12 +262,11 @@ SecretKey.prototype.decrypt = function (passphrase) { const privParams = parse_cleartext_params(hash, cleartext, this.algorithm); if (privParams instanceof Error) { - return false; + throw privParams; } this.params = this.params.concat(privParams); this.isDecrypted = true; this.encrypted = null; - return true; }; SecretKey.prototype.generate = function (bits, curve) { diff --git a/src/packet/sym_encrypted_aead_protected.js b/src/packet/sym_encrypted_aead_protected.js index 0557883c..a6fbe934 100644 --- a/src/packet/sym_encrypted_aead_protected.js +++ b/src/packet/sym_encrypted_aead_protected.js @@ -66,10 +66,8 @@ SymEncryptedAEADProtected.prototype.write = function () { * @param {Uint8Array} key The session key used to encrypt the payload * @return {Promise} Nothing is returned */ -SymEncryptedAEADProtected.prototype.decrypt = function (sessionKeyAlgorithm, key) { - return crypto.gcm.decrypt(sessionKeyAlgorithm, this.encrypted, key, this.iv).then(decrypted => { - this.packets.read(decrypted); - }); +SymEncryptedAEADProtected.prototype.decrypt = async function (sessionKeyAlgorithm, key) { + this.packets.read(await crypto.gcm.decrypt(sessionKeyAlgorithm, this.encrypted, key, this.iv)); }; /** @@ -78,9 +76,7 @@ SymEncryptedAEADProtected.prototype.decrypt = function (sessionKeyAlgorithm, key * @param {Uint8Array} key The session key used to encrypt the payload * @return {Promise} Nothing is returned */ -SymEncryptedAEADProtected.prototype.encrypt = function (sessionKeyAlgorithm, key) { - this.iv = crypto.random.getRandomBytes(IV_LEN); // generate new random IV - return crypto.gcm.encrypt(sessionKeyAlgorithm, this.packets.write(), key, this.iv).then(encrypted => { - this.encrypted = encrypted; - }); +SymEncryptedAEADProtected.prototype.encrypt = async function (sessionKeyAlgorithm, key) { + this.iv = await crypto.random.getRandomBytes(IV_LEN); // generate new random IV + this.encrypted = await crypto.gcm.encrypt(sessionKeyAlgorithm, this.packets.write(), key, this.iv); }; diff --git a/src/packet/sym_encrypted_integrity_protected.js b/src/packet/sym_encrypted_integrity_protected.js index 25a9075d..6b8c7c29 100644 --- a/src/packet/sym_encrypted_integrity_protected.js +++ b/src/packet/sym_encrypted_integrity_protected.js @@ -81,9 +81,9 @@ SymEncryptedIntegrityProtected.prototype.write = function () { * @param {Uint8Array} key The key of cipher blocksize length to be used * @return {Promise} */ -SymEncryptedIntegrityProtected.prototype.encrypt = function (sessionKeyAlgorithm, key) { +SymEncryptedIntegrityProtected.prototype.encrypt = async function (sessionKeyAlgorithm, key) { const bytes = this.packets.write(); - const prefixrandom = crypto.getPrefixRandom(sessionKeyAlgorithm); + const prefixrandom = await crypto.getPrefixRandom(sessionKeyAlgorithm); const repeat = new Uint8Array([prefixrandom[prefixrandom.length - 2], prefixrandom[prefixrandom.length - 1]]); const prefix = util.concatUint8Array([prefixrandom, repeat]); const mdc = new Uint8Array([0xD3, 0x14]); // modification detection code packet @@ -98,8 +98,6 @@ SymEncryptedIntegrityProtected.prototype.encrypt = function (sessionKeyAlgorithm this.encrypted = crypto.cfb.encrypt(prefixrandom, sessionKeyAlgorithm, tohash, key, false); this.encrypted = this.encrypted.subarray(0, prefix.length + tohash.length); } - - return Promise.resolve(); }; /** @@ -108,7 +106,7 @@ SymEncryptedIntegrityProtected.prototype.encrypt = function (sessionKeyAlgorithm * @param {Uint8Array} key The key of cipher blocksize length to be used * @return {Promise} */ -SymEncryptedIntegrityProtected.prototype.decrypt = function (sessionKeyAlgorithm, key) { +SymEncryptedIntegrityProtected.prototype.decrypt = async function (sessionKeyAlgorithm, key) { let decrypted; if (sessionKeyAlgorithm.substr(0, 3) === 'aes') { // AES optimizations. Native code for node, asmCrypto for browser. decrypted = aesDecrypt(sessionKeyAlgorithm, this.encrypted, key); diff --git a/src/packet/sym_encrypted_session_key.js b/src/packet/sym_encrypted_session_key.js index fa6d25ab..248b13cc 100644 --- a/src/packet/sym_encrypted_session_key.js +++ b/src/packet/sym_encrypted_session_key.js @@ -52,7 +52,7 @@ export default function SymEncryptedSessionKey() { this.sessionKeyEncryptionAlgorithm = null; this.sessionKeyAlgorithm = 'aes256'; this.encrypted = null; - this.s2k = new type_s2k(); + this.s2k = null; } /** @@ -73,6 +73,7 @@ SymEncryptedSessionKey.prototype.read = function(bytes) { const algo = enums.read(enums.symmetric, bytes[1]); // A string-to-key (S2K) specifier, length as defined above. + this.s2k = new type_s2k(); const s2klength = this.s2k.read(bytes.subarray(2, bytes.length)); // Optionally, the encrypted session key itself, which is decrypted @@ -106,7 +107,7 @@ SymEncryptedSessionKey.prototype.write = function() { * * @return {Uint8Array} The unencrypted session key */ -SymEncryptedSessionKey.prototype.decrypt = function(passphrase) { +SymEncryptedSessionKey.prototype.decrypt = async function(passphrase) { const algo = this.sessionKeyEncryptionAlgorithm !== null ? this.sessionKeyEncryptionAlgorithm : this.sessionKeyAlgorithm; @@ -124,20 +125,23 @@ SymEncryptedSessionKey.prototype.decrypt = function(passphrase) { } }; -SymEncryptedSessionKey.prototype.encrypt = function(passphrase) { +SymEncryptedSessionKey.prototype.encrypt = async function(passphrase) { const algo = this.sessionKeyEncryptionAlgorithm !== null ? this.sessionKeyEncryptionAlgorithm : this.sessionKeyAlgorithm; this.sessionKeyEncryptionAlgorithm = algo; + this.s2k = new type_s2k(); + this.s2k.salt = await crypto.random.getRandomBytes(8); + const length = crypto.cipher[algo].keySize; const key = this.s2k.produce_key(passphrase, length); const algo_enum = new Uint8Array([enums.write(enums.symmetric, this.sessionKeyAlgorithm)]); if (this.sessionKey === null) { - this.sessionKey = crypto.getRandomBytes(crypto.cipher[this.sessionKeyAlgorithm].keySize); + this.sessionKey = await crypto.generateSessionKey(this.sessionKeyAlgorithm); } const private_key = util.concatUint8Array([algo_enum, this.sessionKey]); diff --git a/src/packet/symmetrically_encrypted.js b/src/packet/symmetrically_encrypted.js index 210ef532..c370ef94 100644 --- a/src/packet/symmetrically_encrypted.js +++ b/src/packet/symmetrically_encrypted.js @@ -62,7 +62,7 @@ SymmetricallyEncrypted.prototype.write = function () { * Key as string with the corresponding length to the * algorithm */ -SymmetricallyEncrypted.prototype.decrypt = function (sessionKeyAlgorithm, key) { +SymmetricallyEncrypted.prototype.decrypt = async function (sessionKeyAlgorithm, key) { const decrypted = crypto.cfb.decrypt(sessionKeyAlgorithm, key, this.encrypted, true); // for modern cipher (blocklength != 64 bit, except for Twofish) MDC is required if (!this.ignore_mdc_error && @@ -76,10 +76,10 @@ SymmetricallyEncrypted.prototype.decrypt = function (sessionKeyAlgorithm, key) { return Promise.resolve(); }; -SymmetricallyEncrypted.prototype.encrypt = function (algo, key) { +SymmetricallyEncrypted.prototype.encrypt = async function (algo, key) { const data = this.packets.write(); - this.encrypted = crypto.cfb.encrypt(crypto.getPrefixRandom(algo), algo, data, key, true); + this.encrypted = crypto.cfb.encrypt(await crypto.getPrefixRandom(algo), algo, data, key, true); return Promise.resolve(); }; diff --git a/src/type/s2k.js b/src/type/s2k.js index 1493b18f..d0294dc1 100644 --- a/src/type/s2k.js +++ b/src/type/s2k.js @@ -46,7 +46,7 @@ export default function S2K() { /** Eight bytes of salt in a binary string. * @type {String} */ - this.salt = crypto.random.getRandomBytes(8); + this.salt = null; } S2K.prototype.get_count = function () { diff --git a/src/worker/async_proxy.js b/src/worker/async_proxy.js index 3e42cd42..eb404ed3 100644 --- a/src/worker/async_proxy.js +++ b/src/worker/async_proxy.js @@ -85,8 +85,8 @@ AsyncProxy.prototype.onMessage = function(event) { * Send message to worker with random data * @param {Integer} size Number of bytes to send */ -AsyncProxy.prototype.seedRandom = function(size) { - const buf = crypto.random.getRandomBytes(size); +AsyncProxy.prototype.seedRandom = async function(size) { + const buf = await crypto.random.getRandomBytes(size); this.worker.postMessage({ event:'seed-random', buf }, util.getTransferables(buf)); }; diff --git a/test/crypto/crypto.js b/test/crypto/crypto.js index fde07520..d63c5231 100644 --- a/test/crypto/crypto.js +++ b/test/crypto/crypto.js @@ -373,11 +373,10 @@ describe('API functional testing', function() { it('Asymmetric using RSA with eme_pkcs1 padding', function () { const symmKey = util.Uint8Array_to_str(crypto.generateSessionKey('aes256')); - const RSAUnencryptedData = crypto.pkcs1.eme.encode(symmKey, RSApubMPIs[0].byteLength()) - const RSAUnencryptedMPI = new openpgp.MPI(RSAUnencryptedData); - return crypto.publicKeyEncrypt( - 1, RSApubMPIs, RSAUnencryptedMPI - ).then(RSAEncryptedData => { + return crypto.pkcs1.eme.encode(symmKey, RSApubMPIs[0].byteLength()).then(RSAUnencryptedData => { + const RSAUnencryptedMPI = new openpgp.MPI(RSAUnencryptedData); + return crypto.publicKeyEncrypt(1, RSApubMPIs, RSAUnencryptedMPI); + }).then(RSAEncryptedData => { return crypto.publicKeyDecrypt( 1, RSApubMPIs.concat(RSAsecMPIs), RSAEncryptedData @@ -393,12 +392,10 @@ describe('API functional testing', function() { it('Asymmetric using Elgamal with eme_pkcs1 padding', function () { const symmKey = util.Uint8Array_to_str(crypto.generateSessionKey('aes256')); - const ElgamalUnencryptedData = crypto.pkcs1.eme.encode(symmKey, ElgamalpubMPIs[0].byteLength()); - const ElgamalUnencryptedMPI = new openpgp.MPI(ElgamalUnencryptedData); - - return crypto.publicKeyEncrypt( - 16, ElgamalpubMPIs, ElgamalUnencryptedMPI - ).then(ElgamalEncryptedData => { + return crypto.pkcs1.eme.encode(symmKey, ElgamalpubMPIs[0].byteLength()).then(ElgamalUnencryptedData => { + const ElgamalUnencryptedMPI = new openpgp.MPI(ElgamalUnencryptedData); + return crypto.publicKeyEncrypt(16, ElgamalpubMPIs, ElgamalUnencryptedMPI); + }).then(ElgamalEncryptedData => { return crypto.publicKeyDecrypt( 16, ElgamalpubMPIs.concat(ElgamalsecMPIs), ElgamalEncryptedData diff --git a/test/general/ecc_nist.js b/test/general/ecc_nist.js index df5339b9..f88708d8 100644 --- a/test/general/ecc_nist.js +++ b/test/general/ecc_nist.js @@ -142,7 +142,7 @@ describe('Elliptic Curve Cryptography', function () { data[name].pub_key = pub.keys[0]; return data[name].pub_key; } - function load_priv_key(name) { + async function load_priv_key(name) { if (data[name].priv_key) { return data[name].priv_key; } @@ -151,7 +151,7 @@ describe('Elliptic Curve Cryptography', function () { expect(pk.err).to.not.exist; expect(pk.keys).to.have.length(1); expect(pk.keys[0].primaryKey.getKeyId().toHex()).to.equal(data[name].id); - expect(pk.keys[0].decrypt(data[name].pass)).to.be.true; + expect(await pk.keys[0].decrypt(data[name].pass)).to.be.true; data[name].priv_key = pk.keys[0]; return data[name].priv_key; } @@ -160,10 +160,10 @@ describe('Elliptic Curve Cryptography', function () { load_pub_key('juliet'); done(); }); - it('Load private key', function (done) { - load_priv_key('romeo'); - load_priv_key('juliet'); - done(); + it('Load private key', async function () { + await load_priv_key('romeo'); + await load_priv_key('juliet'); + return true; }); it('Verify clear signed message', function () { const pub = load_pub_key('juliet'); @@ -175,52 +175,45 @@ describe('Elliptic Curve Cryptography', function () { expect(result.signatures[0].valid).to.be.true; }); }); - it('Sign message', function () { - const romeo = load_priv_key('romeo'); - return openpgp.sign({privateKeys: [romeo], data: data.romeo.message + "\n"}).then(function (signed) { - const romeo = load_pub_key('romeo'); - const msg = openpgp.cleartext.readArmored(signed.data); - return openpgp.verify({publicKeys: [romeo], message: msg}).then(function (result) { - expect(result).to.exist; - expect(result.data.trim()).to.equal(data.romeo.message); - expect(result.signatures).to.have.length(1); - expect(result.signatures[0].valid).to.be.true; - }); - }); + it('Sign message', async function () { + const romeoPrivate = await load_priv_key('romeo'); + const signed = await openpgp.sign({privateKeys: [romeoPrivate], data: data.romeo.message + "\n"}); + const romeoPublic = load_pub_key('romeo'); + const msg = openpgp.cleartext.readArmored(signed.data); + const result = await openpgp.verify({publicKeys: [romeoPublic], message: msg}); + + expect(result).to.exist; + expect(result.data.trim()).to.equal(data.romeo.message); + expect(result.signatures).to.have.length(1); + expect(result.signatures[0].valid).to.be.true; }); - it('Decrypt and verify message', function () { + it('Decrypt and verify message', async function () { const juliet = load_pub_key('juliet'); - const romeo = load_priv_key('romeo'); + const romeo = await load_priv_key('romeo'); const msg = openpgp.message.readArmored(data.juliet.message_encrypted); - return openpgp.decrypt( - {privateKeys: romeo, publicKeys: [juliet], message: msg} - ).then(function (result) { - expect(result).to.exist; - // trim required because https://github.com/openpgpjs/openpgpjs/issues/311 - expect(result.data.trim()).to.equal(data.juliet.message); - expect(result.signatures).to.have.length(1); - expect(result.signatures[0].valid).to.be.true; - }); + const result = await openpgp.decrypt({privateKeys: romeo, publicKeys: [juliet], message: msg}); + + expect(result).to.exist; + // trim required because https://github.com/openpgpjs/openpgpjs/issues/311 + expect(result.data.trim()).to.equal(data.juliet.message); + expect(result.signatures).to.have.length(1); + expect(result.signatures[0].valid).to.be.true; }); - it('Encrypt and sign message', function () { - const romeo = load_priv_key('romeo'); - const juliet = load_pub_key('juliet'); - expect(romeo.decrypt(data.romeo.pass)).to.be.true; - return openpgp.encrypt( - {publicKeys: [juliet], privateKeys: [romeo], data: data.romeo.message + "\n"} - ).then(function (encrypted) { - const message = openpgp.message.readArmored(encrypted.data); - const romeo = load_pub_key('romeo'); - const juliet = load_priv_key('juliet'); - return openpgp.decrypt( - {privateKeys: juliet, publicKeys: [romeo], message: message} - ).then(function (result) { - expect(result).to.exist; - expect(result.data.trim()).to.equal(data.romeo.message); - expect(result.signatures).to.have.length(1); - expect(result.signatures[0].valid).to.be.true; - }); - }); + it('Encrypt and sign message', async function () { + const romeoPrivate = await load_priv_key('romeo'); + const julietPublic = load_pub_key('juliet'); + expect(await romeoPrivate.decrypt(data.romeo.pass)).to.be.true; + const encrypted = await openpgp.encrypt({publicKeys: [julietPublic], privateKeys: [romeoPrivate], data: data.romeo.message + "\n"}); + + const message = openpgp.message.readArmored(encrypted.data); + const romeoPublic = load_pub_key('romeo'); + const julietPrivate = await load_priv_key('juliet'); + const result = await openpgp.decrypt({privateKeys: julietPrivate, publicKeys: [romeoPublic], message: message}); + + expect(result).to.exist; + expect(result.data.trim()).to.equal(data.romeo.message); + expect(result.signatures).to.have.length(1); + expect(result.signatures[0].valid).to.be.true; }); it('Generate key', function () { const options = { diff --git a/test/general/key.js b/test/general/key.js index ea7a1147..87d53190 100644 --- a/test/general/key.js +++ b/test/general/key.js @@ -1037,26 +1037,24 @@ describe('Key', function() { }); }); - it('Encrypt key with new passphrase', function() { + it('Encrypt key with new passphrase', async function() { const userId = 'test '; const opt = {numBits: 512, userIds: userId, passphrase: 'passphrase'}; if (openpgp.util.getWebCryptoAll()) { opt.numBits = 2048; } // webkit webcrypto accepts minimum 2048 bit keys - return openpgp.generateKey(opt).then(function(key) { - key = key.key; - const armor1 = key.armor(); - const armor2 = key.armor(); - expect(armor1).to.equal(armor2); - expect(key.decrypt('passphrase')).to.be.true; - expect(key.primaryKey.isDecrypted).to.be.true; - key.encrypt('new_passphrase'); - expect(key.primaryKey.isDecrypted).to.be.false; - expect(key.decrypt('passphrase')).to.be.false; - expect(key.primaryKey.isDecrypted).to.be.false; - expect(key.decrypt('new_passphrase')).to.be.true; - expect(key.primaryKey.isDecrypted).to.be.true; - const armor3 = key.armor(); - expect(armor3).to.not.equal(armor1); - }); + const key = (await openpgp.generateKey(opt)).key; + const armor1 = key.armor(); + const armor2 = key.armor(); + expect(armor1).to.equal(armor2); + expect(await key.decrypt('passphrase')).to.be.true; + expect(key.primaryKey.isDecrypted).to.be.true; + await key.encrypt('new_passphrase'); + expect(key.primaryKey.isDecrypted).to.be.false; + await expect(key.decrypt('passphrase')).to.eventually.be.rejectedWith('Incorrect key passphrase'); + expect(key.primaryKey.isDecrypted).to.be.false; + expect(await key.decrypt('new_passphrase')).to.be.true; + expect(key.primaryKey.isDecrypted).to.be.true; + const armor3 = key.armor(); + expect(armor3).to.not.equal(armor1); }); it('Generate key - ensure keyExpirationTime works', function() { @@ -1268,7 +1266,7 @@ describe('Key', function() { }); }); - it('Throw user friendly error when reformatting encrypted key', function() { + it('Reject with user-friendly error when reformatting encrypted key', function() { const opt = {numBits: 512, userIds: 'test1 ', passphrase: '1234'}; if (openpgp.util.getWebCryptoAll()) { opt.numBits = 2048; } // webkit webcrypto accepts minimum 2048 bit keys return openpgp.generateKey(opt).then(function(original) { diff --git a/test/general/openpgp.js b/test/general/openpgp.js index 6a71eec6..5bbe68ee 100644 --- a/test/general/openpgp.js +++ b/test/general/openpgp.js @@ -635,12 +635,12 @@ describe('OpenPGP.js public api tests', function() { openpgp.config.aead_protect = aead_protectVal; }); - it('Decrypting key with wrong passphrase returns false', function () { - expect(privateKey.keys[0].decrypt('wrong passphrase')).to.be.false; + it('Decrypting key with wrong passphrase rejected', function () { + expect(privateKey.keys[0].decrypt('wrong passphrase')).to.eventually.be.rejectedWith('Incorrect key passphrase'); }); - it('Decrypting key with correct passphrase returns true', function () { - expect(privateKey.keys[0].decrypt(passphrase)).to.be.true; + it('Decrypting key with correct passphrase returns true', async function () { + expect(await privateKey.keys[0].decrypt(passphrase)).to.be.true; }); tryTests('CFB mode (asm.js)', tests, { @@ -719,7 +719,7 @@ describe('OpenPGP.js public api tests', function() { privateKey: privateKey.keys[0], passphrase: 'incorrect' }).catch(function(error){ - expect(error.message).to.match(/Invalid passphrase/); + expect(error.message).to.match(/Incorrect key passphrase/); }); }); }); @@ -727,9 +727,10 @@ describe('OpenPGP.js public api tests', function() { describe('encryptSessionKey, decryptSessionKeys', function() { const sk = new Uint8Array([0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01]); - beforeEach(function(done) { - expect(privateKey.keys[0].decrypt(passphrase)).to.be.true; - privateKey.keys[0].verifyPrimaryUser().then(() => done()); + beforeEach(async function() { + expect(await privateKey.keys[0].decrypt(passphrase)).to.be.true; + await privateKey.keys[0].verifyPrimaryUser(); + return true; }); it('should encrypt with public key', function() { @@ -867,14 +868,13 @@ describe('OpenPGP.js public api tests', function() { '=6XMW\r\n' + '-----END PGP PUBLIC KEY BLOCK-----\r\n\r\n'; - beforeEach(function (done) { - expect(privateKey.keys[0].decrypt(passphrase)).to.be.true; - Promise.all([ - privateKey.keys[0].verifyPrimaryUser(), - privateKey_2000_2008.keys[0].verifyPrimaryUser(), - privateKey_1337.keys[0].verifyPrimaryUser(), - privateKey_2038_2045.keys[0].verifyPrimaryUser() - ]).then(() => done()); + beforeEach( async function () { + expect(await privateKey.keys[0].decrypt(passphrase)).to.be.true; + await privateKey.keys[0].verifyPrimaryUser(); + await privateKey_2000_2008.keys[0].verifyPrimaryUser(); + await privateKey_1337.keys[0].verifyPrimaryUser(); + await privateKey_2038_2045.keys[0].verifyPrimaryUser(); + return true; }); it('should encrypt then decrypt', function () { diff --git a/test/general/openpgp2.js b/test/general/openpgp2.js new file mode 100644 index 00000000..3183ce1e --- /dev/null +++ b/test/general/openpgp2.js @@ -0,0 +1,219 @@ +/* globals tryTests: true */ + +'use strict'; + +var openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../../dist/openpgp'); + +var sinon = require('sinon'), + chai = require('chai'); +chai.use(require('chai-as-promised')); +var expect = chai.expect; + +var pub_key = + ['-----BEGIN PGP PUBLIC KEY BLOCK-----', + 'Version: GnuPG v2.0.19 (GNU/Linux)', + '', + 'mI0EUmEvTgEEANyWtQQMOybQ9JltDqmaX0WnNPJeLILIM36sw6zL0nfTQ5zXSS3+', + 'fIF6P29lJFxpblWk02PSID5zX/DYU9/zjM2xPO8Oa4xo0cVTOTLj++Ri5mtr//f5', + 'GLsIXxFrBJhD/ghFsL3Op0GXOeLJ9A5bsOn8th7x6JucNKuaRB6bQbSPABEBAAG0', + 'JFRlc3QgTWNUZXN0aW5ndG9uIDx0ZXN0QGV4YW1wbGUuY29tPoi5BBMBAgAjBQJS', + 'YS9OAhsvBwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AACgkQSmNhOk1uQJQwDAP6', + 'AgrTyqkRlJVqz2pb46TfbDM2TDF7o9CBnBzIGoxBhlRwpqALz7z2kxBDmwpQa+ki', + 'Bq3jZN/UosY9y8bhwMAlnrDY9jP1gdCo+H0sD48CdXybblNwaYpwqC8VSpDdTndf', + '9j2wE/weihGp/DAdy/2kyBCaiOY1sjhUfJ1GogF49rC4jQRSYS9OAQQA6R/PtBFa', + 'JaT4jq10yqASk4sqwVMsc6HcifM5lSdxzExFP74naUMMyEsKHP53QxTF0Grqusag', + 'Qg/ZtgT0CN1HUM152y7ACOdp1giKjpMzOTQClqCoclyvWOFB+L/SwGEIJf7LSCEr', + 'woBuJifJc8xAVr0XX0JthoW+uP91eTQ3XpsAEQEAAYkBPQQYAQIACQUCUmEvTgIb', + 'LgCoCRBKY2E6TW5AlJ0gBBkBAgAGBQJSYS9OAAoJEOCE90RsICyXuqIEANmmiRCA', + 'SF7YK7PvFkieJNwzeK0V3F2lGX+uu6Y3Q/Zxdtwc4xR+me/CSBmsURyXTO29OWhP', + 'GLszPH9zSJU9BdDi6v0yNprmFPX/1Ng0Abn/sCkwetvjxC1YIvTLFwtUL/7v6NS2', + 'bZpsUxRTg9+cSrMWWSNjiY9qUKajm1tuzPDZXAUEAMNmAN3xXN/Kjyvj2OK2ck0X', + 'W748sl/tc3qiKPMJ+0AkMF7Pjhmh9nxqE9+QCEl7qinFqqBLjuzgUhBU4QlwX1GD', + 'AtNTq6ihLMD5v1d82ZC7tNatdlDMGWnIdvEMCv2GZcuIqDQ9rXWs49e7tq1NncLY', + 'hz3tYjKhoFTKEIq3y3Pp', + '=h/aX', + '-----END PGP PUBLIC KEY BLOCK-----'].join('\n'); + +var priv_key = + ['-----BEGIN PGP PRIVATE KEY BLOCK-----', + 'Version: GnuPG v2.0.19 (GNU/Linux)', + '', + 'lQH+BFJhL04BBADclrUEDDsm0PSZbQ6pml9FpzTyXiyCyDN+rMOsy9J300Oc10kt', + '/nyBej9vZSRcaW5VpNNj0iA+c1/w2FPf84zNsTzvDmuMaNHFUzky4/vkYuZra//3', + '+Ri7CF8RawSYQ/4IRbC9zqdBlzniyfQOW7Dp/LYe8eibnDSrmkQem0G0jwARAQAB', + '/gMDAu7L//czBpE40p1ZqO8K3k7UejemjsQqc7kOqnlDYd1Z6/3NEA/UM30Siipr', + 'KjdIFY5+hp0hcs6EiiNq0PDfm/W2j+7HfrZ5kpeQVxDek4irezYZrl7JS2xezaLv', + 'k0Fv/6fxasnFtjOM6Qbstu67s5Gpl9y06ZxbP3VpT62+Xeibn/swWrfiJjuGEEhM', + 'bgnsMpHtzAz/L8y6KSzViG/05hBaqrvk3/GeEA6nE+o0+0a6r0LYLTemmq6FbaA1', + 'PHo+x7k7oFcBFUUeSzgx78GckuPwqr2mNfeF+IuSRnrlpZl3kcbHASPAOfEkyMXS', + 'sWGE7grCAjbyQyM3OEXTSyqnehvGS/1RdB6kDDxGwgE/QFbwNyEh6K4eaaAThW2j', + 'IEEI0WEnRkPi9fXyxhFsCLSI1XhqTaq7iDNqJTxE+AX2b9ZuZXAxI3Tc/7++vEyL', + '3p18N/MB2kt1Wb1azmXWL2EKlT1BZ5yDaJuBQ8BhphM3tCRUZXN0IE1jVGVzdGlu', + 'Z3RvbiA8dGVzdEBleGFtcGxlLmNvbT6IuQQTAQIAIwUCUmEvTgIbLwcLCQgHAwIB', + 'BhUIAgkKCwQWAgMBAh4BAheAAAoJEEpjYTpNbkCUMAwD+gIK08qpEZSVas9qW+Ok', + '32wzNkwxe6PQgZwcyBqMQYZUcKagC8+89pMQQ5sKUGvpIgat42Tf1KLGPcvG4cDA', + 'JZ6w2PYz9YHQqPh9LA+PAnV8m25TcGmKcKgvFUqQ3U53X/Y9sBP8HooRqfwwHcv9', + 'pMgQmojmNbI4VHydRqIBePawnQH+BFJhL04BBADpH8+0EVolpPiOrXTKoBKTiyrB', + 'UyxzodyJ8zmVJ3HMTEU/vidpQwzISwoc/ndDFMXQauq6xqBCD9m2BPQI3UdQzXnb', + 'LsAI52nWCIqOkzM5NAKWoKhyXK9Y4UH4v9LAYQgl/stIISvCgG4mJ8lzzEBWvRdf', + 'Qm2Ghb64/3V5NDdemwARAQAB/gMDAu7L//czBpE40iPcpLzL7GwBbWFhSWgSLy53', + 'Md99Kxw3cApWCok2E8R9/4VS0490xKZIa5y2I/K8thVhqk96Z8Kbt7MRMC1WLHgC', + 'qJvkeQCI6PrFM0PUIPLHAQtDJYKtaLXxYuexcAdKzZj3FHdtLNWCooK6n3vJlL1c', + 'WjZcHJ1PH7USlj1jup4XfxsbziuysRUSyXkjn92GZLm+64vCIiwhqAYoizF2NHHG', + 'hRTN4gQzxrxgkeVchl+ag7DkQUDANIIVI+A63JeLJgWJiH1fbYlwESByHW+zBFNt', + 'qStjfIOhjrfNIc3RvsggbDdWQLcbxmLZj4sB0ydPSgRKoaUdRHJY0S4vp9ouKOtl', + '2au/P1BP3bhD0fDXl91oeheYth+MSmsJFDg/vZJzCJhFaQ9dp+2EnjN5auNCNbaI', + 'beFJRHFf9cha8p3hh+AK54NRCT++B2MXYf+TPwqX88jYMBv8kk8vYUgo8128r1zQ', + 'EzjviQE9BBgBAgAJBQJSYS9OAhsuAKgJEEpjYTpNbkCUnSAEGQECAAYFAlJhL04A', + 'CgkQ4IT3RGwgLJe6ogQA2aaJEIBIXtgrs+8WSJ4k3DN4rRXcXaUZf667pjdD9nF2', + '3BzjFH6Z78JIGaxRHJdM7b05aE8YuzM8f3NIlT0F0OLq/TI2muYU9f/U2DQBuf+w', + 'KTB62+PELVgi9MsXC1Qv/u/o1LZtmmxTFFOD35xKsxZZI2OJj2pQpqObW27M8Nlc', + 'BQQAw2YA3fFc38qPK+PY4rZyTRdbvjyyX+1zeqIo8wn7QCQwXs+OGaH2fGoT35AI', + 'SXuqKcWqoEuO7OBSEFThCXBfUYMC01OrqKEswPm/V3zZkLu01q12UMwZach28QwK', + '/YZly4ioND2tdazj17u2rU2dwtiHPe1iMqGgVMoQirfLc+k=', + '=lw5e', + '-----END PGP PRIVATE KEY BLOCK-----'].join('\n'); + +var pub_key_de = + ['-----BEGIN PGP PUBLIC KEY BLOCK-----', + 'Version: GnuPG v2.0.22 (GNU/Linux)', + '', + 'mQMuBFLVgdQRCACOlpq0cd1IazNjOEpWPZvx/O3JMbdDs3B3iCG0Mo5OUZ8lpKU5', + 'EslVgTd8IcUU14ZMOO7y91dw0KP4q61b4OIy7oVxzfFfKCC1s0Dc7GTay+qo5afJ', + 'wbWcgTyCIahTRmi5UepU7xdRHRMlqAclOwY2no8fw0JRQfFwRFCjbMdmvzC/k+Wo', + 'A42nn8YaSAG2v7OqF3rkYjkv/7iak48PO/l0Q13USAJLIWdHvRTir78mQUsEY0qR', + 'VoNqz5sMqakzhTvTav07EVy/1xC6GKoWXA9sdB/4r7+blVuu9M4yD40GkE69oAXO', + 'mz6tG3lRq41S0OSzNyDWtUQgMVF6wYqVxUGrAQDJM5A1rF1RKzFiHdkyy57E8LC1', + 'SIJyIXWJ0c5b8/olWQf9G5a17fMjkRTC3FO+ZHwFE1jIM6znYOF2GltDToLuJPq9', + 'lWrI7zVP9AJPwrUt7FK2MBNAvd1jKyIhdU98PBQ2pr+jmyqIycl9iDGXLDO7D7E/', + 'TBnxwQzoL/5b7UnPImuXOwv5JhVmyV2t003xjzb1EGggOnpKugUtVLps8JiLl9n+', + 'Nkj5wpU7NXbuHj2XGkkGmKkCIz4l0dJQR9V6svJV9By0RPgfGPXlN1VR6f2ounNy', + '6REnDCQP9S3Li5eNcxlSGDIxIZL22j63sU/68GVlzqhVdGXxofv5jGtajiNSpPot', + 'ElZU0dusna4PzYmiBCsyN8jENWSzHLJ37N4ScN4b/gf6Axf9FU0PjzPBN1o9W6zj', + 'kpfhlSWDjE3BK8jJ7KvzecM2QE/iJsbuyKEsklw1v0MsRDsox5QlQJcKOoUHC+OT', + 'iKm8cnPckLQNPOw/kb+5Auz7TXBQ63dogDuqO8QGGOpjh8SIYbblYQI5ueo1Tix3', + 'PlSU36SzOQfxSOCeIomEmaFQcU57O1CLsRl//+5lezMFDovJyQHQZfiTxSGfPHij', + 'oQzEUyEWYHKQhIRV6s5VGvF3hN0t8fo0o57bzhV6E7IaSz2Cnm0O0S2PZt8DBN9l', + 'LYNw3cFgzMb/qdFJGR0JXz+moyAYh/fYMiryb6d8ghhvrRy0CrRlC3U5K6qiYfKu', + 'lLQURFNBL0VMRyA8ZHNhQGVsZy5qcz6IewQTEQgAIwUCUtWB1AIbAwcLCQgHAwIB', + 'BhUIAgkKCwQWAgMBAh4BAheAAAoJELqZP8Ku4Yo6Aa0A/1Kz5S8d9czLiDbrhSa/', + 'C1rQ5qiWpFq9UNTFg2P/gASvAP92TzUMLK2my8ew1xXShtrfXked5fkSuFrPlZBs', + 'b4Ta67kCDQRS1YHUEAgAxOKx4y5QD78uPLlgNBHXrcncUNBIt4IXBGjQTxpFcn5j', + 'rSuj+ztvXJQ8wCkx+TTb2yuL5M+nXd7sx4s+M4KZ/MZfI6ZX4lhcoUdAbB9FWiV7', + 'uNntyeFo8qgGM5at/Q0EsyzMSqbeBxk4bpd5MfYGThn0Ae2xaw3X94KaZ3LjtHo2', + 'V27FD+jvmmoAj9b1+zcO/pJ8SuojQmcnS4VDVV+Ba5WPTav0LzDdQXyGMZI9PDxC', + 'jAI2f1HjTuxIt8X8rAQSQdoMIcQRYEjolsXS6iob1eVigyL86hLJjI3VPn6kBCv3', + 'Tb+WXX+9LgSAt9yvv4HMwBLK33k6IH7M72SqQulZywADBQgAt2xVTMjdVyMniMLj', + 'Ed4HbUgwyCPkVkcA4zTXqfKu+dAe4dK5tre0clkXZVtR1V8RDAD0zaVyM030e2zb', + 'zn4cGKDL2dmwk2ZBeXWZDgGKoKvGKYf8PRpTAYweFzol3OUdfXH5SngOylCD4OCL', + 's4RSVkSsllIWqLpnS5IJFgt6PDVcQgGXo2ZhVYkoLNhWTIEBuJWIyc4Vj20YpTms', + 'lgHnjeq5rP6781MwAJQnViyJ2SziGK4/+3CoDiQLO1zId42otXBvsbUuLSL5peX4', + 'v2XNVMLJMY5iSfzbBWczecyapiQ3fbVtWgucgrqlrqM3546v+GdATBhGOu8ppf5j', + '7d1A7ohhBBgRCAAJBQJS1YHUAhsMAAoJELqZP8Ku4Yo6SgoBAIVcZstwz4lyA2et', + 'y61IhKbJCOlQxyem+kepjNapkhKDAQDIDL38bZWU4Rm0nq82Xb4yaI0BCWDcFkHV', + 'og2umGfGng==', + '=v3+L', + '-----END PGP PUBLIC KEY BLOCK-----'].join('\n'); + +var priv_key_de = + ['-----BEGIN PGP PRIVATE KEY BLOCK-----', + 'Version: GnuPG v2.0.22 (GNU/Linux)', + '', + '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', + 'DHTORVqAOdoOcu5Qh7AQg1GdSmfFAsx2', + '=kyeP', + '-----END PGP PRIVATE KEY BLOCK-----'].join('\n'); + +var passphrase = 'hello world'; +var plaintext = 'short message\nnext line\n한국어/조선말'; +var password1 = 'I am a password'; +var password2 = 'I am another password'; + +var fuckedUp = ['-----BEGIN PGP MESSAGE-----', +'Version: OpenPGP.js v3.0.0', +'Comment: https://openpgpjs.org', +'', +'wy4ECQMIWjj3WEfWxGpgrfb3vXu0TS9L8UNTBvNZFIjltGjMVkLFD+/afgs5', +'aXt0wy4ECQMIrFo3TFN5xqtgtB+AaAjBcWJrA4bvIPBpJ38PbMWeF0JQgrqg', +'j3uehxXy0mUB5i7B61g0ho+YplyFGM0s9XayJCnu40tWmr5LqqsRxuwrhJKR', +'migslOF/l6Y9F0F9xGIZWGhxp3ugQPjVKjj8fOH7ap14mLm60C8q8AOxiSmL', +'ubsd/hL7FPZatUYAAZVA0a6hmQ==', +'=cHCV', +'-----END PGP MESSAGE-----'].join('\n'); + +describe('encrypt, decrypt, sign, verify - integration tests', function() { + var privateKey, publicKey, zero_copyVal, use_nativeVal, aead_protectVal; + + beforeEach(function(done) { + publicKey = openpgp.key.readArmored(pub_key); + expect(publicKey.keys).to.have.length(1); + expect(publicKey.err).to.not.exist; + privateKey = openpgp.key.readArmored(priv_key); + expect(privateKey.keys).to.have.length(1); + expect(privateKey.err).to.not.exist; + zero_copyVal = openpgp.config.zero_copy; + use_nativeVal = openpgp.config.use_native; + aead_protectVal = openpgp.config.aead_protect; + privateKey.keys[0].verifyPrimaryUser().then(() => done()); + }); + + afterEach(function() { + openpgp.config.zero_copy = zero_copyVal; + openpgp.config.use_native = use_nativeVal; + openpgp.config.aead_protect = aead_protectVal; + }); + + it('should encrypt and decrypt with two passwords', function() { + var encOpt = { + data: plaintext, + passwords: [password1, password2] + }; + var decOpt = { + password: password2 + }; + return openpgp.encrypt(encOpt).then(function(encrypted) { + encrypted.data = fuckedUp; + //console.log(encrypted.data); + decOpt.message = openpgp.message.readArmored(encrypted.data); + return openpgp.decrypt(decOpt); + }).then(function(decrypted) { + expect(decrypted.data).to.equal(plaintext); + expect(decrypted.signatures.length).to.equal(0); + }); + }); +}); diff --git a/test/general/packet.js b/test/general/packet.js index 8e924fff..c5fe98d4 100644 --- a/test/general/packet.js +++ b/test/general/packet.js @@ -55,7 +55,7 @@ describe("Packet", function() { '=KXkj\n' + '-----END PGP PRIVATE KEY BLOCK-----'; - it('Symmetrically encrypted packet', function(done) { + it('Symmetrically encrypted packet', async function() { const message = new openpgp.packet.List(); const literal = new openpgp.packet.Literal(); @@ -68,18 +68,17 @@ describe("Packet", function() { const key = new Uint8Array([1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2]); const algo = 'aes256'; - enc.encrypt(algo, key); + await enc.encrypt(algo, key); const msg2 = new openpgp.packet.List(); msg2.read(message.write()); msg2[0].ignore_mdc_error = true; - msg2[0].decrypt(algo, key); + await msg2[0].decrypt(algo, key); expect(stringify(msg2[0].packets[0].data)).to.equal(stringify(literal.data)); - done(); }); - it('Symmetrically encrypted packet - MDC error for modern cipher', function() { + it('Symmetrically encrypted packet - MDC error for modern cipher', async function() { const message = new openpgp.packet.List(); const literal = new openpgp.packet.Literal(); @@ -87,19 +86,19 @@ describe("Packet", function() { const enc = new openpgp.packet.SymmetricallyEncrypted(); message.push(enc); - enc.packets.push(literal); + await enc.packets.push(literal); const key = '12345678901234567890123456789012'; const algo = 'aes256'; - enc.encrypt(algo, key); + await enc.encrypt(algo, key); const msg2 = new openpgp.packet.List(); msg2.read(message.write()); - expect(msg2[0].decrypt.bind(msg2[0], algo, key)).to.throw('Decryption failed due to missing MDC in combination with modern cipher.'); + expect(msg2[0].decrypt(algo, key)).to.eventually.be.rejectedWith('Decryption failed due to missing MDC in combination with modern cipher.'); }); - it('Sym. encrypted integrity protected packet', function(done) { + it('Sym. encrypted integrity protected packet', async function() { const key = new Uint8Array([1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2]); const algo = 'aes256'; @@ -110,15 +109,14 @@ describe("Packet", function() { msg.push(enc); literal.setText('Hello world!'); enc.packets.push(literal); - enc.encrypt(algo, key); + await enc.encrypt(algo, key); const msg2 = new openpgp.packet.List(); msg2.read(msg.write()); - msg2[0].decrypt(algo, key); + await msg2[0].decrypt(algo, key); expect(stringify(msg2[0].packets[0].data)).to.equal(stringify(literal.data)); - done(); }); it('Sym. encrypted AEAD protected packet', function() { @@ -310,7 +308,7 @@ describe("Packet", function() { }); }); - it('Sym. encrypted session key reading/writing', function(done) { + it('Sym. encrypted session key reading/writing', async function() { const passphrase = 'hello'; const algo = 'aes256'; @@ -323,23 +321,22 @@ describe("Packet", function() { msg.push(enc); key_enc.sessionKeyAlgorithm = algo; - key_enc.decrypt(passphrase); + await key_enc.encrypt(passphrase); const key = key_enc.sessionKey; literal.setText('Hello world!'); enc.packets.push(literal); - enc.encrypt(algo, key); + await enc.encrypt(algo, key); const msg2 = new openpgp.packet.List(); msg2.read(msg.write()); - msg2[0].decrypt(passphrase); + await msg2[0].decrypt(passphrase); const key2 = msg2[0].sessionKey; - msg2[1].decrypt(msg2[0].sessionKeyAlgorithm, key2); + await msg2[1].decrypt(msg2[0].sessionKeyAlgorithm, key2); expect(stringify(msg2[1].packets[0].data)).to.equal(stringify(literal.data)); - done(); }); it('Secret key encryption/decryption test', function() { diff --git a/test/general/x25519.js b/test/general/x25519.js index cd21bca1..b7849304 100644 --- a/test/general/x25519.js +++ b/test/general/x25519.js @@ -127,7 +127,7 @@ describe('X25519 Cryptography', function () { return data[name].pub_key; } - function load_priv_key(name) { + async function load_priv_key(name) { if (data[name].priv_key) { return data[name].priv_key; } @@ -136,7 +136,7 @@ describe('X25519 Cryptography', function () { expect(pk.err).to.not.exist; expect(pk.keys).to.have.length(1); expect(pk.keys[0].primaryKey.getKeyId().toHex()).to.equal(data[name].id); - expect(pk.keys[0].decrypt(data[name].pass)).to.be.true; + expect(await pk.keys[0].decrypt(data[name].pass)).to.be.true; data[name].priv_key = pk.keys[0]; return data[name].priv_key; } @@ -149,10 +149,10 @@ describe('X25519 Cryptography', function () { // This test is slow because the keys are generated by GPG2, which // by default chooses a larger number for S2K iterations than we do. - it('Load private key', function (done) { - load_priv_key('light'); - load_priv_key('night'); - done(); + it('Load private key', async function () { + await load_priv_key('light'); + await load_priv_key('night'); + return true; }); it('Verify clear signed message', function () { @@ -167,56 +167,49 @@ describe('X25519 Cryptography', function () { }); }); - it('Sign message', function () { + it('Sign message', async function () { const name = 'light'; - const priv = load_priv_key(name); - return openpgp.sign({ privateKeys: [priv], data: data[name].message + "\n" }).then(function (signed) { - const pub = load_pub_key(name); - const msg = openpgp.cleartext.readArmored(signed.data); - return openpgp.verify({ publicKeys: [pub], message: msg}).then(function (result) { - expect(result).to.exist; - expect(result.data.trim()).to.equal(data[name].message); - expect(result.signatures).to.have.length(1); - expect(result.signatures[0].valid).to.be.true; - }); - }); + const priv = await load_priv_key(name); + const signed = await openpgp.sign({ privateKeys: [priv], data: data[name].message + "\n" }); + const pub = load_pub_key(name); + const msg = openpgp.cleartext.readArmored(signed.data); + const result = await openpgp.verify({ publicKeys: [pub], message: msg}); + + expect(result).to.exist; + expect(result.data.trim()).to.equal(data[name].message); + expect(result.signatures).to.have.length(1); + expect(result.signatures[0].valid).to.be.true; }); - it('Decrypt and verify message', function () { + it('Decrypt and verify message', async function () { const light = load_pub_key('light'); - const night = load_priv_key('night'); - expect(night.decrypt(data.night.pass)).to.be.true; + const night = await load_priv_key('night'); + expect(await night.decrypt(data.night.pass)).to.be.true; const msg = openpgp.message.readArmored(data.night.message_encrypted); - return openpgp.decrypt( - { privateKeys: night, publicKeys: [light], message: msg } - ).then(function (result) { - expect(result).to.exist; - // trim required because https://github.com/openpgpjs/openpgpjs/issues/311 - expect(result.data.trim()).to.equal(data.night.message); - expect(result.signatures).to.have.length(1); - expect(result.signatures[0].valid).to.be.true; - }); + const result = await openpgp.decrypt({ privateKeys: night, publicKeys: [light], message: msg }); + + expect(result).to.exist; + // trim required because https://github.com/openpgpjs/openpgpjs/issues/311 + expect(result.data.trim()).to.equal(data.night.message); + expect(result.signatures).to.have.length(1); + expect(result.signatures[0].valid).to.be.true; }); - it('Encrypt and sign message', function () { - const night = load_pub_key('night'); - const light = load_priv_key('light'); - expect(light.decrypt(data.light.pass)).to.be.true; - openpgp.encrypt( - { publicKeys: [night], privateKeys: [light], data: data.light.message + "\n" } - ).then(function (encrypted) { - const message = openpgp.message.readArmored(encrypted.data); - const light = load_pub_key('light'); - const night = load_priv_key('night'); - return openpgp.decrypt( - { privateKeys: night, publicKeys: [light], message: message } - ).then(function (result) { - expect(result).to.exist; - expect(result.data.trim()).to.equal(data.light.message); - expect(result.signatures).to.have.length(1); - expect(result.signatures[0].valid).to.be.true; - }); - }); + it('Encrypt and sign message', async function () { + const nightPublic = load_pub_key('night'); + const lightPrivate = await load_priv_key('light'); + expect(await lightPrivate.decrypt(data.light.pass)).to.be.true; + const encrypted = await openpgp.encrypt({ publicKeys: [nightPublic], privateKeys: [lightPrivate], data: data.light.message + "\n" }); + + const message = openpgp.message.readArmored(encrypted.data); + const lightPublic = load_pub_key('light'); + const nightPrivate = await load_priv_key('night'); + const result = await openpgp.decrypt({ privateKeys: nightPrivate, publicKeys: [lightPublic], message: message }); + + expect(result).to.exist; + expect(result.data.trim()).to.equal(data.light.message); + expect(result.signatures).to.have.length(1); + expect(result.signatures[0].valid).to.be.true; }); // TODO export, then reimport key and validate