From 51d7860622c0485ac288c26e49eca6f304c39c35 Mon Sep 17 00:00:00 2001 From: Daniel Huigens Date: Fri, 13 Apr 2018 12:16:36 +0200 Subject: [PATCH] Native CMAC --- src/crypto/cmac.js | 85 +++++- src/crypto/eax.js | 174 +++++------ src/crypto/ocb.js | 325 +++++++++++---------- src/packet/secret_key.js | 6 +- src/packet/sym_encrypted_aead_protected.js | 4 +- src/packet/sym_encrypted_session_key.js | 6 +- test/crypto/eax.js | 2 +- test/crypto/ocb.js | 4 +- 8 files changed, 339 insertions(+), 267 deletions(-) diff --git a/src/crypto/cmac.js b/src/crypto/cmac.js index 34061258..c4c8107a 100644 --- a/src/crypto/cmac.js +++ b/src/crypto/cmac.js @@ -1,21 +1,80 @@ /** + * @fileoverview This module implements AES-CMAC on top of + * native AES-CBC using either the WebCrypto API or Node.js' crypto API. * @requires asmcrypto.js + * @requires util + * @module crypto/cmac */ -import { AES_CMAC } from 'asmcrypto.js/src/aes/cmac/cmac'; +import { AES_CBC } from 'asmcrypto.js/src/aes/cbc/exports'; +import util from '../util'; -export default class CMAC extends AES_CMAC { - constructor(key) { - super(key); - this._k = this.k.slice(); - } +const webCrypto = util.getWebCryptoAll(); +const nodeCrypto = util.getNodeCrypto(); +const Buffer = util.getNodeBuffer(); - mac(data) { - if (this.result) { - this.bufferLength = 0; - this.k.set(this._k, 0); - this.cbc.AES_reset(undefined, new Uint8Array(16), false); - } - return this.process(data).finish().result; + +const blockLength = 16; + + +function set_xor_r(S, T) { + const offset = S.length - blockLength; + for (let i = 0; i < blockLength; i++) { + S[i + offset] ^= T[i]; } + return S; +} + +function mul2(data) { + const t = data[0] & 0x80; + for (let i = 0; i < 15; i++) { + data[i] = (data[i] << 1) ^ ((data[i + 1] & 0x80) ? 1 : 0); + } + data[15] = (data[15] << 1) ^ (t ? 0x87 : 0); + return data; +} + +const zeros_16 = new Uint8Array(16); + +export default async function CMAC(key) { + const cbc = await CBC(key); + const padding = mul2(await cbc(zeros_16)); + const padding2 = mul2(padding.slice()); + + return async function(data) { + return (await cbc(pad(data, padding, padding2))).subarray(-blockLength); + }; +} + +function pad(data, padding, padding2) { + if (data.length % blockLength === 0) { + return set_xor_r(data, padding); + } + const padded = new Uint8Array(data.length + (blockLength - data.length % blockLength)); + padded.set(data); + padded[data.length] = 0b10000000; + return set_xor_r(padded, padding2); +} + +async function CBC(key) { + if (util.getWebCryptoAll() && key.length !== 24) { // WebCrypto (no 192 bit support) see: https://www.chromium.org/blink/webcrypto#TOC-AES-support + key = await webCrypto.importKey('raw', key, { name: 'AES-CBC', length: key.length * 8 }, false, ['encrypt']); + return async function(pt) { + const ct = await webCrypto.encrypt({ name: 'AES-CBC', iv: zeros_16, length: blockLength * 8 }, key, pt); + return new Uint8Array(ct).subarray(0, ct.byteLength - blockLength); + }; + } + if (util.getNodeCrypto()) { // Node crypto library + key = new Buffer(key); + return async function(pt) { + pt = new Buffer(pt); + const en = new nodeCrypto.createCipheriv('aes-' + (key.length * 8) + '-cbc', key, zeros_16); + const ct = en.update(pt); + return new Uint8Array(ct); + }; + } + // asm.js fallback + return async function(pt) { + return AES_CBC.encrypt(pt, key, false, zeros_16); + }; } diff --git a/src/crypto/eax.js b/src/crypto/eax.js index c8c81f8e..86f7396d 100644 --- a/src/crypto/eax.js +++ b/src/crypto/eax.js @@ -41,98 +41,104 @@ const zero = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); const one = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]); const two = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]); -class OMAC extends CMAC { - mac(t, message) { - return super.mac(concat(t, message)); - } +async function OMAC(key) { + const cmac = await CMAC(key); + return function(t, message) { + return cmac(concat(t, message)); + }; } -class CTR { - constructor(key) { - if (util.getWebCryptoAll() && key.length !== 24) { // WebCrypto (no 192 bit support) see: https://www.chromium.org/blink/webcrypto#TOC-AES-support - this.key = webCrypto.importKey('raw', key, { name: 'AES-CTR', length: key.length * 8 }, false, ['encrypt']); - this.ctr = this.webCtr; - } else if (util.getNodeCrypto()) { // Node crypto library - this.key = new Buffer(key); - this.ctr = this.nodeCtr; - } else { - // asm.js fallback - this.key = key; - } +async function CTR(key) { + if (util.getWebCryptoAll() && key.length !== 24) { // WebCrypto (no 192 bit support) see: https://www.chromium.org/blink/webcrypto#TOC-AES-support + key = await webCrypto.importKey('raw', key, { name: 'AES-CTR', length: key.length * 8 }, false, ['encrypt']); + return async function(pt, iv) { + const ct = await webCrypto.encrypt({ name: 'AES-CTR', counter: iv, length: blockLength * 8 }, key, pt); + return new Uint8Array(ct); + }; } - - webCtr(pt, iv) { - return this.key - .then(keyObj => webCrypto.encrypt({ name: 'AES-CTR', counter: iv, length: blockLength * 8 }, keyObj, pt)) - .then(ct => new Uint8Array(ct)); - } - - nodeCtr(pt, iv) { - pt = new Buffer(pt); - iv = new Buffer(iv); - const en = new nodeCrypto.createCipheriv('aes-' + (this.key.length * 8) + '-ctr', this.key, iv); - const ct = Buffer.concat([en.update(pt), en.final()]); - return Promise.resolve(new Uint8Array(ct)); - } - - ctr(pt, iv) { - return Promise.resolve(AES_CTR.encrypt(pt, this.key, iv)); + if (util.getNodeCrypto()) { // Node crypto library + key = new Buffer(key); + return async function(pt, iv) { + pt = new Buffer(pt); + iv = new Buffer(iv); + const en = new nodeCrypto.createCipheriv('aes-' + (key.length * 8) + '-ctr', key, iv); + const ct = Buffer.concat([en.update(pt), en.final()]); + return new Uint8Array(ct); + }; } + // asm.js fallback + return async function(pt, iv) { + return AES_CTR.encrypt(pt, key, iv); + }; } -class EAX { - /** - * Class to en/decrypt using EAX mode. - * @param {String} cipher The symmetric cipher algorithm to use e.g. 'aes128' - * @param {Uint8Array} key The encryption key - */ - constructor(cipher, key) { - if (cipher.substr(0, 3) !== 'aes') { - throw new Error('EAX mode supports only AES cipher'); +/** + * Class to en/decrypt using EAX mode. + * @param {String} cipher The symmetric cipher algorithm to use e.g. 'aes128' + * @param {Uint8Array} key The encryption key + */ +async function EAX(cipher, key) { + if (cipher.substr(0, 3) !== 'aes') { + throw new Error('EAX mode supports only AES cipher'); + } + + const [ + omac, + ctr + ] = await Promise.all([ + OMAC(key), + CTR(key) + ]); + + return { + /** + * Encrypt plaintext input. + * @param {Uint8Array} plaintext The cleartext input to be encrypted + * @param {Uint8Array} nonce The nonce (16 bytes) + * @param {Uint8Array} adata Associated data to sign + * @returns {Promise} The ciphertext output + */ + encrypt: async function(plaintext, nonce, adata) { + const [ + _nonce, + _adata + ] = await Promise.all([ + omac(zero, nonce), + omac(one, adata) + ]); + const ciphered = await ctr(plaintext, _nonce); + const _ciphered = await omac(two, ciphered); + const tag = xor3(_nonce, _ciphered, _adata); // Assumes that omac(*).length === tagLength. + return concat(ciphered, tag); + }, + + /** + * Decrypt ciphertext input. + * @param {Uint8Array} ciphertext The ciphertext input to be decrypted + * @param {Uint8Array} nonce The nonce (16 bytes) + * @param {Uint8Array} adata Associated data to verify + * @returns {Promise} The plaintext output + */ + decrypt: async function(ciphertext, nonce, adata) { + if (ciphertext.length < tagLength) throw new Error('Invalid EAX ciphertext'); + const ciphered = ciphertext.subarray(0, ciphertext.length - tagLength); + const tag = ciphertext.subarray(ciphertext.length - tagLength); + const [ + _nonce, + _adata, + _ciphered + ] = await Promise.all([ + omac(zero, nonce), + omac(one, adata), + omac(two, ciphered) + ]); + const _tag = xor3(_nonce, _ciphered, _adata); // Assumes that omac(*).length === tagLength. + if (!util.equalsUint8Array(tag, _tag)) throw new Error('Authentication tag mismatch in EAX ciphertext'); + const plaintext = await ctr(ciphered, _nonce); + return plaintext; } - - const omac = new OMAC(key); - this.omac = omac.mac.bind(omac); - const ctr = new CTR(key); - this.ctr = ctr.ctr.bind(ctr); - } - - /** - * Encrypt plaintext input. - * @param {Uint8Array} plaintext The cleartext input to be encrypted - * @param {Uint8Array} nonce The nonce (16 bytes) - * @param {Uint8Array} adata Associated data to sign - * @returns {Promise} The ciphertext output - */ - async encrypt(plaintext, nonce, adata) { - const _nonce = this.omac(zero, nonce); - const _adata = this.omac(one, adata); - const ciphered = await this.ctr(plaintext, _nonce); - const _ciphered = this.omac(two, ciphered); - const tag = xor3(_nonce, _ciphered, _adata); // Assumes that omac(*).length === tagLength. - return concat(ciphered, tag); - } - - /** - * Decrypt ciphertext input. - * @param {Uint8Array} ciphertext The ciphertext input to be decrypted - * @param {Uint8Array} nonce The nonce (16 bytes) - * @param {Uint8Array} adata Associated data to verify - * @returns {Promise} The plaintext output - */ - async decrypt(ciphertext, nonce, adata) { - if (ciphertext.length < tagLength) throw new Error('Invalid EAX ciphertext'); - const ciphered = ciphertext.subarray(0, ciphertext.length - tagLength); - const tag = ciphertext.subarray(ciphertext.length - tagLength); - const _nonce = this.omac(zero, nonce); - const _adata = this.omac(one, adata); - const _ciphered = this.omac(two, ciphered); - const _tag = xor3(_nonce, _ciphered, _adata); // Assumes that omac(*).length === tagLength. - if (!util.equalsUint8Array(tag, _tag)) throw new Error('Authentication tag mismatch in EAX ciphertext'); - const plaintext = await this.ctr(ciphered, _nonce); - return plaintext; - } + }; } diff --git a/src/crypto/ocb.js b/src/crypto/ocb.js index 5bfe4aab..034abcd1 100644 --- a/src/crypto/ocb.js +++ b/src/crypto/ocb.js @@ -79,18 +79,19 @@ function double(S) { const zeros_16 = zeros(16); const one = new Uint8Array([1]); -class OCB { - /** - * Class to en/decrypt using OCB mode. - * @param {String} cipher The symmetric cipher algorithm to use e.g. 'aes128' - * @param {Uint8Array} key The encryption key - */ - constructor(cipher, key) { - this.max_ntz = 0; - this.constructKeyVariables(cipher, key); - } +/** + * Class to en/decrypt using OCB mode. + * @param {String} cipher The symmetric cipher algorithm to use e.g. 'aes128' + * @param {Uint8Array} key The encryption key + */ +async function OCB(cipher, key) { - constructKeyVariables(cipher, key) { + let max_ntz = 0; + let kv; + + constructKeyVariables(cipher, key); + + function constructKeyVariables(cipher, key) { const aes = new ciphers[cipher](key); const encipher = aes.encrypt.bind(aes); const decipher = aes.decrypt.bind(aes); @@ -104,25 +105,25 @@ class OCB { L.x = L_x; L.$ = L_$; - this.kv = { encipher, decipher, L }; + kv = { encipher, decipher, L }; } - extendKeyVariables(text, adata) { - const { L } = this.kv; - const max_ntz = util.nbits(Math.max(text.length, adata.length) >> 4) - 1; - for (let i = this.max_ntz + 1; i <= max_ntz; i++) { + function extendKeyVariables(text, adata) { + const { L } = kv; + const new_max_ntz = util.nbits(Math.max(text.length, adata.length) >> 4) - 1; + for (let i = max_ntz + 1; i <= new_max_ntz; i++) { L[i] = double(L[i - 1]); } - this.max_ntz = max_ntz; + max_ntz = new_max_ntz; } - hash(adata) { + function hash(adata) { if (!adata.length) { // Fast path return zeros_16; } - const { encipher, L } = this.kv; + const { encipher, L } = kv; // // Consider A as a sequence of 128-bit blocks @@ -155,154 +156,156 @@ class OCB { } - /** - * Encrypt plaintext input. - * @param {Uint8Array} plaintext The cleartext input to be encrypted - * @param {Uint8Array} nonce The nonce (15 bytes) - * @param {Uint8Array} adata Associated data to sign - * @returns {Promise} The ciphertext output - */ - async encrypt(plaintext, nonce, adata) { - // - // Consider P as a sequence of 128-bit blocks - // - const m = plaintext.length >> 4; + return { + /** + * Encrypt plaintext input. + * @param {Uint8Array} plaintext The cleartext input to be encrypted + * @param {Uint8Array} nonce The nonce (15 bytes) + * @param {Uint8Array} adata Associated data to sign + * @returns {Promise} The ciphertext output + */ + encrypt: async function(plaintext, nonce, adata) { + // + // Consider P as a sequence of 128-bit blocks + // + const m = plaintext.length >> 4; - // - // Key-dependent variables - // - this.extendKeyVariables(plaintext, adata); - const { encipher, L } = this.kv; + // + // Key-dependent variables + // + extendKeyVariables(plaintext, adata); + const { encipher, L } = kv; - // - // Nonce-dependent and per-encryption variables - // - // We assume here that TAGLEN mod 128 == 0 (tagLength === 16). - const Nonce = concat(zeros_16.subarray(0, 15 - nonce.length), one, nonce); - const bottom = Nonce[15] & 0b111111; - Nonce[15] &= 0b11000000; - const Ktop = encipher(Nonce); - const Stretch = concat(Ktop, xor(Ktop.subarray(0, 8), Ktop.subarray(1, 9))); - // Offset_0 = Stretch[1+bottom..128+bottom] - const offset = shiftRight(Stretch.subarray(0 + (bottom >> 3), 17 + (bottom >> 3)), 8 - (bottom & 7)).subarray(1); - const checksum = zeros(16); + // + // Nonce-dependent and per-encryption variables + // + // We assume here that TAGLEN mod 128 == 0 (tagLength === 16). + const Nonce = concat(zeros_16.subarray(0, 15 - nonce.length), one, nonce); + const bottom = Nonce[15] & 0b111111; + Nonce[15] &= 0b11000000; + const Ktop = encipher(Nonce); + const Stretch = concat(Ktop, xor(Ktop.subarray(0, 8), Ktop.subarray(1, 9))); + // Offset_0 = Stretch[1+bottom..128+bottom] + const offset = shiftRight(Stretch.subarray(0 + (bottom >> 3), 17 + (bottom >> 3)), 8 - (bottom & 7)).subarray(1); + const checksum = zeros(16); - const C = new Uint8Array(plaintext.length + tagLength); + const C = new Uint8Array(plaintext.length + tagLength); - // - // Process any whole blocks - // - let i; - let pos = 0; - for (i = 0; i < m; i++) { - set_xor(offset, L[ntz(i + 1)]); - C.set(set_xor(encipher(xor(offset, plaintext)), offset), pos); - set_xor(checksum, plaintext); + // + // Process any whole blocks + // + let i; + let pos = 0; + for (i = 0; i < m; i++) { + set_xor(offset, L[ntz(i + 1)]); + C.set(set_xor(encipher(xor(offset, plaintext)), offset), pos); + set_xor(checksum, plaintext); - plaintext = plaintext.subarray(16); - pos += 16; + plaintext = plaintext.subarray(16); + pos += 16; + } + + // + // Process any final partial block and compute raw tag + // + if (plaintext.length) { + set_xor(offset, L.x); + const Pad = encipher(offset); + C.set(xor(plaintext, Pad), pos); + + // Checksum_* = Checksum_m xor (P_* || 1 || zeros(127-bitlen(P_*))) + const xorInput = zeros(16); + xorInput.set(plaintext, 0); + xorInput[plaintext.length] = 0b10000000; + set_xor(checksum, xorInput); + pos += plaintext.length; + } + const Tag = set_xor(encipher(set_xor(set_xor(checksum, offset), L.$)), hash(adata)); + + // + // Assemble ciphertext + // + C.set(Tag, pos); + return C; + }, + + + /** + * Decrypt ciphertext input. + * @param {Uint8Array} ciphertext The ciphertext input to be decrypted + * @param {Uint8Array} nonce The nonce (15 bytes) + * @param {Uint8Array} adata Associated data to verify + * @returns {Promise} The plaintext output + */ + decrypt: async function(ciphertext, nonce, adata) { + // + // Consider C as a sequence of 128-bit blocks + // + const T = ciphertext.subarray(ciphertext.length - tagLength); + ciphertext = ciphertext.subarray(0, ciphertext.length - tagLength); + const m = ciphertext.length >> 4; + + // + // Key-dependent variables + // + extendKeyVariables(ciphertext, adata); + const { encipher, decipher, L } = kv; + + // + // Nonce-dependent and per-encryption variables + // + // We assume here that TAGLEN mod 128 == 0 (tagLength === 16). + const Nonce = concat(zeros_16.subarray(0, 15 - nonce.length), one, nonce); + const bottom = Nonce[15] & 0b111111; + Nonce[15] &= 0b11000000; + const Ktop = encipher(Nonce); + const Stretch = concat(Ktop, xor(Ktop.subarray(0, 8), Ktop.subarray(1, 9))); + // Offset_0 = Stretch[1+bottom..128+bottom] + const offset = shiftRight(Stretch.subarray(0 + (bottom >> 3), 17 + (bottom >> 3)), 8 - (bottom & 7)).subarray(1); + const checksum = zeros(16); + + const P = new Uint8Array(ciphertext.length); + + // + // Process any whole blocks + // + let i; + let pos = 0; + for (i = 0; i < m; i++) { + set_xor(offset, L[ntz(i + 1)]); + P.set(set_xor(decipher(xor(offset, ciphertext)), offset), pos); + set_xor(checksum, P.subarray(pos)); + + ciphertext = ciphertext.subarray(16); + pos += 16; + } + + // + // Process any final partial block and compute raw tag + // + if (ciphertext.length) { + set_xor(offset, L.x); + const Pad = encipher(offset); + P.set(xor(ciphertext, Pad), pos); + + // Checksum_* = Checksum_m xor (P_* || 1 || zeros(127-bitlen(P_*))) + const xorInput = zeros(16); + xorInput.set(P.subarray(pos), 0); + xorInput[ciphertext.length] = 0b10000000; + set_xor(checksum, xorInput); + pos += ciphertext.length; + } + const Tag = set_xor(encipher(set_xor(set_xor(checksum, offset), L.$)), hash(adata)); + + // + // Check for validity and assemble plaintext + // + if (!util.equalsUint8Array(Tag, T)) { + throw new Error('Authentication tag mismatch in OCB ciphertext'); + } + return P; } - - // - // Process any final partial block and compute raw tag - // - if (plaintext.length) { - set_xor(offset, L.x); - const Pad = encipher(offset); - C.set(xor(plaintext, Pad), pos); - - // Checksum_* = Checksum_m xor (P_* || 1 || zeros(127-bitlen(P_*))) - const xorInput = zeros(16); - xorInput.set(plaintext, 0); - xorInput[plaintext.length] = 0b10000000; - set_xor(checksum, xorInput); - pos += plaintext.length; - } - const Tag = set_xor(encipher(set_xor(set_xor(checksum, offset), L.$)), this.hash(adata)); - - // - // Assemble ciphertext - // - C.set(Tag, pos); - return C; - } - - - /** - * Decrypt ciphertext input. - * @param {Uint8Array} ciphertext The ciphertext input to be decrypted - * @param {Uint8Array} nonce The nonce (15 bytes) - * @param {Uint8Array} adata Associated data to verify - * @returns {Promise} The plaintext output - */ - async decrypt(ciphertext, nonce, adata) { - // - // Consider C as a sequence of 128-bit blocks - // - const T = ciphertext.subarray(ciphertext.length - tagLength); - ciphertext = ciphertext.subarray(0, ciphertext.length - tagLength); - const m = ciphertext.length >> 4; - - // - // Key-dependent variables - // - this.extendKeyVariables(ciphertext, adata); - const { encipher, decipher, L } = this.kv; - - // - // Nonce-dependent and per-encryption variables - // - // We assume here that TAGLEN mod 128 == 0 (tagLength === 16). - const Nonce = concat(zeros_16.subarray(0, 15 - nonce.length), one, nonce); - const bottom = Nonce[15] & 0b111111; - Nonce[15] &= 0b11000000; - const Ktop = encipher(Nonce); - const Stretch = concat(Ktop, xor(Ktop.subarray(0, 8), Ktop.subarray(1, 9))); - // Offset_0 = Stretch[1+bottom..128+bottom] - const offset = shiftRight(Stretch.subarray(0 + (bottom >> 3), 17 + (bottom >> 3)), 8 - (bottom & 7)).subarray(1); - const checksum = zeros(16); - - const P = new Uint8Array(ciphertext.length); - - // - // Process any whole blocks - // - let i; - let pos = 0; - for (i = 0; i < m; i++) { - set_xor(offset, L[ntz(i + 1)]); - P.set(set_xor(decipher(xor(offset, ciphertext)), offset), pos); - set_xor(checksum, P.subarray(pos)); - - ciphertext = ciphertext.subarray(16); - pos += 16; - } - - // - // Process any final partial block and compute raw tag - // - if (ciphertext.length) { - set_xor(offset, L.x); - const Pad = encipher(offset); - P.set(xor(ciphertext, Pad), pos); - - // Checksum_* = Checksum_m xor (P_* || 1 || zeros(127-bitlen(P_*))) - const xorInput = zeros(16); - xorInput.set(P.subarray(pos), 0); - xorInput[ciphertext.length] = 0b10000000; - set_xor(checksum, xorInput); - pos += ciphertext.length; - } - const Tag = set_xor(encipher(set_xor(set_xor(checksum, offset), L.$)), this.hash(adata)); - - // - // Check for validity and assemble plaintext - // - if (!util.equalsUint8Array(Tag, T)) { - throw new Error('Authentication tag mismatch in OCB ciphertext'); - } - return P; - } + }; } diff --git a/src/packet/secret_key.js b/src/packet/secret_key.js index 59105443..491d60ae 100644 --- a/src/packet/secret_key.js +++ b/src/packet/secret_key.js @@ -211,7 +211,8 @@ SecretKey.prototype.encrypt = async function (passphrase) { arr = [new Uint8Array([253, optionalFields.length])]; arr.push(optionalFields); const mode = crypto[aead]; - const encrypted = await new mode(symmetric, key).encrypt(cleartext, iv.subarray(0, mode.ivLength), new Uint8Array()); + const modeInstance = await mode(symmetric, key); + const encrypted = await modeInstance.encrypt(cleartext, iv.subarray(0, mode.ivLength), new Uint8Array()); arr.push(util.writeNumber(encrypted.length, 4)); arr.push(encrypted); } else { @@ -305,7 +306,8 @@ SecretKey.prototype.decrypt = async function (passphrase) { if (aead) { const mode = crypto[aead]; try { - cleartext = await new mode(symmetric, key).decrypt(ciphertext, iv.subarray(0, mode.ivLength), new Uint8Array()); + const modeInstance = await mode(symmetric, key); + cleartext = await modeInstance.decrypt(ciphertext, iv.subarray(0, mode.ivLength), new Uint8Array()); } catch(err) { if (err.message.startsWith('Authentication tag mismatch')) { throw new Error('Incorrect key passphrase: ' + err.message); diff --git a/src/packet/sym_encrypted_aead_protected.js b/src/packet/sym_encrypted_aead_protected.js index fcd4c80d..eb31238a 100644 --- a/src/packet/sym_encrypted_aead_protected.js +++ b/src/packet/sym_encrypted_aead_protected.js @@ -107,7 +107,7 @@ SymEncryptedAEADProtected.prototype.decrypt = async function (sessionKeyAlgorith adataArray.set([0xC0 | this.tag, this.version, this.cipherAlgo, this.aeadAlgo, this.chunkSizeByte], 0); adataView.setInt32(13 + 4, data.length - mode.blockLength); // Should be setInt64(13, ...) const decryptedPromises = []; - const modeInstance = new mode(cipher, key); + const modeInstance = await mode(cipher, key); for (let chunkIndex = 0; chunkIndex === 0 || data.length;) { decryptedPromises.push( modeInstance.decrypt(data.subarray(0, chunkSize), mode.getNonce(this.iv, chunkIndexArray), adataArray) @@ -149,7 +149,7 @@ SymEncryptedAEADProtected.prototype.encrypt = async function (sessionKeyAlgorith adataArray.set([0xC0 | this.tag, this.version, this.cipherAlgo, this.aeadAlgo, this.chunkSizeByte], 0); adataView.setInt32(13 + 4, data.length); // Should be setInt64(13, ...) const encryptedPromises = []; - const modeInstance = new mode(sessionKeyAlgorithm, key); + const modeInstance = await mode(sessionKeyAlgorithm, key); for (let chunkIndex = 0; chunkIndex === 0 || data.length;) { encryptedPromises.push( modeInstance.encrypt(data.subarray(0, chunkSize), mode.getNonce(this.iv, chunkIndexArray), adataArray) diff --git a/src/packet/sym_encrypted_session_key.js b/src/packet/sym_encrypted_session_key.js index 39687f40..c0a26049 100644 --- a/src/packet/sym_encrypted_session_key.js +++ b/src/packet/sym_encrypted_session_key.js @@ -142,7 +142,8 @@ SymEncryptedSessionKey.prototype.decrypt = async function(passphrase) { if (this.version === 5) { const mode = crypto[this.aeadAlgorithm]; const adata = new Uint8Array([0xC0 | this.tag, this.version, enums.write(enums.symmetric, this.sessionKeyEncryptionAlgorithm), enums.write(enums.aead, this.aeadAlgorithm)]); - this.sessionKey = await new mode(algo, key).decrypt(this.encrypted, this.iv, adata); + const modeInstance = await mode(algo, key); + this.sessionKey = await modeInstance.decrypt(this.encrypted, this.iv, adata); } else if (this.encrypted !== null) { const decrypted = crypto.cfb.normalDecrypt(algo, key, this.encrypted, null); @@ -182,7 +183,8 @@ SymEncryptedSessionKey.prototype.encrypt = async function(passphrase) { const mode = crypto[this.aeadAlgorithm]; this.iv = await crypto.random.getRandomBytes(mode.ivLength); // generate new random IV const adata = new Uint8Array([0xC0 | this.tag, this.version, enums.write(enums.symmetric, this.sessionKeyEncryptionAlgorithm), enums.write(enums.aead, this.aeadAlgorithm)]); - this.encrypted = await new mode(algo, key).encrypt(this.sessionKey, this.iv, adata); + const modeInstance = await mode(algo, key); + this.encrypted = await modeInstance.encrypt(this.sessionKey, this.iv, adata); } else { const algo_enum = new Uint8Array([enums.write(enums.symmetric, this.sessionKeyAlgorithm)]); const private_key = util.concatUint8Array([algo_enum, this.sessionKey]); diff --git a/test/crypto/eax.js b/test/crypto/eax.js index c5aec8b9..3158428a 100644 --- a/test/crypto/eax.js +++ b/test/crypto/eax.js @@ -94,7 +94,7 @@ function testAESEAX() { headerBytes = openpgp.util.hex_to_Uint8Array(vec.header), ctBytes = openpgp.util.hex_to_Uint8Array(vec.ct); - const eax = new openpgp.crypto.eax(cipher, keyBytes); + const eax = await openpgp.crypto.eax(cipher, keyBytes); // encryption test let ct = await eax.encrypt(msgBytes, nonceBytes, headerBytes); diff --git a/test/crypto/ocb.js b/test/crypto/ocb.js index a1e269cb..290e8b88 100644 --- a/test/crypto/ocb.js +++ b/test/crypto/ocb.js @@ -122,7 +122,7 @@ describe('Symmetric AES-OCB', function() { headerBytes = openpgp.util.hex_to_Uint8Array(vec.A), ctBytes = openpgp.util.hex_to_Uint8Array(vec.C); - const ocb = new openpgp.crypto.ocb(cipher, keyBytes); + const ocb = await openpgp.crypto.ocb(cipher, keyBytes); // encryption test let ct = await ocb.encrypt(msgBytes, nonceBytes, headerBytes); @@ -162,7 +162,7 @@ describe('Symmetric AES-OCB', function() { const K = new Uint8Array(KEYLEN / 8); K[K.length - 1] = TAGLEN; - const ocb = new openpgp.crypto.ocb('aes' + KEYLEN, K); + const ocb = await openpgp.crypto.ocb('aes' + KEYLEN, K); const C = []; let N;