diff --git a/src/cleartext.js b/src/cleartext.js index 8069051a..51d8b78a 100644 --- a/src/cleartext.js +++ b/src/cleartext.js @@ -71,7 +71,7 @@ export class CleartextMessage { async sign(privateKeys, signature = null, signingKeyIDs = [], date = new Date(), userIDs = [], config = defaultConfig) { const literalDataPacket = new LiteralDataPacket(); literalDataPacket.setText(this.text); - const newSignature = new Signature(await createSignaturePackets(literalDataPacket, privateKeys, signature, signingKeyIDs, date, userIDs, true, undefined, config)); + const newSignature = new Signature(await createSignaturePackets(literalDataPacket, privateKeys, signature, signingKeyIDs, date, userIDs, true, config)); return new CleartextMessage(this.text, newSignature); } @@ -90,7 +90,7 @@ export class CleartextMessage { const literalDataPacket = new LiteralDataPacket(); // we assume that cleartext signature is generated based on UTF8 cleartext literalDataPacket.setText(this.text); - return createVerificationObjects(signatureList, [literalDataPacket], keys, date, true, undefined, config); + return createVerificationObjects(signatureList, [literalDataPacket], keys, date, true, config); } /** diff --git a/src/crypto/hash/index.js b/src/crypto/hash/index.js index 1065665b..2e9e4855 100644 --- a/src/crypto/hash/index.js +++ b/src/crypto/hash/index.js @@ -32,6 +32,9 @@ function nodeHash(type) { function hashjsHash(hash, webCryptoHash) { return async function(data, config = defaultConfig) { + if (stream.isArrayStream(data)) { + data = await stream.readToEnd(data); + } if (!util.isStream(data) && webCrypto && webCryptoHash && data.length >= config.minBytesForWebCrypto) { return new Uint8Array(await webCrypto.digest(webCryptoHash, data)); } @@ -44,6 +47,9 @@ function hashjsHash(hash, webCryptoHash) { function asmcryptoHash(hash, webCryptoHash) { return async function(data, config = defaultConfig) { + if (stream.isArrayStream(data)) { + data = await stream.readToEnd(data); + } if (util.isStream(data)) { const hashInstance = new hash(); return stream.transform(data, value => { diff --git a/src/key/factory.js b/src/key/factory.js index a1e0b65c..8ea967f4 100644 --- a/src/key/factory.js +++ b/src/key/factory.js @@ -233,7 +233,7 @@ async function wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options, conf signatureType: enums.signature.keyRevocation, reasonForRevocationFlag: enums.reasonForRevocation.noReason, reasonForRevocationString: '' - }, options.date, undefined, undefined, undefined, config)); + }, options.date, undefined, undefined, config)); // set passphrase protection if (options.passphrase) { diff --git a/src/key/helper.js b/src/key/helper.js index 9d770d37..b3e0d956 100644 --- a/src/key/helper.js +++ b/src/key/helper.js @@ -51,7 +51,7 @@ export async function getLatestValidSignature(signatures, primaryKey, signatureT !signatures[i].isExpired(date) ) { // check binding signature is verified - signatures[i].verified || await signatures[i].verify(primaryKey, signatureType, dataToVerify, undefined, undefined, config); + signatures[i].verified || await signatures[i].verify(primaryKey, signatureType, dataToVerify, undefined, config); signature = signatures[i]; } } catch (e) { @@ -97,7 +97,7 @@ export async function createBindingSignature(subkey, primaryKey, options, config subkeySignaturePacket.keyFlags = [enums.keyFlags.signData]; subkeySignaturePacket.embeddedSignature = await createSignaturePacket(dataToSign, null, subkey, { signatureType: enums.signature.keyBinding - }, options.date, undefined, undefined, undefined, config); + }, options.date, undefined, undefined, config); } else { subkeySignaturePacket.keyFlags = [enums.keyFlags.encryptCommunication | enums.keyFlags.encryptStorage]; } @@ -193,12 +193,11 @@ export async function getPreferredAlgo(type, keys = [], date = new Date(), userI * @param {Date} [date] - Override the creationtime of the signature * @param {Object} [userID] - User ID * @param {Object} [detached] - Whether to create a detached signature packet - * @param {Boolean} [streaming] - Whether to process data as a stream * @param {Object} config - full configuration * @returns {SignaturePacket} Signature packet. * @async */ -export async function createSignaturePacket(dataToSign, privateKey, signingKeyPacket, signatureProperties, date, userID, detached = false, streaming = false, config) { +export async function createSignaturePacket(dataToSign, privateKey, signingKeyPacket, signatureProperties, date, userID, detached = false, config) { if (signingKeyPacket.isDummy()) { throw new Error('Cannot sign with a gnu-dummy key.'); } @@ -209,7 +208,7 @@ export async function createSignaturePacket(dataToSign, privateKey, signingKeyPa Object.assign(signaturePacket, signatureProperties); signaturePacket.publicKeyAlgorithm = signingKeyPacket.algorithm; signaturePacket.hashAlgorithm = await getPreferredHashAlgo(privateKey, signingKeyPacket, date, userID, config); - await signaturePacket.sign(signingKeyPacket, dataToSign, detached, streaming); + await signaturePacket.sign(signingKeyPacket, dataToSign, detached); return signaturePacket; } @@ -272,7 +271,7 @@ export async function isDataRevoked(primaryKey, signatureType, dataToVerify, rev (!signature || revocationSignature.issuerKeyID.equals(signature.issuerKeyID)) && !(config.revocationsExpire && revocationSignature.isExpired(normDate)) ) { - revocationSignature.verified || await revocationSignature.verify(key, signatureType, dataToVerify, undefined, undefined, config); + revocationSignature.verified || await revocationSignature.verify(key, signatureType, dataToVerify, undefined, config); // TODO get an identifier of the revoked object instead revocationKeyIDs.push(revocationSignature.issuerKeyID); diff --git a/src/key/key.js b/src/key/key.js index b9f7e413..e1cade1d 100644 --- a/src/key/key.js +++ b/src/key/key.js @@ -768,7 +768,7 @@ class Key { signatureType: enums.signature.keyRevocation, reasonForRevocationFlag: enums.write(enums.reasonForRevocation, reasonForRevocationFlag), reasonForRevocationString - }, date, undefined, undefined, undefined, config)); + }, date, undefined, undefined, config)); return key; } @@ -812,7 +812,7 @@ class Key { throw new Error('Revocation signature is expired'); } try { - await revocationSignature.verify(this.keyPacket, enums.signature.keyRevocation, { key: this.keyPacket }, undefined, undefined, config); + await revocationSignature.verify(this.keyPacket, enums.signature.keyRevocation, { key: this.keyPacket }, undefined, config); } catch (e) { throw util.wrapError('Could not verify revocation signature', e); } diff --git a/src/key/subkey.js b/src/key/subkey.js index 10fd62b4..2029fd5d 100644 --- a/src/key/subkey.js +++ b/src/key/subkey.js @@ -142,7 +142,7 @@ class SubKey { } } try { - srcBindSig.verified || await srcBindSig.verify(primaryKey, enums.signature.subkeyBinding, dataToVerify, undefined, undefined, config); + srcBindSig.verified || await srcBindSig.verify(primaryKey, enums.signature.subkeyBinding, dataToVerify, undefined, config); return true; } catch (e) { return false; @@ -180,7 +180,7 @@ class SubKey { signatureType: enums.signature.subkeyRevocation, reasonForRevocationFlag: enums.write(enums.reasonForRevocation, reasonForRevocationFlag), reasonForRevocationString - }, date, undefined, undefined, undefined, config)); + }, date, undefined, undefined, config)); await subKey.update(this, primaryKey); return subKey; } diff --git a/src/key/user.js b/src/key/user.js index 544e80c6..7e3325a1 100644 --- a/src/key/user.js +++ b/src/key/user.js @@ -64,7 +64,7 @@ class User { // Most OpenPGP implementations use generic certification (0x10) signatureType: enums.signature.certGeneric, keyFlags: [enums.keyFlags.certifyKeys | enums.keyFlags.signData] - }, undefined, undefined, undefined, undefined, config); + }, undefined, undefined, undefined, config); })); await user.update(this, primaryKey); return user; @@ -122,7 +122,7 @@ class User { throw new Error('User certificate is revoked'); } try { - certificate.verified || await certificate.verify(signingKey.keyPacket, enums.signature.certGeneric, dataToVerify, undefined, undefined, config); + certificate.verified || await certificate.verify(signingKey.keyPacket, enums.signature.certGeneric, dataToVerify, undefined, config); } catch (e) { throw util.wrapError('User certificate is invalid', e); } @@ -186,7 +186,7 @@ class User { throw new Error('Self-certification is revoked'); } try { - selfCertification.verified || await selfCertification.verify(primaryKey, enums.signature.certGeneric, dataToVerify, undefined, undefined, config); + selfCertification.verified || await selfCertification.verify(primaryKey, enums.signature.certGeneric, dataToVerify, undefined, config); } catch (e) { throw util.wrapError('Self-certification is invalid', e); } @@ -219,7 +219,7 @@ class User { // self signatures await mergeSignatures(user, this, 'selfCertifications', async function(srcSelfSig) { try { - srcSelfSig.verified || await srcSelfSig.verify(primaryKey, enums.signature.certGeneric, dataToVerify, undefined, undefined, config); + srcSelfSig.verified || await srcSelfSig.verify(primaryKey, enums.signature.certGeneric, dataToVerify, undefined, config); return true; } catch (e) { return false; diff --git a/src/message.js b/src/message.js index 6b958c46..12c26957 100644 --- a/src/message.js +++ b/src/message.js @@ -107,12 +107,11 @@ export class Message { * @param {Array} [privateKeys] - Private keys with decrypted secret data * @param {Array} [passwords] - Passwords used to decrypt * @param {Array} [sessionKeys] - Session keys in the form: { data:Uint8Array, algorithm:String, [aeadAlgorithm:String] } - * @param {Boolean} [streaming] - Whether to process data as a stream * @param {Object} [config] - Full configuration, defaults to openpgp.config * @returns {Message} New message with decrypted content. * @async */ - async decrypt(privateKeys, passwords, sessionKeys, streaming, config = defaultConfig) { + async decrypt(privateKeys, passwords, sessionKeys, config = defaultConfig) { const keyObjs = sessionKeys || await this.decryptSessionKeys(privateKeys, passwords, config); const symEncryptedPacketlist = this.packets.filterByTag( @@ -133,7 +132,7 @@ export class Message { } try { - await symEncryptedPacket.decrypt(keyObj.algorithm, keyObj.data, streaming, config); + await symEncryptedPacket.decrypt(keyObj.algorithm, keyObj.data, config); } catch (e) { util.printDebugError(e); exception = e; @@ -317,12 +316,11 @@ export class Message { * @param {Array} [encryptionKeyIDs] - Array of key IDs to use for encryption. Each encryptionKeyIDs[i] corresponds to publicKeys[i] * @param {Date} [date] - Override the creation date of the literal package * @param {Array} [userIDs] - User IDs to encrypt for, e.g. [{ name:'Robert Receiver', email:'robert@openpgp.org' }] - * @param {Boolean} [streaming] - Whether to process data as a stream * @param {Object} [config] - Full configuration, defaults to openpgp.config * @returns {Message} New message with encrypted content. * @async */ - async encrypt(keys, passwords, sessionKey, wildcard = false, encryptionKeyIDs = [], date = new Date(), userIDs = [], streaming, config = defaultConfig) { + async encrypt(keys, passwords, sessionKey, wildcard = false, encryptionKeyIDs = [], date = new Date(), userIDs = [], config = defaultConfig) { if (sessionKey) { if (!util.isUint8Array(sessionKey.data) || !util.isString(sessionKey.algorithm)) { throw new Error('Invalid session key for encryption.'); @@ -348,7 +346,7 @@ export class Message { } symEncryptedPacket.packets = this.packets; - await symEncryptedPacket.encrypt(algorithm, sessionKeyData, streaming, config); + await symEncryptedPacket.encrypt(algorithm, sessionKeyData, config); msg.packets.push(symEncryptedPacket); symEncryptedPacket.packets = new PacketList(); // remove packets after encryption @@ -433,12 +431,11 @@ export class Message { * @param {Array} [signingKeyIDs] - Array of key IDs to use for signing. Each signingKeyIDs[i] corresponds to privateKeys[i] * @param {Date} [date] - Override the creation time of the signature * @param {Array} [userIDs] - User IDs to sign with, e.g. [{ name:'Steve Sender', email:'steve@openpgp.org' }] - * @param {Boolean} [streaming] - Whether to process data as a stream * @param {Object} [config] - Full configuration, defaults to openpgp.config * @returns {Message} New message with signed content. * @async */ - async sign(privateKeys = [], signature = null, signingKeyIDs = [], date = new Date(), userIDs = [], streaming = false, config = defaultConfig) { + async sign(privateKeys = [], signature = null, signingKeyIDs = [], date = new Date(), userIDs = [], config = defaultConfig) { const packetlist = new PacketList(); const literalDataPacket = this.packets.findPacket(enums.packet.literalData); @@ -488,7 +485,7 @@ export class Message { }); packetlist.push(literalDataPacket); - packetlist.concat(await createSignaturePackets(literalDataPacket, privateKeys, signature, signingKeyIDs, date, userIDs, false, streaming, config)); + packetlist.concat(await createSignaturePackets(literalDataPacket, privateKeys, signature, signingKeyIDs, date, userIDs, false, config)); return new Message(packetlist); } @@ -521,49 +518,47 @@ export class Message { * @param {Array} [signingKeyIDs] - Array of key IDs to use for signing. Each signingKeyIDs[i] corresponds to privateKeys[i] * @param {Date} [date] - Override the creation time of the signature * @param {Array} [userIDs] - User IDs to sign with, e.g. [{ name:'Steve Sender', email:'steve@openpgp.org' }] - * @param {Boolean} [streaming] - Whether to process data as a stream * @param {Object} [config] - Full configuration, defaults to openpgp.config * @returns {Signature} New detached signature of message content. * @async */ - async signDetached(privateKeys = [], signature = null, signingKeyIDs = [], date = new Date(), userIDs = [], streaming = false, config = defaultConfig) { + async signDetached(privateKeys = [], signature = null, signingKeyIds = [], date = new Date(), userIDs = [], config = defaultConfig) { const literalDataPacket = this.packets.findPacket(enums.packet.literalData); if (!literalDataPacket) { throw new Error('No literal data packet to sign.'); } - return new Signature(await createSignaturePackets(literalDataPacket, privateKeys, signature, signingKeyIDs, date, userIDs, true, streaming, config)); + return new Signature(await createSignaturePackets(literalDataPacket, privateKeys, signature, signingKeyIds, date, userIDs, true, config)); } /** * Verify message signatures * @param {Array} keys - Array of keys to verify signatures * @param {Date} [date] - Verify the signature against the given date, i.e. check signature creation time < date < expiration time - * @param {Boolean} [streaming] - Whether to process data as a stream * @param {Object} [config] - Full configuration, defaults to openpgp.config * @returns {Array<{keyID: module:type/keyid~KeyID, * signature: Promise, * verified: Promise}>} List of signer's keyID and validity of signatures. * @async */ - async verify(keys, date = new Date(), streaming, config = defaultConfig) { + async verify(keys, date = new Date(), config = defaultConfig) { const msg = this.unwrapCompressed(); const literalDataList = msg.packets.filterByTag(enums.packet.literalData); if (literalDataList.length !== 1) { throw new Error('Can only verify message with one literal data packet.'); } - if (!streaming) { + if (stream.isArrayStream(msg.packets.stream)) { msg.packets.concat(await stream.readToEnd(msg.packets.stream, _ => _)); } const onePassSigList = msg.packets.filterByTag(enums.packet.onePassSignature).reverse(); const signatureList = msg.packets.filterByTag(enums.packet.signature); - if (streaming && onePassSigList.length && !signatureList.length && msg.packets.stream) { + if (onePassSigList.length && !signatureList.length && util.isStream(msg.packets.stream) && !stream.isArrayStream(msg.packets.stream)) { await Promise.all(onePassSigList.map(async onePassSig => { onePassSig.correspondingSig = new Promise((resolve, reject) => { onePassSig.correspondingSigResolve = resolve; onePassSig.correspondingSigReject = reject; }); onePassSig.signatureData = stream.fromAsync(async () => (await onePassSig.correspondingSig).signatureData); - onePassSig.hashed = stream.readToEnd(await onePassSig.hash(onePassSig.signatureType, literalDataList[0], undefined, false, streaming)); + onePassSig.hashed = stream.readToEnd(await onePassSig.hash(onePassSig.signatureType, literalDataList[0], undefined, false)); onePassSig.hashed.catch(() => {}); })); msg.packets.stream = stream.transformPair(msg.packets.stream, async (readable, writable) => { @@ -584,9 +579,9 @@ export class Message { await writer.abort(e); } }); - return createVerificationObjects(onePassSigList, literalDataList, keys, date, false, streaming, config); + return createVerificationObjects(onePassSigList, literalDataList, keys, date, false, config); } - return createVerificationObjects(signatureList, literalDataList, keys, date, false, streaming, config); + return createVerificationObjects(signatureList, literalDataList, keys, date, false, config); } /** @@ -600,14 +595,14 @@ export class Message { * verified: Promise}>} List of signer's keyID and validity of signature. * @async */ - verifyDetached(signature, keys, date = new Date(), streaming, config = defaultConfig) { + verifyDetached(signature, keys, date = new Date(), config = defaultConfig) { const msg = this.unwrapCompressed(); const literalDataList = msg.packets.filterByTag(enums.packet.literalData); if (literalDataList.length !== 1) { throw new Error('Can only verify message with one literal data packet.'); } const signatureList = signature.packets; - return createVerificationObjects(signatureList, literalDataList, keys, date, true, undefined, config); + return createVerificationObjects(signatureList, literalDataList, keys, date, true, config); } /** @@ -717,13 +712,12 @@ export class Message { * @param {Date} [date] - Override the creationtime of the signature * @param {Array} [userIDs] - User IDs to sign with, e.g. [{ name:'Steve Sender', email:'steve@openpgp.org' }] * @param {Boolean} [detached] - Whether to create detached signature packets - * @param {Boolean} [streaming] - Whether to process data as a stream * @param {Object} [config] - Full configuration, defaults to openpgp.config * @returns {PacketList} List of signature packets. * @async * @private */ -export async function createSignaturePackets(literalDataPacket, privateKeys, signature = null, signingKeyIDs = [], date = new Date(), userIDs = [], detached = false, streaming = false, config = defaultConfig) { +export async function createSignaturePackets(literalDataPacket, privateKeys, signature = null, signingKeyIDs = [], date = new Date(), userIDs = [], detached = false, config = defaultConfig) { const packetlist = new PacketList(); // If data packet was created from Uint8Array, use binary, otherwise use text @@ -736,7 +730,7 @@ export async function createSignaturePackets(literalDataPacket, privateKeys, sig throw new Error('Need private key for signing'); } const signingKey = await privateKey.getSigningKey(signingKeyIDs[i], date, userID, config); - return createSignaturePacket(literalDataPacket, privateKey, signingKey.keyPacket, { signatureType }, date, userID, detached, streaming, config); + return createSignaturePacket(literalDataPacket, privateKey, signingKey.keyPacket, { signatureType }, date, userID, detached, config); })).then(signatureList => { signatureList.forEach(signaturePacket => packetlist.push(signaturePacket)); }); @@ -763,7 +757,7 @@ export async function createSignaturePackets(literalDataPacket, privateKeys, sig * @async * @private */ -async function createVerificationObject(signature, literalDataList, keys, date = new Date(), detached = false, streaming = false, config = defaultConfig) { +async function createVerificationObject(signature, literalDataList, keys, date = new Date(), detached = false, config = defaultConfig) { let primaryKey; let signingKey; let keyError; @@ -791,7 +785,7 @@ async function createVerificationObject(signature, literalDataList, keys, date = if (keyError) { throw keyError; } - await signature.verify(signingKey.keyPacket, signature.signatureType, literalDataList[0], detached, streaming, config); + await signature.verify(signingKey.keyPacket, signature.signatureType, literalDataList[0], detached, config); const sig = await signaturePacket; if (sig.isExpired(date) || !( sig.created >= signingKey.getCreationTime() && @@ -837,11 +831,11 @@ async function createVerificationObject(signature, literalDataList, keys, date = * @async * @private */ -export async function createVerificationObjects(signatureList, literalDataList, keys, date = new Date(), detached = false, streaming = false, config = defaultConfig) { +export async function createVerificationObjects(signatureList, literalDataList, keys, date = new Date(), detached = false, config = defaultConfig) { return Promise.all(signatureList.filter(function(signature) { return ['text', 'binary'].includes(enums.read(enums.signature, signature.signatureType)); }).map(async function(signature) { - return createVerificationObject(signature, literalDataList, keys, date, detached, streaming, config); + return createVerificationObject(signature, literalDataList, keys, date, detached, config); })); } diff --git a/src/openpgp.js b/src/openpgp.js index 6203cf70..cd764a7c 100644 --- a/src/openpgp.js +++ b/src/openpgp.js @@ -262,13 +262,13 @@ export function encrypt({ message, publicKeys, privateKeys, passwords, sessionKe privateKeys = []; } if (privateKeys.length || signature) { // sign the message only if private keys or signature is specified - message = await message.sign(privateKeys, signature, signingKeyIDs, date, fromUserIDs, message.fromStream, config); + message = await message.sign(privateKeys, signature, signingKeyIDs, date, fromUserIDs, config); } message = message.compress( await getPreferredAlgo('compression', publicKeys, date, toUserIDs, config), config ); - message = await message.encrypt(publicKeys, passwords, sessionKey, wildcard, encryptionKeyIDs, date, toUserIDs, streaming, config); + message = await message.encrypt(publicKeys, passwords, sessionKey, wildcard, encryptionKeyIDs, date, toUserIDs, config); const data = armor ? message.armor(config) : message.write(); return convertStream(data, streaming, armor ? 'utf8' : 'binary'); }).catch(onError.bind(null, 'Error encrypting message')); @@ -309,13 +309,13 @@ export function decrypt({ message, privateKeys, passwords, sessionKeys, publicKe config = { ...defaultConfig, ...config }; checkMessage(message); publicKeys = toArray(publicKeys); privateKeys = toArray(privateKeys); passwords = toArray(passwords); sessionKeys = toArray(sessionKeys); - return message.decrypt(privateKeys, passwords, sessionKeys, streaming, config).then(async function(decrypted) { + return message.decrypt(privateKeys, passwords, sessionKeys, config).then(async function(decrypted) { if (!publicKeys) { publicKeys = []; } const result = {}; - result.signatures = signature ? await decrypted.verifyDetached(signature, publicKeys, date, streaming, config) : await decrypted.verify(publicKeys, date, streaming, config); + result.signatures = signature ? await decrypted.verifyDetached(signature, publicKeys, date, config) : await decrypted.verify(publicKeys, date, config); result.data = format === 'binary' ? decrypted.getLiteralData() : decrypted.getText(); result.filename = decrypted.getFilename(); linkStreams(result, message); @@ -358,12 +358,10 @@ export function sign({ message, privateKeys, armor = true, streaming = message & return Promise.resolve().then(async function() { let signature; - if (message instanceof CleartextMessage) { - signature = await message.sign(privateKeys, undefined, signingKeyIDs, date, fromUserIDs, config); - } else if (detached) { - signature = await message.signDetached(privateKeys, undefined, signingKeyIDs, date, fromUserIDs, message.fromStream, config); + if (detached) { + signature = await message.signDetached(privateKeys, undefined, signingKeyIDs, date, fromUserIDs, config); } else { - signature = await message.sign(privateKeys, undefined, signingKeyIDs, date, fromUserIDs, message.fromStream, config); + signature = await message.sign(privateKeys, undefined, signingKeyIDs, date, fromUserIDs, config); } signature = armor ? signature.armor(config) : signature.write(); if (detached) { @@ -413,10 +411,10 @@ export function verify({ message, publicKeys, format = 'utf8', streaming = messa return Promise.resolve().then(async function() { const result = {}; - if (message instanceof CleartextMessage) { - result.signatures = await message.verify(publicKeys, date, config); + if (signature) { + result.signatures = await message.verifyDetached(signature, publicKeys, date, config); } else { - result.signatures = signature ? await message.verifyDetached(signature, publicKeys, date, streaming, config) : await message.verify(publicKeys, date, streaming, config); + result.signatures = await message.verify(publicKeys, date, config); } result.data = format === 'binary' ? message.getLiteralData() : message.getText(); if (streaming) linkStreams(result, message); diff --git a/src/packet/aead_encrypted_data.js b/src/packet/aead_encrypted_data.js index d57d4bf3..44f0ecbd 100644 --- a/src/packet/aead_encrypted_data.js +++ b/src/packet/aead_encrypted_data.js @@ -89,31 +89,29 @@ class AEADEncryptedDataPacket { * Decrypt the encrypted payload. * @param {String} sessionKeyAlgorithm - The session key's cipher algorithm e.g. 'aes128' * @param {Uint8Array} key - The session key used to encrypt the payload - * @param {Boolean} streaming - Whether the top-level function will return a stream * @throws {Error} if decryption was not successful * @async */ - async decrypt(sessionKeyAlgorithm, key, streaming) { - await this.packets.read(await this.crypt('decrypt', key, stream.clone(this.encrypted), streaming), allowedPackets, streaming); + async decrypt(sessionKeyAlgorithm, key) { + await this.packets.read(await this.crypt('decrypt', key, stream.clone(this.encrypted)), allowedPackets); } /** * Encrypt the packet list payload. * @param {String} sessionKeyAlgorithm - The session key's cipher algorithm e.g. 'aes128' * @param {Uint8Array} key - The session key used to encrypt the payload - * @param {Boolean} streaming - Whether the top-level function will return a stream * @param {Object} [config] - Full configuration, defaults to openpgp.config * @throws {Error} if encryption was not successful * @async */ - async encrypt(sessionKeyAlgorithm, key, streaming, config = defaultConfig) { + async encrypt(sessionKeyAlgorithm, key, config = defaultConfig) { this.cipherAlgo = enums.write(enums.symmetric, sessionKeyAlgorithm); this.aeadAlgo = enums.write(enums.aead, this.aeadAlgorithm); const mode = crypto.mode[enums.read(enums.aead, this.aeadAlgo)]; this.iv = await crypto.random.getRandomBytes(mode.ivLength); // generate new random IV this.chunkSizeByte = config.aeadChunkSizeByte; const data = this.packets.write(); - this.encrypted = await this.crypt('encrypt', key, data, streaming); + this.encrypted = await this.crypt('encrypt', key, data); } /** @@ -121,11 +119,10 @@ class AEADEncryptedDataPacket { * @param {encrypt|decrypt} fn - Whether to encrypt or decrypt * @param {Uint8Array} key - The session key used to en/decrypt the payload * @param {Uint8Array | ReadableStream} data - The data to en/decrypt - * @param {Boolean} streaming - Whether the top-level function will return a stream * @returns {Uint8Array | ReadableStream} * @async */ - async crypt(fn, key, data, streaming) { + async crypt(fn, key, data) { const cipher = enums.read(enums.symmetric, this.cipherAlgo); const mode = crypto.mode[enums.read(enums.aead, this.aeadAlgo)]; const modeInstance = await mode(cipher, key); @@ -146,7 +143,7 @@ class AEADEncryptedDataPacket { return stream.transformPair(data, async (readable, writable) => { if (util.isStream(readable) !== 'array') { const buffer = new stream.TransformStream({}, { - highWaterMark: streaming ? util.getHardwareConcurrency() * 2 ** (this.chunkSizeByte + 6) : Infinity, + highWaterMark: util.getHardwareConcurrency() * 2 ** (this.chunkSizeByte + 6), size: array => array.length }); stream.pipe(buffer.readable, writable); diff --git a/src/packet/packet.js b/src/packet/packet.js index 3da9689d..084cfd9f 100644 --- a/src/packet/packet.js +++ b/src/packet/packet.js @@ -117,7 +117,7 @@ export function supportsStreaming(tag_type) { * @param {Function} callback - Function to call with the parsed packet * @returns {Boolean} Returns false if the stream was empty and parsing is done, and true otherwise. */ -export async function readPackets(input, streaming, callback) { +export async function readPackets(input, callback) { const reader = stream.getReader(input); let writer; let callbackReturned; @@ -149,7 +149,7 @@ export async function readPackets(input, streaming, callback) { const packetSupportsStreaming = supportsStreaming(tag); let packet = null; - if (streaming && packetSupportsStreaming) { + if (packetSupportsStreaming) { if (util.isStream(input) === 'array') { const arrayStream = new stream.ArrayStream(); writer = stream.getWriter(arrayStream); diff --git a/src/packet/packetlist.js b/src/packet/packetlist.js index a986b7cf..30148cc1 100644 --- a/src/packet/packetlist.js +++ b/src/packet/packetlist.js @@ -33,18 +33,18 @@ class PacketList extends Array { * Reads a stream of binary data and interprets it as a list of packets. * @param {Uint8Array | ReadableStream} bytes - A Uint8Array of bytes. */ - async read(bytes, allowedPackets, streaming, config = defaultConfig) { + async read(bytes, allowedPackets, config = defaultConfig) { this.stream = stream.transformPair(bytes, async (readable, writable) => { const writer = stream.getWriter(writable); try { while (true) { await writer.ready; - const done = await readPackets(readable, streaming, async parsed => { + const done = await readPackets(readable, async parsed => { try { const packet = newPacketFromTag(parsed.tag, allowedPackets); packet.packets = new PacketList(); packet.fromStream = util.isStream(parsed.packet); - await packet.read(parsed.packet, config, streaming); + await packet.read(parsed.packet, config); await writer.write(packet); } catch (e) { if (!config.tolerant || supportsStreaming(parsed.tag)) { diff --git a/src/packet/signature.js b/src/packet/signature.js index 17a95971..17a6219c 100644 --- a/src/packet/signature.js +++ b/src/packet/signature.js @@ -153,11 +153,10 @@ class SignaturePacket { * @param {SecretKeyPacket} key - Private key used to sign the message. * @param {Object} data - Contains packets to be signed. * @param {Boolean} [detached] - Whether to create a detached signature - * @param {Boolean} [streaming] - Whether to process data as a stream * @throws {Error} if signing failed * @async */ - async sign(key, data, detached = false, streaming = false) { + async sign(key, data, detached = false) { const signatureType = enums.write(enums.signature, this.signatureType); const publicKeyAlgorithm = enums.write(enums.publicKey, this.publicKeyAlgorithm); const hashAlgorithm = enums.write(enums.hash, this.hashAlgorithm); @@ -183,7 +182,7 @@ class SignaturePacket { const signed = async () => crypto.signature.sign( publicKeyAlgorithm, hashAlgorithm, key.publicParams, key.privateParams, toHash, await stream.readToEnd(hash) ); - if (streaming) { + if (util.isStream(hash)) { this.params = signed(); } else { this.params = await signed(); @@ -643,12 +642,9 @@ class SignaturePacket { return util.concat([bytes, this.signatureData, this.calculateTrailer(data, detached)]); } - async hash(signatureType, data, toHash, detached = false, streaming = true) { + async hash(signatureType, data, toHash, detached = false) { const hashAlgorithm = enums.write(enums.hash, this.hashAlgorithm); if (!toHash) toHash = this.toHash(signatureType, data, detached); - if (!streaming && util.isStream(toHash)) { - return stream.fromAsync(async () => this.hash(signatureType, data, await stream.readToEnd(toHash), detached)); - } return crypto.hash.digest(hashAlgorithm, toHash); } @@ -659,12 +655,11 @@ class SignaturePacket { * @param {module:enums.signature} signatureType - Expected signature type * @param {String|Object} data - Data which on the signature applies * @param {Boolean} [detached] - Whether to verify a detached signature - * @param {Boolean} [streaming] - Whether to process data as a stream * @param {Object} [config] - Full configuration, defaults to openpgp.config * @throws {Error} if signature validation failed * @async */ - async verify(key, signatureType, data, detached = false, streaming = false, config = defaultConfig) { + async verify(key, signatureType, data, detached = false, config = defaultConfig) { const publicKeyAlgorithm = enums.write(enums.publicKey, this.publicKeyAlgorithm); const hashAlgorithm = enums.write(enums.hash, this.hashAlgorithm); @@ -678,7 +673,6 @@ class SignaturePacket { hash = await this.hashed; } else { toHash = this.toHash(signatureType, data, detached); - if (!streaming) toHash = await stream.readToEnd(toHash); hash = await this.hash(signatureType, data, toHash); } hash = await stream.readToEnd(hash); diff --git a/src/packet/sym_encrypted_integrity_protected_data.js b/src/packet/sym_encrypted_integrity_protected_data.js index 020dedc4..6794f1fc 100644 --- a/src/packet/sym_encrypted_integrity_protected_data.js +++ b/src/packet/sym_encrypted_integrity_protected_data.js @@ -88,14 +88,13 @@ class SymEncryptedIntegrityProtectedDataPacket { * Encrypt the payload in the packet. * @param {String} sessionKeyAlgorithm - The selected symmetric encryption algorithm to be used e.g. 'aes128' * @param {Uint8Array} key - The key of cipher blocksize length to be used - * @param {Boolean} streaming - Whether to set this.encrypted to a stream * @param {Object} [config] - Full configuration, defaults to openpgp.config * @returns {Boolean} * @async */ - async encrypt(sessionKeyAlgorithm, key, streaming, config = defaultConfig) { + async encrypt(sessionKeyAlgorithm, key, config = defaultConfig) { let bytes = this.packets.write(); - if (!streaming) bytes = await stream.readToEnd(bytes); + if (stream.isArrayStream(bytes)) bytes = await stream.readToEnd(bytes); const prefix = await crypto.getPrefixRandom(sessionKeyAlgorithm); const mdc = new Uint8Array([0xD3, 0x14]); // modification detection code packet @@ -111,14 +110,13 @@ class SymEncryptedIntegrityProtectedDataPacket { * Decrypts the encrypted data contained in the packet. * @param {String} sessionKeyAlgorithm - The selected symmetric encryption algorithm to be used e.g. 'aes128' * @param {Uint8Array} key - The key of cipher blocksize length to be used - * @param {Boolean} streaming - Whether to read this.encrypted as a stream * @param {Object} [config] - Full configuration, defaults to openpgp.config * @returns {Boolean} * @async */ - async decrypt(sessionKeyAlgorithm, key, streaming, config = defaultConfig) { + async decrypt(sessionKeyAlgorithm, key, config = defaultConfig) { let encrypted = stream.clone(this.encrypted); - if (!streaming) encrypted = await stream.readToEnd(encrypted); + if (stream.isArrayStream(encrypted)) encrypted = await stream.readToEnd(encrypted); const decrypted = await crypto.mode.cfb.decrypt(sessionKeyAlgorithm, key, encrypted, new Uint8Array(crypto.cipher[sessionKeyAlgorithm].blockSize)); // there must be a modification detection code packet as the @@ -140,7 +138,7 @@ class SymEncryptedIntegrityProtectedDataPacket { if (!util.isStream(encrypted) || !config.allowUnauthenticatedStream) { packetbytes = await stream.readToEnd(packetbytes); } - await this.packets.read(packetbytes, allowedPackets, streaming); + await this.packets.read(packetbytes, allowedPackets); return true; } } diff --git a/src/packet/symmetrically_encrypted_data.js b/src/packet/symmetrically_encrypted_data.js index 763eb7a0..3df67adb 100644 --- a/src/packet/symmetrically_encrypted_data.js +++ b/src/packet/symmetrically_encrypted_data.js @@ -79,7 +79,7 @@ class SymmetricallyEncryptedDataPacket { * @throws {Error} if decryption was not successful * @async */ - async decrypt(sessionKeyAlgorithm, key, streaming, config = defaultConfig) { + async decrypt(sessionKeyAlgorithm, key, config = defaultConfig) { // If MDC errors are not being ignored, all missing MDC packets in symmetrically encrypted data should throw an error if (!config.allowUnauthenticatedMessages) { throw new Error('Message is not authenticated.'); @@ -91,7 +91,7 @@ class SymmetricallyEncryptedDataPacket { encrypted.subarray(2, crypto.cipher[sessionKeyAlgorithm].blockSize + 2) ); - await this.packets.read(decrypted, allowedPackets, streaming); + await this.packets.read(decrypted, allowedPackets); } /** @@ -103,7 +103,7 @@ class SymmetricallyEncryptedDataPacket { * @throws {Error} if encryption was not successful * @async */ - async encrypt(algo, key, streaming, config = defaultConfig) { + async encrypt(algo, key, config = defaultConfig) { const data = this.packets.write(); const prefix = await crypto.getPrefixRandom(algo); diff --git a/test/general/packet.js b/test/general/packet.js index bfcc3ca4..0076f4a4 100644 --- a/test/general/packet.js +++ b/test/general/packet.js @@ -221,7 +221,7 @@ module.exports = () => describe("Packet", function() { const msg2 = new openpgp.PacketList(); try { - await enc.encrypt(algo, key, undefined, { ...openpgp.config, aeadChunkSizeByte: 0 }); + await enc.encrypt(algo, key, { ...openpgp.config, aeadChunkSizeByte: 0 }); await msg2.read(msg.write(), allAllowedPackets); await msg2[0].decrypt(algo, key); expect(await openpgp.stream.readToEnd(msg2[0].packets[0].data)).to.deep.equal(literal.data); @@ -266,7 +266,7 @@ module.exports = () => describe("Packet", function() { randomBytesStub.returns(iv); try { - await enc.encrypt(algo, key, undefined, { ...openpgp.config, aeadChunkSizeByte: 14 }); + await enc.encrypt(algo, key, { ...openpgp.config, aeadChunkSizeByte: 14 }); const data = msg.write(); expect(await openpgp.stream.readToEnd(openpgp.stream.clone(data))).to.deep.equal(packetBytes); await msg2.read(data, allAllowedPackets);