diff --git a/src/packet/literal.js b/src/packet/literal.js index d4af1f38..31d1eda1 100644 --- a/src/packet/literal.js +++ b/src/packet/literal.js @@ -169,7 +169,7 @@ Literal.prototype.write = function() { const date = util.writeDate(this.date); const data = this.getBytes(); - return util.concatUint8Array([format, filename_length, filename, date, data]); + return util.concat([format, filename_length, filename, date, data]); }; export default Literal; diff --git a/src/packet/packetlist.js b/src/packet/packetlist.js index 05644417..afffd8d2 100644 --- a/src/packet/packetlist.js +++ b/src/packet/packetlist.js @@ -86,19 +86,19 @@ List.prototype.write = function () { if (bufferLength >= minLength) { const powerOf2 = Math.min(Math.log(bufferLength) / Math.LN2 | 0, 30); const chunkSize = 2 ** powerOf2; - const bufferConcat = util.concatUint8Array([packetParser.writePartialLength(powerOf2)].concat(buffer)); + const bufferConcat = util.concat([packetParser.writePartialLength(powerOf2)].concat(buffer)); buffer = [bufferConcat.subarray(1 + chunkSize)]; bufferLength = buffer[0].length; return bufferConcat.subarray(0, 1 + chunkSize); } - }, () => util.concatUint8Array([packetParser.writeSimpleLength(bufferLength)].concat(buffer)))); + }, () => util.concat([packetParser.writeSimpleLength(bufferLength)].concat(buffer)))); } else { arr.push(packetParser.writeHeader(this[i].tag, packetbytes.length)); arr.push(packetbytes); } } - return util.concatUint8Array(arr); + return util.concat(arr); }; /** diff --git a/src/packet/signature.js b/src/packet/signature.js index 7c0aeb32..c430a637 100644 --- a/src/packet/signature.js +++ b/src/packet/signature.js @@ -208,7 +208,7 @@ Signature.prototype.write = function () { } arr.push(this.signedHashValue); arr.push(this.signature); - return util.concatUint8Array(arr); + return util.concat(arr); }; /** @@ -237,7 +237,7 @@ Signature.prototype.sign = async function (key, data) { // Add hashed subpackets arr.push(this.write_all_sub_packets()); - this.signatureData = util.concatUint8Array(arr); + this.signatureData = util.concat(arr); const trailer = this.calculateTrailer(); @@ -245,10 +245,10 @@ Signature.prototype.sign = async function (key, data) { switch (this.version) { case 3: - toHash = util.concatUint8Array([this.toSign(signatureType, data), new Uint8Array([signatureType]), util.writeDate(this.created)]); + toHash = util.concat([this.toSign(signatureType, data), new Uint8Array([signatureType]), util.writeDate(this.created)]); break; case 4: - toHash = util.concatUint8Array([this.toSign(signatureType, data), this.signatureData, trailer]); + toHash = util.concat([this.toSign(signatureType, data), this.signatureData, trailer]); break; default: throw new Error('Version ' + this.version + ' of the signature is unsupported.'); } @@ -299,7 +299,7 @@ Signature.prototype.write_all_sub_packets = function () { } if (this.revocationKeyClass !== null) { bytes = new Uint8Array([this.revocationKeyClass, this.revocationKeyAlgorithm]); - bytes = util.concatUint8Array([bytes, this.revocationKeyFingerprint]); + bytes = util.concat([bytes, this.revocationKeyFingerprint]); arr.push(write_sub_packet(sub.revocation_key, bytes)); } if (!this.issuerKeyId.isNull() && this.issuerKeyVersion !== 5) { @@ -315,7 +315,7 @@ Signature.prototype.write_all_sub_packets = function () { // 2 octets of value length bytes.push(util.writeNumber(value.length, 2)); bytes.push(util.str_to_Uint8Array(name + value)); - bytes = util.concatUint8Array(bytes); + bytes = util.concat(bytes); arr.push(write_sub_packet(sub.notation_data, bytes)); }); } @@ -358,7 +358,7 @@ Signature.prototype.write_all_sub_packets = function () { if (this.signatureTargetPublicKeyAlgorithm !== null) { bytes = [new Uint8Array([this.signatureTargetPublicKeyAlgorithm, this.signatureTargetHashAlgorithm])]; bytes.push(util.str_to_Uint8Array(this.signatureTargetHash)); - bytes = util.concatUint8Array(bytes); + bytes = util.concat(bytes); arr.push(write_sub_packet(sub.signature_target, bytes)); } if (this.embeddedSignature !== null) { @@ -366,7 +366,7 @@ Signature.prototype.write_all_sub_packets = function () { } if (this.issuerFingerprint !== null) { bytes = [new Uint8Array([this.issuerKeyVersion]), this.issuerFingerprint]; - bytes = util.concatUint8Array(bytes); + bytes = util.concat(bytes); arr.push(write_sub_packet(sub.issuer_fingerprint, bytes)); } if (this.preferredAeadAlgorithms !== null) { @@ -374,10 +374,10 @@ Signature.prototype.write_all_sub_packets = function () { arr.push(write_sub_packet(sub.preferred_aead_algorithms, bytes)); } - const result = util.concatUint8Array(arr); + const result = util.concat(arr); const length = util.writeNumber(result.length, 2); - return util.concatUint8Array([length, result]); + return util.concat([length, result]); }; /** @@ -394,7 +394,7 @@ function write_sub_packet(type, data) { arr.push(packet.writeSimpleLength(data.length + 1)); arr.push(new Uint8Array([type])); arr.push(data); - return util.concatUint8Array(arr); + return util.concat(arr); } // V4 signature sub packets @@ -611,12 +611,12 @@ Signature.prototype.toSign = function (type, data) { const bytes = packet.write(); if (this.version === 4) { - return util.concatUint8Array([this.toSign(t.key, data), + return util.concat([this.toSign(t.key, data), new Uint8Array([tag]), util.writeNumber(bytes.length, 4), bytes]); } else if (this.version === 3) { - return util.concatUint8Array([this.toSign(t.key, data), + return util.concat([this.toSign(t.key, data), bytes]); } break; @@ -624,7 +624,7 @@ Signature.prototype.toSign = function (type, data) { case t.subkey_binding: case t.subkey_revocation: case t.key_binding: - return util.concatUint8Array([this.toSign(t.key, data), this.toSign(t.key, { + return util.concat([this.toSign(t.key, data), this.toSign(t.key, { key: data.bind })]); @@ -653,7 +653,7 @@ Signature.prototype.calculateTrailer = function () { return new Uint8Array(0); } const first = new Uint8Array([4, 0xFF]); //Version, ? - return util.concatUint8Array([first, util.writeNumber(this.signatureData.length, 4)]); + return util.concat([first, util.writeNumber(this.signatureData.length, 4)]); }; @@ -700,7 +700,7 @@ Signature.prototype.verify = async function (key, data) { this.verified = await crypto.signature.verify( publicKeyAlgorithm, hashAlgorithm, mpi, key.params, - util.concatUint8Array([bytes, this.signatureData, trailer]) + util.concat([bytes, this.signatureData, trailer]) ); return this.verified; diff --git a/src/packet/sym_encrypted_aead_protected.js b/src/packet/sym_encrypted_aead_protected.js index 821a2a86..2775ae5c 100644 --- a/src/packet/sym_encrypted_aead_protected.js +++ b/src/packet/sym_encrypted_aead_protected.js @@ -80,9 +80,9 @@ SymEncryptedAEADProtected.prototype.read = async function (bytes) { */ SymEncryptedAEADProtected.prototype.write = function () { if (config.aead_protect_version === 4) { - return util.concatUint8Array([new Uint8Array([this.version, this.cipherAlgo, this.aeadAlgo, this.chunkSizeByte]), this.iv, this.encrypted]); + return util.concat([new Uint8Array([this.version, this.cipherAlgo, this.aeadAlgo, this.chunkSizeByte]), this.iv, this.encrypted]); } - return util.concatUint8Array([new Uint8Array([this.version]), this.iv, this.encrypted]); + return util.concat([new Uint8Array([this.version]), this.iv, this.encrypted]); }; /** diff --git a/src/packet/sym_encrypted_integrity_protected.js b/src/packet/sym_encrypted_integrity_protected.js index 8bcced81..60537131 100644 --- a/src/packet/sym_encrypted_integrity_protected.js +++ b/src/packet/sym_encrypted_integrity_protected.js @@ -77,7 +77,7 @@ SymEncryptedIntegrityProtected.prototype.read = async function (bytes) { }; SymEncryptedIntegrityProtected.prototype.write = function () { - return util.concatUint8Array([new Uint8Array([VERSION]), this.encrypted]); + return util.concat([new Uint8Array([VERSION]), this.encrypted]); }; /** @@ -91,15 +91,15 @@ SymEncryptedIntegrityProtected.prototype.encrypt = async function (sessionKeyAlg const bytes = this.packets.write(); 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 prefix = util.concat([prefixrandom, repeat]); const mdc = new Uint8Array([0xD3, 0x14]); // modification detection code packet - let [tohash, tohashClone] = stream.tee(util.concatUint8Array([bytes, mdc])); - const hash = crypto.hash.sha1(util.concatUint8Array([prefix, tohashClone])); - tohash = util.concatUint8Array([tohash, hash]); + let [tohash, tohashClone] = stream.tee(util.concat([bytes, mdc])); + const hash = crypto.hash.sha1(util.concat([prefix, tohashClone])); + tohash = util.concat([tohash, hash]); if (sessionKeyAlgorithm.substr(0, 3) === 'aes') { // AES optimizations. Native code for node, asmCrypto for browser. - this.encrypted = aesEncrypt(sessionKeyAlgorithm, util.concatUint8Array([prefix, tohash]), key); + this.encrypted = aesEncrypt(sessionKeyAlgorithm, util.concat([prefix, tohash]), key); } else { this.encrypted = crypto.cfb.encrypt(prefixrandom, sessionKeyAlgorithm, tohash, key, false); this.encrypted = stream.subarray(this.encrypted, 0, prefix.length + tohash.length); @@ -130,7 +130,7 @@ SymEncryptedIntegrityProtected.prototype.decrypt = async function (sessionKeyAlg const encryptedPrefix = await stream.readToEnd(stream.subarray(encryptedClone, 0, crypto.cipher[sessionKeyAlgorithm].blockSize + 2)); const prefix = crypto.cfb.mdc(sessionKeyAlgorithm, key, encryptedPrefix); let [bytes, bytesClone] = stream.tee(stream.subarray(decrypted, 0, -20)); - const tohash = util.concatUint8Array([prefix, bytes]); + const tohash = util.concat([prefix, bytes]); this.hash = util.Uint8Array_to_str(await stream.readToEnd(crypto.hash.sha1(tohash))); const mdc = util.Uint8Array_to_str(await stream.readToEnd(stream.subarray(decryptedClone, -20))); @@ -176,7 +176,7 @@ function nodeEncrypt(algo, prefix, 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); - const ct = cipherObj.update(new Buffer(util.concatUint8Array([prefix, pt]))); + const ct = cipherObj.update(new Buffer(util.concat([prefix, pt]))); return new Uint8Array(ct); } diff --git a/src/util.js b/src/util.js index 38ed6656..39b1ae08 100644 --- a/src/util.js +++ b/src/util.js @@ -282,28 +282,29 @@ export default { }, /** - * Concat a list of Uint8arrays or a list of Strings - * @param {Array} Array of Uint8Arrays/Strings to concatenate - * @returns {Uint8array|String} Concatenated array + * Concat a list of Uint8Arrays, Strings or Streams + * The caller must not mix Uint8Arrays with Strings, but may mix Streams with non-Streams. + * @param {Array} Array of Uint8Arrays/Strings/Streams to concatenate + * @returns {Uint8array|String|ReadableStream} Concatenated array */ - concat: function (arrays) { - if (util.isUint8Array(arrays[0])) { - return util.concatUint8Array(arrays); + concat: function (list) { + if (list.some(util.isStream)) { + return stream.concat(list); } - return arrays.join(''); + if (util.isUint8Array(list[0])) { + return util.concatUint8Array(list); + } + return list.join(''); }, /** - * Concat Uint8arrays + * Concat Uint8Arrays * @param {Array} Array of Uint8Arrays to concatenate * @returns {Uint8array} Concatenated array */ concatUint8Array: function (arrays) { let totalLength = 0; for (let i = 0; i < arrays.length; i++) { - if (util.isStream(arrays[i])) { - return stream.concat(arrays); - } if (!util.isUint8Array(arrays[i])) { throw new Error('concatUint8Array: Data must be in the form of a Uint8Array'); }