From 836ad2805ae62607789347f9a80f4f394698d88d Mon Sep 17 00:00:00 2001 From: Sanjana Rajan Date: Sun, 23 Dec 2018 18:42:24 +0100 Subject: [PATCH] Revert "Web Crypto CFB encryption" --- src/crypto/cfb.js | 318 +++++++++++++----- src/crypto/crypto.js | 10 +- src/packet/secret_key.js | 4 +- .../sym_encrypted_integrity_protected.js | 86 ++++- src/packet/sym_encrypted_session_key.js | 4 +- src/packet/symmetrically_encrypted.js | 13 +- 6 files changed, 318 insertions(+), 117 deletions(-) diff --git a/src/crypto/cfb.js b/src/crypto/cfb.js index 7504d232..41e871cb 100644 --- a/src/crypto/cfb.js +++ b/src/crypto/cfb.js @@ -18,68 +18,273 @@ */ /** - * @requires web-stream-tools * @requires crypto/cipher - * @requires util * @module crypto/cfb */ -import { AES_CFB } from 'asmcrypto.js/dist_es5/aes/cfb'; - -import stream from 'web-stream-tools'; import cipher from './cipher'; -import config from '../config'; -import util from '../util'; - -const webCrypto = util.getWebCrypto(); -const nodeCrypto = util.getNodeCrypto(); -const Buffer = util.getNodeBuffer(); export default { - encrypt: function(algo, key, plaintext, iv) { - if (algo.substr(0, 3) === 'aes') { - return aesEncrypt(algo, key, plaintext, iv); + + /** + * This function encrypts a given plaintext with the specified prefixrandom + * using the specified blockcipher + * @param {Uint8Array} prefixrandom random bytes of block_size length + * to be used in prefixing the data + * @param {String} cipherfn the algorithm cipher class to encrypt + * data in one block_size encryption, {@link module:crypto/cipher}. + * @param {Uint8Array} plaintext data to be encrypted + * @param {Uint8Array} key key to be used to encrypt the plaintext. + * This will be passed to the cipherfn + * @param {Boolean} resync a boolean value specifying if a resync of the + * IV should be used or not. The encrypteddatapacket uses the + * "old" style with a resync. Encryption within an + * encryptedintegrityprotecteddata packet is not resyncing the IV. + * @returns {Uint8Array} encrypted data + */ + encrypt: function(prefixrandom, cipherfn, plaintext, key, resync) { + cipherfn = new cipher[cipherfn](key); + const block_size = cipherfn.blockSize; + + const FR = new Uint8Array(block_size); + let FRE = new Uint8Array(block_size); + + const new_prefix = new Uint8Array(prefixrandom.length + 2); + new_prefix.set(prefixrandom); + new_prefix[prefixrandom.length] = prefixrandom[block_size-2]; + new_prefix[prefixrandom.length+1] = prefixrandom[block_size-1]; + prefixrandom = new_prefix; + + let ciphertext = new Uint8Array(plaintext.length + 2 + block_size * 2); + let i; + let n; + let begin; + const offset = resync ? 0 : 2; + + // 1. The feedback register (FR) is set to the IV, which is all zeros. + for (i = 0; i < block_size; i++) { + FR[i] = 0; } - const cipherfn = new cipher[algo](key); + // 2. FR is encrypted to produce FRE (FR Encrypted). This is the + // encryption of an all-zero value. + FRE = cipherfn.encrypt(FR); + // 3. FRE is xored with the first BS octets of random data prefixed to + // the plaintext to produce C[1] through C[BS], the first BS octets + // of ciphertext. + for (i = 0; i < block_size; i++) { + ciphertext[i] = FRE[i] ^ prefixrandom[i]; + } + + // 4. FR is loaded with C[1] through C[BS]. + FR.set(ciphertext.subarray(0, block_size)); + + // 5. FR is encrypted to produce FRE, the encryption of the first BS + // octets of ciphertext. + FRE = cipherfn.encrypt(FR); + + // 6. The left two octets of FRE get xored with the next two octets of + // data that were prefixed to the plaintext. This produces C[BS+1] + // and C[BS+2], the next two octets of ciphertext. + ciphertext[block_size] = FRE[0] ^ prefixrandom[block_size]; + ciphertext[block_size + 1] = FRE[1] ^ prefixrandom[block_size + 1]; + + if (resync) { + // 7. (The resync step) FR is loaded with C[3] through C[BS+2]. + FR.set(ciphertext.subarray(2, block_size + 2)); + } else { + FR.set(ciphertext.subarray(0, block_size)); + } + // 8. FR is encrypted to produce FRE. + FRE = cipherfn.encrypt(FR); + + // 9. FRE is xored with the first BS octets of the given plaintext, now + // that we have finished encrypting the BS+2 octets of prefixed + // data. This produces C[BS+3] through C[BS+(BS+2)], the next BS + // octets of ciphertext. + for (i = 0; i < block_size; i++) { + ciphertext[block_size + 2 + i] = FRE[i + offset] ^ plaintext[i]; + } + for (n = block_size; n < plaintext.length + offset; n += block_size) { + // 10. FR is loaded with C[BS+3] to C[BS + (BS+2)] (which is C11-C18 for + // an 8-octet block). + begin = n + 2 - offset; + FR.set(ciphertext.subarray(begin, begin + block_size)); + + // 11. FR is encrypted to produce FRE. + FRE = cipherfn.encrypt(FR); + + // 12. FRE is xored with the next BS octets of plaintext, to produce + // the next BS octets of ciphertext. These are loaded into FR, and + // the process is repeated until the plaintext is used up. + for (i = 0; i < block_size; i++) { + ciphertext[block_size + begin + i] = FRE[i] ^ plaintext[n + i - offset]; + } + } + + ciphertext = ciphertext.subarray(0, plaintext.length + 2 + block_size); + return ciphertext; + }, + + /** + * Decrypts the prefixed data for the Modification Detection Code (MDC) computation + * @param {String} cipherfn.encrypt Cipher function to use, + * @see module:crypto/cipher. + * @param {Uint8Array} key Uint8Array representation of key to be used to check the mdc + * This will be passed to the cipherfn + * @param {Uint8Array} ciphertext The encrypted data + * @returns {Uint8Array} plaintext Data of D(ciphertext) with blocksize length +2 + */ + mdc: function(cipherfn, key, ciphertext) { + cipherfn = new cipher[cipherfn](key); + const block_size = cipherfn.blockSize; + + let iblock = new Uint8Array(block_size); + let ablock = new Uint8Array(block_size); + let i; + + + // initialisation vector + for (i = 0; i < block_size; i++) { + iblock[i] = 0; + } + + iblock = cipherfn.encrypt(iblock); + for (i = 0; i < block_size; i++) { + ablock[i] = ciphertext[i]; + iblock[i] ^= ablock[i]; + } + + ablock = cipherfn.encrypt(ablock); + + const result = new Uint8Array(iblock.length + 2); + result.set(iblock); + result[iblock.length] = ablock[0] ^ ciphertext[block_size]; + result[iblock.length + 1] = ablock[1] ^ ciphertext[block_size + 1]; + return result; + }, + + /** + * This function decrypts a given ciphertext using the specified blockcipher + * @param {String} cipherfn the algorithm cipher class to decrypt + * data in one block_size encryption, {@link module:crypto/cipher}. + * @param {Uint8Array} key Uint8Array representation of key to be used to decrypt the ciphertext. + * This will be passed to the cipherfn + * @param {Uint8Array} ciphertext to be decrypted + * @param {Boolean} resync a boolean value specifying if a resync of the + * IV should be used or not. The encrypteddatapacket uses the + * "old" style with a resync. Decryption within an + * encryptedintegrityprotecteddata packet is not resyncing the IV. + * @returns {Uint8Array} the plaintext data + */ + decrypt: function(cipherfn, key, ciphertext, resync) { + cipherfn = new cipher[cipherfn](key); + const block_size = cipherfn.blockSize; + + const iblock = new Uint8Array(block_size); + let ablock = new Uint8Array(block_size); + + let i; + let j; + let n; + let text = new Uint8Array(ciphertext.length - block_size); + + /* RFC4880: Tag 18 and Resync: + * [...] Unlike the Symmetrically Encrypted Data Packet, no + * special CFB resynchronization is done after encrypting this prefix + * data. See "OpenPGP CFB Mode" below for more details. + */ + + j = 0; + if (resync) { + for (i = 0; i < block_size; i++) { + iblock[i] = ciphertext[i + 2]; + } + for (n = block_size + 2; n < ciphertext.length; n += block_size) { + ablock = cipherfn.encrypt(iblock); + + for (i = 0; i < block_size && i + n < ciphertext.length; i++) { + iblock[i] = ciphertext[n + i]; + if (j < text.length) { + text[j] = ablock[i] ^ iblock[i]; + j++; + } + } + } + } else { + for (i = 0; i < block_size; i++) { + iblock[i] = ciphertext[i]; + } + for (n = block_size; n < ciphertext.length; n += block_size) { + ablock = cipherfn.encrypt(iblock); + for (i = 0; i < block_size && i + n < ciphertext.length; i++) { + iblock[i] = ciphertext[n + i]; + if (j < text.length) { + text[j] = ablock[i] ^ iblock[i]; + j++; + } + } + } + } + + n = resync ? 0 : 2; + + text = text.subarray(n, ciphertext.length - block_size - 2 + n); + + return text; + }, + + normalEncrypt: function(cipherfn, key, plaintext, iv) { + cipherfn = new cipher[cipherfn](key); const block_size = cipherfn.blockSize; let blocki = new Uint8Array(block_size); - const blockc = iv; + const blockc = new Uint8Array(block_size); let pos = 0; - const ciphertext = new Uint8Array(plaintext.length); + const cyphertext = new Uint8Array(plaintext.length); let i; let j = 0; + if (iv === null) { + for (i = 0; i < block_size; i++) { + blockc[i] = 0; + } + } else { + for (i = 0; i < block_size; i++) { + blockc[i] = iv[i]; + } + } while (plaintext.length > block_size * pos) { const encblock = cipherfn.encrypt(blockc); blocki = plaintext.subarray((pos * block_size), (pos * block_size) + block_size); for (i = 0; i < blocki.length; i++) { blockc[i] = blocki[i] ^ encblock[i]; - ciphertext[j++] = blockc[i]; + cyphertext[j++] = blockc[i]; } pos++; } - return ciphertext; + return cyphertext; }, - decrypt: async function(algo, key, ciphertext, iv) { - if (algo.substr(0, 3) === 'aes') { - return aesDecrypt(algo, key, ciphertext, iv); - } - - ciphertext = await stream.readToEnd(ciphertext); - - const cipherfn = new cipher[algo](key); + normalDecrypt: function(cipherfn, key, ciphertext, iv) { + cipherfn = new cipher[cipherfn](key); const block_size = cipherfn.blockSize; - let blockp = iv; + let blockp; let pos = 0; const plaintext = new Uint8Array(ciphertext.length); const offset = 0; let i; let j = 0; + if (iv === null) { + blockp = new Uint8Array(block_size); + for (i = 0; i < block_size; i++) { + blockp[i] = 0; + } + } else { + blockp = iv.subarray(0, block_size); + } while (ciphertext.length > (block_size * pos)) { const decblock = cipherfn.encrypt(blockp); blockp = ciphertext.subarray((pos * (block_size)) + offset, (pos * (block_size)) + (block_size) + offset); @@ -92,60 +297,3 @@ export default { return plaintext; } }; - -function aesEncrypt(algo, key, pt, iv) { - if ( - util.getWebCrypto() && - key.length !== 24 && // Chrome doesn't support 192 bit keys, see https://www.chromium.org/blink/webcrypto#TOC-AES-support - !util.isStream(pt) && - pt.length >= 3000 * config.min_bytes_for_web_crypto // Default to a 3MB minimum. Chrome is pretty slow for small messages, see: https://bugs.chromium.org/p/chromium/issues/detail?id=701188#c2 - ) { // Web Crypto - return webEncrypt(algo, key, pt, iv); - } - if (nodeCrypto) { // Node crypto library. - return nodeEncrypt(algo, key, pt, iv); - } // asm.js fallback - const cfb = new AES_CFB(key); - return stream.transform(pt, value => cfb.AES_Encrypt_process(value), () => cfb.AES_Encrypt_finish()); -} - -function aesDecrypt(algo, key, ct, iv) { - if (nodeCrypto) { // Node crypto library. - return nodeDecrypt(algo, key, ct, iv); - } - if (util.isStream(ct)) { - const cfb = new AES_CFB(key); - return stream.transform(ct, value => cfb.AES_Decrypt_process(value), () => cfb.AES_Decrypt_finish()); - } - return AES_CFB.decrypt(ct, key, iv); -} - -function xorMut(a, b) { - for (let i = 0; i < a.length; i++) { - a[i] = a[i] ^ b[i]; - } -} - -async function webEncrypt(algo, key, pt, iv) { - const ALGO = 'AES-CBC'; - const _key = await webCrypto.importKey('raw', key, { name: ALGO }, false, ['encrypt']); - const { blockSize } = cipher[algo]; - const cbc_pt = util.concatUint8Array([new Uint8Array(blockSize), pt]); - const ct = new Uint8Array(await webCrypto.encrypt({ name: ALGO, iv }, _key, cbc_pt)).subarray(0, pt.length); - xorMut(ct, pt); - return ct; -} - -function nodeEncrypt(algo, key, pt, iv) { - key = new Buffer(key); - iv = new Buffer(iv); - const cipherObj = new nodeCrypto.createCipheriv('aes-' + algo.substr(3, 3) + '-cfb', key, iv); - return stream.transform(pt, value => new Uint8Array(cipherObj.update(new Buffer(value)))); -} - -function nodeDecrypt(algo, key, ct, iv) { - key = new Buffer(key); - iv = new Buffer(iv); - const decipherObj = new nodeCrypto.createDecipheriv('aes-' + algo.substr(3, 3) + '-cfb', key, iv); - return stream.transform(ct, value => new Uint8Array(decipherObj.update(new Buffer(value)))); -} diff --git a/src/crypto/crypto.js b/src/crypto/crypto.js index 38d8e8f7..c3692837 100644 --- a/src/crypto/crypto.js +++ b/src/crypto/crypto.js @@ -28,7 +28,6 @@ * @requires type/mpi * @requires type/oid * @requires enums - * @requires util * @module crypto/crypto */ @@ -40,7 +39,6 @@ import type_kdf_params from '../type/kdf_params'; import type_mpi from '../type/mpi'; import type_oid from '../type/oid'; import enums from '../enums'; -import util from '../util'; function constructParams(types, data) { return types.map(function(type, i) { @@ -293,13 +291,11 @@ export default { * Generates a random byte prefix for the specified algorithm * See {@link https://tools.ietf.org/html/rfc4880#section-9.2|RFC 4880 9.2} for algorithms. * @param {module:enums.symmetric} algo Symmetric encryption algorithm - * @returns {Uint8Array} Random bytes with length equal to the block size of the cipher, plus the last two bytes repeated. + * @returns {Uint8Array} Random bytes with length equal to the block size of the cipher * @async */ - getPrefixRandom: async function(algo) { - const prefixrandom = await random.getRandomBytes(cipher[algo].blockSize); - const repeat = new Uint8Array([prefixrandom[prefixrandom.length - 2], prefixrandom[prefixrandom.length - 1]]); - return util.concat([prefixrandom, repeat]); + getPrefixRandom: function(algo) { + return random.getRandomBytes(cipher[algo].blockSize); }, /** diff --git a/src/packet/secret_key.js b/src/packet/secret_key.js index 13f660f1..c335114d 100644 --- a/src/packet/secret_key.js +++ b/src/packet/secret_key.js @@ -195,7 +195,7 @@ SecretKey.prototype.encrypt = async function (passphrase) { arr = [new Uint8Array([254, enums.write(enums.symmetric, symmetric)])]; arr.push(s2k.write()); arr.push(iv); - arr.push(crypto.cfb.encrypt(symmetric, key, util.concatUint8Array([ + arr.push(crypto.cfb.normalEncrypt(symmetric, key, util.concatUint8Array([ cleartext, await crypto.hash.sha1(cleartext) ]), iv)); @@ -293,7 +293,7 @@ SecretKey.prototype.decrypt = async function (passphrase) { } } } else { - const cleartextWithHash = await crypto.cfb.decrypt(symmetric, key, ciphertext, iv); + const cleartextWithHash = crypto.cfb.normalDecrypt(symmetric, key, ciphertext, iv); let hash; let hashlen; diff --git a/src/packet/sym_encrypted_integrity_protected.js b/src/packet/sym_encrypted_integrity_protected.js index a2c4e66b..4362ee5d 100644 --- a/src/packet/sym_encrypted_integrity_protected.js +++ b/src/packet/sym_encrypted_integrity_protected.js @@ -24,12 +24,17 @@ * @requires util */ +import { AES_CFB } from 'asmcrypto.js/dist_es5/aes/cfb'; + import stream from 'web-stream-tools'; import config from '../config'; import crypto from '../crypto'; import enums from '../enums'; import util from '../util'; +const nodeCrypto = util.getNodeCrypto(); +const Buffer = util.getNodeBuffer(); + const VERSION = 1; // A one-octet version number of the data packet. /** @@ -89,14 +94,22 @@ SymEncryptedIntegrityProtected.prototype.write = function () { SymEncryptedIntegrityProtected.prototype.encrypt = async function (sessionKeyAlgorithm, key, streaming) { let bytes = this.packets.write(); if (!streaming) bytes = await stream.readToEnd(bytes); - const prefix = await crypto.getPrefixRandom(sessionKeyAlgorithm); + const prefixrandom = await crypto.getPrefixRandom(sessionKeyAlgorithm); + const repeat = new Uint8Array([prefixrandom[prefixrandom.length - 2], prefixrandom[prefixrandom.length - 1]]); + const prefix = util.concat([prefixrandom, repeat]); const mdc = new Uint8Array([0xD3, 0x14]); // modification detection code packet - const tohash = util.concat([prefix, bytes, mdc]); - const hash = await crypto.hash.sha1(stream.passiveClone(tohash)); - const plaintext = util.concat([tohash, hash]); + let tohash = util.concat([bytes, mdc]); + const hash = await crypto.hash.sha1(util.concat([prefix, stream.passiveClone(tohash)])); + tohash = util.concat([tohash, hash]); - this.encrypted = await crypto.cfb.encrypt(sessionKeyAlgorithm, key, plaintext, new Uint8Array(crypto.cipher[sessionKeyAlgorithm].blockSize)); + if (sessionKeyAlgorithm.substr(0, 3) === 'aes') { // AES optimizations. Native code for node, asmCrypto for browser. + this.encrypted = aesEncrypt(sessionKeyAlgorithm, util.concat([prefix, tohash]), key); + } else { + tohash = await stream.readToEnd(tohash); + this.encrypted = crypto.cfb.encrypt(prefixrandom, sessionKeyAlgorithm, tohash, key, false); + this.encrypted = stream.slice(this.encrypted, 0, prefix.length + tohash.length); + } return true; }; @@ -111,14 +124,23 @@ SymEncryptedIntegrityProtected.prototype.encrypt = async function (sessionKeyAlg SymEncryptedIntegrityProtected.prototype.decrypt = async function (sessionKeyAlgorithm, key, streaming) { if (!streaming) this.encrypted = await stream.readToEnd(this.encrypted); const encrypted = stream.clone(this.encrypted); - const decrypted = await crypto.cfb.decrypt(sessionKeyAlgorithm, key, encrypted, new Uint8Array(crypto.cipher[sessionKeyAlgorithm].blockSize)); + const encryptedClone = stream.passiveClone(encrypted); + let decrypted; + if (sessionKeyAlgorithm.substr(0, 3) === 'aes') { // AES optimizations. Native code for node, asmCrypto for browser. + decrypted = aesDecrypt(sessionKeyAlgorithm, encrypted, key, streaming); + } else { + decrypted = crypto.cfb.decrypt(sessionKeyAlgorithm, key, await stream.readToEnd(encrypted), false); + } // there must be a modification detection code packet as the // last packet and everything gets hashed except the hash itself + const encryptedPrefix = await stream.readToEnd(stream.slice(encryptedClone, 0, crypto.cipher[sessionKeyAlgorithm].blockSize + 2)); + const prefix = crypto.cfb.mdc(sessionKeyAlgorithm, key, encryptedPrefix); const realHash = stream.slice(stream.passiveClone(decrypted), -20); - const tohash = stream.slice(decrypted, 0, -20); + const bytes = stream.slice(decrypted, 0, -20); + const tohash = util.concat([prefix, stream.passiveClone(bytes)]); const verifyHash = Promise.all([ - stream.readToEnd(await crypto.hash.sha1(stream.passiveClone(tohash))), + stream.readToEnd(await crypto.hash.sha1(tohash)), stream.readToEnd(realHash) ]).then(([hash, mdc]) => { if (!util.equalsUint8Array(hash, mdc)) { @@ -126,8 +148,7 @@ SymEncryptedIntegrityProtected.prototype.decrypt = async function (sessionKeyAlg } return new Uint8Array(); }); - const bytes = stream.slice(tohash, crypto.cipher[sessionKeyAlgorithm].blockSize + 2); // Remove random prefix - let packetbytes = stream.slice(bytes, 0, -2); // Remove MDC packet + let packetbytes = stream.slice(bytes, 0, -2); packetbytes = stream.concat([packetbytes, stream.fromAsync(() => verifyHash)]); if (!util.isStream(encrypted) || !config.allow_unauthenticated_stream) { packetbytes = await stream.readToEnd(packetbytes); @@ -137,3 +158,48 @@ SymEncryptedIntegrityProtected.prototype.decrypt = async function (sessionKeyAlg }; export default SymEncryptedIntegrityProtected; + + +////////////////////////// +// // +// Helper functions // +// // +////////////////////////// + + +function aesEncrypt(algo, pt, key) { + if (nodeCrypto) { // Node crypto library. + return nodeEncrypt(algo, pt, key); + } // asm.js fallback + const cfb = new AES_CFB(key); + return stream.transform(pt, value => cfb.AES_Encrypt_process(value), () => cfb.AES_Encrypt_finish()); +} + +function aesDecrypt(algo, ct, key) { + let pt; + if (nodeCrypto) { // Node crypto library. + pt = nodeDecrypt(algo, ct, key); + } else { // asm.js fallback + if (util.isStream(ct)) { + const cfb = new AES_CFB(key); + pt = stream.transform(ct, value => cfb.AES_Decrypt_process(value), () => cfb.AES_Decrypt_finish()); + } else { + pt = AES_CFB.decrypt(ct, key); + } + } + return stream.slice(pt, crypto.cipher[algo].blockSize + 2); // Remove random prefix +} + +function nodeEncrypt(algo, pt, key) { + key = new Buffer(key); + const iv = new Buffer(new Uint8Array(crypto.cipher[algo].blockSize)); + const cipherObj = new nodeCrypto.createCipheriv('aes-' + algo.substr(3, 3) + '-cfb', key, iv); + return stream.transform(pt, value => new Uint8Array(cipherObj.update(new Buffer(value)))); +} + +function nodeDecrypt(algo, ct, key) { + key = new Buffer(key); + const iv = new Buffer(new Uint8Array(crypto.cipher[algo].blockSize)); + const decipherObj = new nodeCrypto.createDecipheriv('aes-' + algo.substr(3, 3) + '-cfb', key, iv); + return stream.transform(ct, value => new Uint8Array(decipherObj.update(new Buffer(value)))); +} diff --git a/src/packet/sym_encrypted_session_key.js b/src/packet/sym_encrypted_session_key.js index a526c3f5..b371f0e9 100644 --- a/src/packet/sym_encrypted_session_key.js +++ b/src/packet/sym_encrypted_session_key.js @@ -145,7 +145,7 @@ SymEncryptedSessionKey.prototype.decrypt = async function(passphrase) { const modeInstance = await mode(algo, key); this.sessionKey = await modeInstance.decrypt(this.encrypted, this.iv, adata); } else if (this.encrypted !== null) { - const decrypted = await crypto.cfb.decrypt(algo, key, this.encrypted, new Uint8Array(crypto.cipher[algo].blockSize)); + const decrypted = crypto.cfb.normalDecrypt(algo, key, this.encrypted, null); this.sessionKeyAlgorithm = enums.read(enums.symmetric, decrypted[0]); this.sessionKey = decrypted.subarray(1, decrypted.length); @@ -188,7 +188,7 @@ SymEncryptedSessionKey.prototype.encrypt = async function(passphrase) { } else { const algo_enum = new Uint8Array([enums.write(enums.symmetric, this.sessionKeyAlgorithm)]); const private_key = util.concatUint8Array([algo_enum, this.sessionKey]); - this.encrypted = await crypto.cfb.encrypt(algo, key, private_key, new Uint8Array(crypto.cipher[algo].blockSize)); + this.encrypted = crypto.cfb.normalEncrypt(algo, key, private_key, null); } return true; diff --git a/src/packet/symmetrically_encrypted.js b/src/packet/symmetrically_encrypted.js index b178ecb3..da730b19 100644 --- a/src/packet/symmetrically_encrypted.js +++ b/src/packet/symmetrically_encrypted.js @@ -20,14 +20,12 @@ * @requires config * @requires crypto * @requires enums - * @requires util */ import stream from 'web-stream-tools'; import config from '../config'; import crypto from '../crypto'; import enums from '../enums'; -import util from '../util'; /** * Implementation of the Symmetrically Encrypted Data Packet (Tag 9) @@ -81,11 +79,7 @@ SymmetricallyEncrypted.prototype.write = function () { */ SymmetricallyEncrypted.prototype.decrypt = async function (sessionKeyAlgorithm, key) { this.encrypted = await stream.readToEnd(this.encrypted); - const decrypted = await crypto.cfb.decrypt(sessionKeyAlgorithm, key, - this.encrypted.subarray(crypto.cipher[sessionKeyAlgorithm].blockSize + 2), - this.encrypted.subarray(2, crypto.cipher[sessionKeyAlgorithm].blockSize + 2) - ); - + const decrypted = crypto.cfb.decrypt(sessionKeyAlgorithm, key, this.encrypted, true); // If MDC errors are not being ignored, all missing MDC packets in symmetrically encrypted data should throw an error if (!this.ignore_mdc_error) { throw new Error('Decryption failed due to missing MDC.'); @@ -106,10 +100,7 @@ SymmetricallyEncrypted.prototype.decrypt = async function (sessionKeyAlgorithm, SymmetricallyEncrypted.prototype.encrypt = async function (algo, key) { const data = this.packets.write(); - const prefix = await crypto.getPrefixRandom(algo); - const FRE = await crypto.cfb.encrypt(algo, key, prefix, new Uint8Array(crypto.cipher[algo].blockSize)); - const ciphertext = await crypto.cfb.encrypt(algo, key, data, FRE.subarray(2)); - this.encrypted = util.concatUint8Array([FRE, ciphertext]); + this.encrypted = crypto.cfb.encrypt(await crypto.getPrefixRandom(algo), algo, await stream.readToEnd(data), key, true); return true; };