@protontech/openpgp 6.0.0-beta.3.patch.1 → 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/README.md +34 -37
  2. package/dist/lightweight/argon2id.min.mjs +1 -1
  3. package/dist/lightweight/argon2id.min.mjs.map +1 -1
  4. package/dist/lightweight/argon2id.mjs +1 -1
  5. package/dist/lightweight/legacy_ciphers.min.mjs +1 -1
  6. package/dist/lightweight/legacy_ciphers.min.mjs.map +1 -1
  7. package/dist/lightweight/legacy_ciphers.mjs +1 -1
  8. package/dist/lightweight/noble_curves.min.mjs +1 -1
  9. package/dist/lightweight/noble_curves.min.mjs.map +1 -1
  10. package/dist/lightweight/noble_curves.mjs +1 -1
  11. package/dist/lightweight/noble_hashes.min.mjs +1 -1
  12. package/dist/lightweight/noble_hashes.min.mjs.map +1 -1
  13. package/dist/lightweight/noble_hashes.mjs +1 -1
  14. package/dist/lightweight/openpgp.min.mjs +4 -4
  15. package/dist/lightweight/openpgp.min.mjs.map +1 -1
  16. package/dist/lightweight/openpgp.mjs +247 -951
  17. package/dist/lightweight/seek-bzip.min.mjs +3 -0
  18. package/dist/lightweight/seek-bzip.min.mjs.map +1 -0
  19. package/dist/lightweight/seek-bzip.mjs +866 -0
  20. package/dist/lightweight/sha3.min.mjs +1 -1
  21. package/dist/lightweight/sha3.min.mjs.map +1 -1
  22. package/dist/lightweight/sha3.mjs +1 -1
  23. package/dist/node/openpgp.cjs +11366 -11208
  24. package/dist/node/openpgp.min.cjs +14 -14
  25. package/dist/node/openpgp.min.cjs.map +1 -1
  26. package/dist/node/openpgp.min.mjs +14 -14
  27. package/dist/node/openpgp.min.mjs.map +1 -1
  28. package/dist/node/openpgp.mjs +5459 -5301
  29. package/dist/openpgp.js +6506 -6348
  30. package/dist/openpgp.min.js +14 -14
  31. package/dist/openpgp.min.js.map +1 -1
  32. package/dist/openpgp.min.mjs +14 -14
  33. package/dist/openpgp.min.mjs.map +1 -1
  34. package/dist/openpgp.mjs +6506 -6348
  35. package/package.json +23 -23
@@ -1,4 +1,4 @@
1
- /*! OpenPGP.js v6.0.0-beta.3.patch.1 - 2024-09-11 - this is LGPL licensed code, see LICENSE/our website https://openpgpjs.org/ for more information. */
1
+ /*! OpenPGP.js v6.0.0 - 2024-11-06 - this is LGPL licensed code, see LICENSE/our website https://openpgpjs.org/ for more information. */
2
2
  const globalThis = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
3
3
 
4
4
  const doneWritingPromise = Symbol('doneWritingPromise');
@@ -1455,7 +1455,7 @@ var config = {
1455
1455
  * @memberof module:config
1456
1456
  * @property {Integer} preferredHashAlgorithm Default hash algorithm {@link module:enums.hash}
1457
1457
  */
1458
- preferredHashAlgorithm: enums.hash.sha256,
1458
+ preferredHashAlgorithm: enums.hash.sha512,
1459
1459
  /**
1460
1460
  * @memberof module:config
1461
1461
  * @property {Integer} preferredSymmetricAlgorithm Default encryption cipher {@link module:enums.symmetric}
@@ -1682,7 +1682,7 @@ var config = {
1682
1682
  * @memberof module:config
1683
1683
  * @property {String} versionString A version string to be included in armored messages
1684
1684
  */
1685
- versionString: 'OpenPGP.js 6.0.0-beta.3.patch.1',
1685
+ versionString: 'OpenPGP.js 6.0.0',
1686
1686
  /**
1687
1687
  * @memberof module:config
1688
1688
  * @property {String} commentString A comment string to be included in armored messages
@@ -1883,6 +1883,9 @@ const util = {
1883
1883
  * @returns {Uint8Array} Padded bytes.
1884
1884
  */
1885
1885
  leftPad(bytes, length) {
1886
+ if (bytes.length > length) {
1887
+ throw new Error('Input array too long');
1888
+ }
1886
1889
  const padded = new Uint8Array(length);
1887
1890
  const offset = length - bytes.length;
1888
1891
  padded.set(bytes, offset);
@@ -2458,7 +2461,7 @@ function encode$1(data) {
2458
2461
  * @returns {Uint8Array | ReadableStream<Uint8Array>} Binary array version of input string.
2459
2462
  * @static
2460
2463
  */
2461
- function decode$2(data) {
2464
+ function decode$1(data) {
2462
2465
  let buf = '';
2463
2466
  return transform(data, value => {
2464
2467
  buf += value;
@@ -2494,7 +2497,7 @@ function decode$2(data) {
2494
2497
  * @returns {Uint8Array} An array of 8-bit integers.
2495
2498
  */
2496
2499
  function b64ToUint8Array(base64) {
2497
- return decode$2(base64.replace(/-/g, '+').replace(/_/g, '/'));
2500
+ return decode$1(base64.replace(/-/g, '+').replace(/_/g, '/'));
2498
2501
  }
2499
2502
 
2500
2503
  /**
@@ -2747,7 +2750,7 @@ function unarmor(input) {
2747
2750
  let headersDone;
2748
2751
  let text = [];
2749
2752
  let textDone;
2750
- const data = decode$2(transformPair(input, async (readable, writable) => {
2753
+ const data = decode$1(transformPair(input, async (readable, writable) => {
2751
2754
  const reader = getReader(readable);
2752
2755
  try {
2753
2756
  while (true) {
@@ -4004,14 +4007,14 @@ function validatePCKS(data, pcks5) {
4004
4007
  return data;
4005
4008
  const len = data.length;
4006
4009
  if (!len)
4007
- throw new Error(`aes/pcks5: empty ciphertext not allowed`);
4010
+ throw new Error('aes/pcks5: empty ciphertext not allowed');
4008
4011
  const lastByte = data[len - 1];
4009
4012
  if (lastByte <= 0 || lastByte > 16)
4010
- throw new Error(`aes/pcks5: wrong padding byte: ${lastByte}`);
4013
+ throw new Error('aes/pcks5: wrong padding');
4011
4014
  const out = data.subarray(0, -lastByte);
4012
4015
  for (let i = 0; i < lastByte; i++)
4013
4016
  if (data[len - i - 1] !== lastByte)
4014
- throw new Error(`aes/pcks5: wrong padding`);
4017
+ throw new Error('aes/pcks5: wrong padding');
4015
4018
  return out;
4016
4019
  }
4017
4020
  function padPCKS(left) {
@@ -4152,17 +4155,21 @@ function computeTag(fn, isLE, key, data, AAD) {
4152
4155
  }
4153
4156
  /**
4154
4157
  * GCM: Galois/Counter Mode.
4155
- * Good, modern version of CTR, parallel, with MAC.
4158
+ * Modern, parallel version of CTR, with MAC.
4156
4159
  * Be careful: MACs can be forged.
4160
+ * Unsafe to use random nonces under the same key, due to collision chance.
4161
+ * As for nonce size, prefer 12-byte, instead of 8-byte.
4157
4162
  */
4158
4163
  const gcm = wrapCipher({ blockSize: 16, nonceLength: 12, tagLength: 16 }, function gcm(key, nonce, AAD) {
4159
4164
  bytes(key);
4160
4165
  bytes(nonce);
4161
4166
  if (AAD !== undefined)
4162
4167
  bytes(AAD);
4163
- // Nonce can be pretty much anything (even 1 byte). But smaller nonces less secure.
4164
- if (nonce.length === 0)
4165
- throw new Error('aes/gcm: empty nonce');
4168
+ // NIST 800-38d doesn't enforce minimum nonce length.
4169
+ // We enforce 8 bytes for compat with openssl.
4170
+ // 12 bytes are recommended. More than 12 bytes would be converted into 12.
4171
+ if (nonce.length < 8)
4172
+ throw new Error('aes/gcm: invalid nonce length');
4166
4173
  const tagLength = 16;
4167
4174
  function _computeTag(authKey, tagMask, data) {
4168
4175
  const tag = computeTag(ghash, false, authKey, data, AAD);
@@ -4175,12 +4182,11 @@ const gcm = wrapCipher({ blockSize: 16, nonceLength: 12, tagLength: 16 }, functi
4175
4182
  const authKey = EMPTY_BLOCK.slice();
4176
4183
  const counter = EMPTY_BLOCK.slice();
4177
4184
  ctr32(xk, false, counter, counter, authKey);
4185
+ // NIST 800-38d, page 15: different behavior for 96-bit and non-96-bit nonces
4178
4186
  if (nonce.length === 12) {
4179
4187
  counter.set(nonce);
4180
4188
  }
4181
4189
  else {
4182
- // Spec (NIST 800-38d) supports variable size nonce.
4183
- // Not supported for now, but can be useful.
4184
4190
  const nonceLen = EMPTY_BLOCK.slice();
4185
4191
  const view = createView(nonceLen);
4186
4192
  setBigUint64(view, 8, BigInt(nonce.length * 8), false);
@@ -4331,7 +4337,7 @@ const aeskw = wrapCipher({ blockSize: 8 }, (kek) => ({
4331
4337
  encrypt(plaintext) {
4332
4338
  bytes(plaintext);
4333
4339
  if (!plaintext.length || plaintext.length % 8 !== 0)
4334
- throw new Error('plaintext length must be non-empty and a multiple of 8 bytes');
4340
+ throw new Error('invalid plaintext length');
4335
4341
  if (plaintext.length === 8)
4336
4342
  throw new Error('8-byte keys not allowed in AESKW, use AESKWP instead');
4337
4343
  const out = concatBytes$1(AESKW_IV, plaintext);
@@ -4340,10 +4346,11 @@ const aeskw = wrapCipher({ blockSize: 8 }, (kek) => ({
4340
4346
  },
4341
4347
  decrypt(ciphertext) {
4342
4348
  bytes(ciphertext);
4349
+ // ciphertext must be at least 24 bytes and a multiple of 8 bytes
4343
4350
  // 24 because should have at least two block (1 iv + 2).
4344
4351
  // Replace with 16 to enable '8-byte keys'
4345
4352
  if (ciphertext.length % 8 !== 0 || ciphertext.length < 3 * 8)
4346
- throw new Error('ciphertext must be at least 24 bytes and a multiple of 8 bytes');
4353
+ throw new Error('invalid ciphertext length');
4347
4354
  const out = copyBytes(ciphertext);
4348
4355
  AESW.decrypt(kek, out);
4349
4356
  if (!equalBytes$1(out.subarray(0, 8), AESKW_IV))
@@ -5617,16 +5624,13 @@ const nodeCrypto$6 = util.getNodeCrypto();
5617
5624
  * @returns {Uint8Array} Random byte array.
5618
5625
  */
5619
5626
  function getRandomBytes(length) {
5620
- const buf = new Uint8Array(length);
5621
- if (nodeCrypto$6) {
5622
- const bytes = nodeCrypto$6.randomBytes(buf.length);
5623
- buf.set(bytes);
5624
- } else if (typeof crypto !== 'undefined' && crypto.getRandomValues) {
5625
- crypto.getRandomValues(buf);
5627
+ const webcrypto = typeof crypto !== 'undefined' ? crypto : nodeCrypto$6?.webcrypto;
5628
+ if (webcrypto?.getRandomValues) {
5629
+ const buf = new Uint8Array(length);
5630
+ return webcrypto.getRandomValues(buf);
5626
5631
  } else {
5627
5632
  throw new Error('No secure random number generator available.');
5628
5633
  }
5629
- return buf;
5630
5634
  }
5631
5635
 
5632
5636
  /**
@@ -6092,6 +6096,14 @@ const _1n$3 = BigInt(1);
6092
6096
  * @async
6093
6097
  */
6094
6098
  async function sign$7(hashAlgo, data, n, e, d, p, q, u, hashed) {
6099
+ if (hash.getHashByteLength(hashAlgo) >= n.length) {
6100
+ // Throw here instead of `emsaEncode` below, to provide a clearer and consistent error
6101
+ // e.g. if a 512-bit RSA key is used with a SHA-512 digest.
6102
+ // The size limit is actually slightly different but here we only care about throwing
6103
+ // on common key sizes.
6104
+ throw new Error('Digest size cannot exceed key modulus size');
6105
+ }
6106
+
6095
6107
  if (data && !util.isStream(data)) {
6096
6108
  if (util.getWebCrypto()) {
6097
6109
  try {
@@ -6311,9 +6323,6 @@ async function bnSign(hashAlgo, n, d, hashed) {
6311
6323
  n = uint8ArrayToBigInt(n);
6312
6324
  const m = uint8ArrayToBigInt(emsaEncode(hashAlgo, hashed, byteLength(n)));
6313
6325
  d = uint8ArrayToBigInt(d);
6314
- if (m >= n) {
6315
- throw new Error('Message size cannot exceed modulus size');
6316
- }
6317
6326
  return bigIntToUint8Array(modExp(m, d, n), 'be', byteLength(n));
6318
6327
  }
6319
6328
 
@@ -9280,6 +9289,9 @@ async function generate$4(algo) {
9280
9289
  */
9281
9290
  async function sign$6(algo, hashAlgo, message, publicKey, privateKey, hashed) {
9282
9291
  if (hash.getHashByteLength(hashAlgo) < hash.getHashByteLength(getPreferredHashAlgo$2(algo))) {
9292
+ // Enforce digest sizes:
9293
+ // - Ed25519: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.4-4
9294
+ // - Ed448: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.5-4
9283
9295
  throw new Error('Hash algorithm too weak for EdDSA.');
9284
9296
  }
9285
9297
  switch (algo) {
@@ -9327,6 +9339,9 @@ async function sign$6(algo, hashAlgo, message, publicKey, privateKey, hashed) {
9327
9339
  */
9328
9340
  async function verify$6(algo, hashAlgo, { RS }, m, publicKey, hashed) {
9329
9341
  if (hash.getHashByteLength(hashAlgo) < hash.getHashByteLength(getPreferredHashAlgo$2(algo))) {
9342
+ // Enforce digest sizes:
9343
+ // - Ed25519: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.4-4
9344
+ // - Ed448: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.5-4
9330
9345
  throw new Error('Hash algorithm too weak for EdDSA.');
9331
9346
  }
9332
9347
  switch (algo) {
@@ -9726,14 +9741,15 @@ async function generateEphemeralEncryptionMaterial(algo, recipientA) {
9726
9741
  case enums.publicKey.x25519: {
9727
9742
  const ephemeralSecretKey = getRandomBytes(getPayloadSize(algo));
9728
9743
  const sharedSecret = nacl.scalarMult(ephemeralSecretKey, recipientA);
9744
+ assertNonZeroArray(sharedSecret);
9729
9745
  const { publicKey: ephemeralPublicKey } = nacl.box.keyPair.fromSecretKey(ephemeralSecretKey);
9730
-
9731
9746
  return { ephemeralPublicKey, sharedSecret };
9732
9747
  }
9733
9748
  case enums.publicKey.x448: {
9734
9749
  const x448 = await util.getNobleCurve(enums.publicKey.x448);
9735
9750
  const ephemeralSecretKey = x448.utils.randomPrivateKey();
9736
9751
  const sharedSecret = x448.getSharedSecret(ephemeralSecretKey, recipientA);
9752
+ assertNonZeroArray(sharedSecret);
9737
9753
  const ephemeralPublicKey = x448.getPublicKey(ephemeralSecretKey);
9738
9754
  return { ephemeralPublicKey, sharedSecret };
9739
9755
  }
@@ -9744,11 +9760,15 @@ async function generateEphemeralEncryptionMaterial(algo, recipientA) {
9744
9760
 
9745
9761
  async function recomputeSharedSecret(algo, ephemeralPublicKey, A, k) {
9746
9762
  switch (algo) {
9747
- case enums.publicKey.x25519:
9748
- return nacl.scalarMult(k, ephemeralPublicKey);
9763
+ case enums.publicKey.x25519: {
9764
+ const sharedSecret = nacl.scalarMult(k, ephemeralPublicKey);
9765
+ assertNonZeroArray(sharedSecret);
9766
+ return sharedSecret;
9767
+ }
9749
9768
  case enums.publicKey.x448: {
9750
9769
  const x448 = await util.getNobleCurve(enums.publicKey.x448);
9751
9770
  const sharedSecret = x448.getSharedSecret(k, ephemeralPublicKey);
9771
+ assertNonZeroArray(sharedSecret);
9752
9772
  return sharedSecret;
9753
9773
  }
9754
9774
  default:
@@ -9756,6 +9776,22 @@ async function recomputeSharedSecret(algo, ephemeralPublicKey, A, k) {
9756
9776
  }
9757
9777
  }
9758
9778
 
9779
+ /**
9780
+ * x25519 and x448 produce an all-zero value when given as input a point with small order.
9781
+ * This does not lead to a security issue in the context of ECDH, but it is still unexpected,
9782
+ * hence we throw.
9783
+ * @param {Uint8Array} sharedSecret
9784
+ */
9785
+ function assertNonZeroArray(sharedSecret) {
9786
+ let acc = 0;
9787
+ for (let i = 0; i < sharedSecret.length; i++) {
9788
+ acc |= sharedSecret[i];
9789
+ }
9790
+ if (acc === 0) {
9791
+ throw new Error('Unexpected low order point');
9792
+ }
9793
+ }
9794
+
9759
9795
  var ecdh_x = /*#__PURE__*/Object.freeze({
9760
9796
  __proto__: null,
9761
9797
  decrypt: decrypt$2,
@@ -10464,7 +10500,9 @@ async function sign$4(oid, hashAlgo, message, publicKey, privateKey, hashed) {
10464
10500
  const curve = new CurveWithOID(oid);
10465
10501
  checkPublicPointEnconding(curve, publicKey);
10466
10502
  if (hash.getHashByteLength(hashAlgo) < hash.getHashByteLength(enums.hash.sha256)) {
10503
+ // Enforce digest sizes, since the constraint was already present in RFC4880bis:
10467
10504
  // see https://tools.ietf.org/id/draft-ietf-openpgp-rfc4880bis-10.html#section-15-7.2
10505
+ // and https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.3-3
10468
10506
  throw new Error('Hash algorithm too weak for EdDSA.');
10469
10507
  }
10470
10508
  const { RS: signature } = await sign$6(enums.publicKey.ed25519, hashAlgo, message, publicKey.subarray(1), privateKey, hashed);
@@ -10491,6 +10529,9 @@ async function verify$4(oid, hashAlgo, { r, s }, m, publicKey, hashed) {
10491
10529
  const curve = new CurveWithOID(oid);
10492
10530
  checkPublicPointEnconding(curve, publicKey);
10493
10531
  if (hash.getHashByteLength(hashAlgo) < hash.getHashByteLength(enums.hash.sha256)) {
10532
+ // Enforce digest sizes, since the constraint was already present in RFC4880bis:
10533
+ // see https://tools.ietf.org/id/draft-ietf-openpgp-rfc4880bis-10.html#section-15-7.2
10534
+ // and https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.3-3
10494
10535
  throw new Error('Hash algorithm too weak for EdDSA.');
10495
10536
  }
10496
10537
  const RS = util.concatUint8Array([r, s]);
@@ -10569,7 +10610,7 @@ function encode(message) {
10569
10610
  * @param {Uint8Array} message - message to remove padding from
10570
10611
  * @returns {Uint8Array} Message without padding.
10571
10612
  */
10572
- function decode$1(message) {
10613
+ function decode(message) {
10573
10614
  const len = message.length;
10574
10615
  if (len > 0) {
10575
10616
  const c = message[len - 1];
@@ -10586,7 +10627,7 @@ function decode$1(message) {
10586
10627
 
10587
10628
  var pkcs5 = /*#__PURE__*/Object.freeze({
10588
10629
  __proto__: null,
10589
- decode: decode$1,
10630
+ decode: decode,
10590
10631
  encode: encode
10591
10632
  });
10592
10633
 
@@ -10779,7 +10820,7 @@ async function decrypt$1(oid, kdfParams, V, C, Q, d, fingerprint) {
10779
10820
  try {
10780
10821
  // Work around old go crypto bug and old OpenPGP.js bug, respectively.
10781
10822
  const Z = await kdf(kdfParams.hash, sharedKey, keySize, param, i === 1, i === 2);
10782
- return decode$1(await unwrap(kdfParams.cipher, Z, C));
10823
+ return decode(await unwrap(kdfParams.cipher, Z, C));
10783
10824
  } catch (e) {
10784
10825
  err = e;
10785
10826
  }
@@ -11326,6 +11367,8 @@ function parseSignatureParams(algo, signature) {
11326
11367
  case enums.publicKey.dsa:
11327
11368
  case enums.publicKey.ecdsa:
11328
11369
  {
11370
+ // If the signature payload sizes are unexpected, we will throw on verification,
11371
+ // where we also have access to the OID curve from the key.
11329
11372
  const r = util.readMPI(signature.subarray(read)); read += r.length + 2;
11330
11373
  const s = util.readMPI(signature.subarray(read)); read += s.length + 2;
11331
11374
  return { read, signatureParams: { r, s } };
@@ -11334,12 +11377,11 @@ function parseSignatureParams(algo, signature) {
11334
11377
  // - MPI of an EC point r.
11335
11378
  // - EdDSA value s, in MPI, in the little endian representation
11336
11379
  case enums.publicKey.eddsaLegacy: {
11337
- // When parsing little-endian MPI data, we always need to left-pad it, as done with big-endian values:
11338
- // https://www.ietf.org/archive/id/draft-ietf-openpgp-rfc4880bis-10.html#section-3.2-9
11339
- let r = util.readMPI(signature.subarray(read)); read += r.length + 2;
11340
- r = util.leftPad(r, 32);
11341
- let s = util.readMPI(signature.subarray(read)); read += s.length + 2;
11342
- s = util.leftPad(s, 32);
11380
+ // Only Curve25519Legacy is supported (no Curve448Legacy), but the relevant checks are done on key parsing and signature
11381
+ // verification: if the signature payload sizes are unexpected, we will throw on verification,
11382
+ // where we also have access to the OID curve from the key.
11383
+ const r = util.readMPI(signature.subarray(read)); read += r.length + 2;
11384
+ const s = util.readMPI(signature.subarray(read)); read += s.length + 2;
11343
11385
  return { read, signatureParams: { r, s } };
11344
11386
  }
11345
11387
  // Algorithm-Specific Fields for Ed25519 signatures:
@@ -11400,8 +11442,12 @@ async function verify$1(algo, hashAlgo, signature, publicParams, privateParams,
11400
11442
  }
11401
11443
  case enums.publicKey.eddsaLegacy: {
11402
11444
  const { oid, Q } = publicParams;
11403
- // signature already padded on parsing
11404
- return publicKey.elliptic.eddsaLegacy.verify(oid, hashAlgo, signature, data, Q, hashed);
11445
+ const curveSize = new publicKey.elliptic.CurveWithOID(oid).payloadSize;
11446
+ // When dealing little-endian MPI data, we always need to left-pad it, as done with big-endian values:
11447
+ // https://www.ietf.org/archive/id/draft-ietf-openpgp-rfc4880bis-10.html#section-3.2-9
11448
+ const r = util.leftPad(signature.r, curveSize);
11449
+ const s = util.leftPad(signature.s, curveSize);
11450
+ return publicKey.elliptic.eddsaLegacy.verify(oid, hashAlgo, { r, s }, data, Q, hashed);
11405
11451
  }
11406
11452
  case enums.publicKey.ed25519:
11407
11453
  case enums.publicKey.ed448: {
@@ -13666,849 +13712,6 @@ try {
13666
13712
  }
13667
13713
  catch (e) { }
13668
13714
 
13669
- /*
13670
- node-bzip - a pure-javascript Node.JS module for decoding bzip2 data
13671
-
13672
- Copyright (C) 2012 Eli Skeggs
13673
-
13674
- This library is free software; you can redistribute it and/or
13675
- modify it under the terms of the GNU Lesser General Public
13676
- License as published by the Free Software Foundation; either
13677
- version 2.1 of the License, or (at your option) any later version.
13678
-
13679
- This library is distributed in the hope that it will be useful,
13680
- but WITHOUT ANY WARRANTY; without even the implied warranty of
13681
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13682
- Lesser General Public License for more details.
13683
-
13684
- You should have received a copy of the GNU Lesser General Public
13685
- License along with this library; if not, see
13686
- http://www.gnu.org/licenses/lgpl-2.1.html
13687
-
13688
- Adapted from bzip2.js, copyright 2011 antimatter15 (antimatter15@gmail.com).
13689
-
13690
- Based on micro-bunzip by Rob Landley (rob@landley.net).
13691
-
13692
- Based on bzip2 decompression code by Julian R Seward (jseward@acm.org),
13693
- which also acknowledges contributions by Mike Burrows, David Wheeler,
13694
- Peter Fenwick, Alistair Moffat, Radford Neal, Ian H. Witten,
13695
- Robert Sedgewick, and Jon L. Bentley.
13696
- */
13697
-
13698
- var BITMASK = [0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF];
13699
-
13700
- // offset in bytes
13701
- var BitReader$1 = function(stream) {
13702
- this.stream = stream;
13703
- this.bitOffset = 0;
13704
- this.curByte = 0;
13705
- this.hasByte = false;
13706
- };
13707
-
13708
- BitReader$1.prototype._ensureByte = function() {
13709
- if (!this.hasByte) {
13710
- this.curByte = this.stream.readByte();
13711
- this.hasByte = true;
13712
- }
13713
- };
13714
-
13715
- // reads bits from the buffer
13716
- BitReader$1.prototype.read = function(bits) {
13717
- var result = 0;
13718
- while (bits > 0) {
13719
- this._ensureByte();
13720
- var remaining = 8 - this.bitOffset;
13721
- // if we're in a byte
13722
- if (bits >= remaining) {
13723
- result <<= remaining;
13724
- result |= BITMASK[remaining] & this.curByte;
13725
- this.hasByte = false;
13726
- this.bitOffset = 0;
13727
- bits -= remaining;
13728
- } else {
13729
- result <<= bits;
13730
- var shift = remaining - bits;
13731
- result |= (this.curByte & (BITMASK[bits] << shift)) >> shift;
13732
- this.bitOffset += bits;
13733
- bits = 0;
13734
- }
13735
- }
13736
- return result;
13737
- };
13738
-
13739
- // seek to an arbitrary point in the buffer (expressed in bits)
13740
- BitReader$1.prototype.seek = function(pos) {
13741
- var n_bit = pos % 8;
13742
- var n_byte = (pos - n_bit) / 8;
13743
- this.bitOffset = n_bit;
13744
- this.stream.seek(n_byte);
13745
- this.hasByte = false;
13746
- };
13747
-
13748
- // reads 6 bytes worth of data using the read method
13749
- BitReader$1.prototype.pi = function() {
13750
- var buf = new Uint8Array(6), i;
13751
- for (i = 0; i < buf.length; i++) {
13752
- buf[i] = this.read(8);
13753
- }
13754
- return bufToHex(buf);
13755
- };
13756
-
13757
- function bufToHex(buf) {
13758
- return Array.prototype.map.call(buf, x => ('00' + x.toString(16)).slice(-2)).join('');
13759
- }
13760
-
13761
- var bitreader = BitReader$1;
13762
-
13763
- /* very simple input/output stream interface */
13764
-
13765
- var Stream$1 = function() {
13766
- };
13767
-
13768
- // input streams //////////////
13769
- /** Returns the next byte, or -1 for EOF. */
13770
- Stream$1.prototype.readByte = function() {
13771
- throw new Error("abstract method readByte() not implemented");
13772
- };
13773
- /** Attempts to fill the buffer; returns number of bytes read, or
13774
- * -1 for EOF. */
13775
- Stream$1.prototype.read = function(buffer, bufOffset, length) {
13776
- var bytesRead = 0;
13777
- while (bytesRead < length) {
13778
- var c = this.readByte();
13779
- if (c < 0) { // EOF
13780
- return (bytesRead===0) ? -1 : bytesRead;
13781
- }
13782
- buffer[bufOffset++] = c;
13783
- bytesRead++;
13784
- }
13785
- return bytesRead;
13786
- };
13787
- Stream$1.prototype.seek = function(new_pos) {
13788
- throw new Error("abstract method seek() not implemented");
13789
- };
13790
-
13791
- // output streams ///////////
13792
- Stream$1.prototype.writeByte = function(_byte) {
13793
- throw new Error("abstract method readByte() not implemented");
13794
- };
13795
- Stream$1.prototype.write = function(buffer, bufOffset, length) {
13796
- var i;
13797
- for (i=0; i<length; i++) {
13798
- this.writeByte(buffer[bufOffset++]);
13799
- }
13800
- return length;
13801
- };
13802
- Stream$1.prototype.flush = function() {
13803
- };
13804
-
13805
- var stream = Stream$1;
13806
-
13807
- /* CRC32, used in Bzip2 implementation.
13808
- * This is a port of CRC32.java from the jbzip2 implementation at
13809
- * https://code.google.com/p/jbzip2
13810
- * which is:
13811
- * Copyright (c) 2011 Matthew Francis
13812
- *
13813
- * Permission is hereby granted, free of charge, to any person
13814
- * obtaining a copy of this software and associated documentation
13815
- * files (the "Software"), to deal in the Software without
13816
- * restriction, including without limitation the rights to use,
13817
- * copy, modify, merge, publish, distribute, sublicense, and/or sell
13818
- * copies of the Software, and to permit persons to whom the
13819
- * Software is furnished to do so, subject to the following
13820
- * conditions:
13821
- *
13822
- * The above copyright notice and this permission notice shall be
13823
- * included in all copies or substantial portions of the Software.
13824
- *
13825
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13826
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
13827
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
13828
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
13829
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
13830
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
13831
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
13832
- * OTHER DEALINGS IN THE SOFTWARE.
13833
- * This JavaScript implementation is:
13834
- * Copyright (c) 2013 C. Scott Ananian
13835
- * with the same licensing terms as Matthew Francis' original implementation.
13836
- */
13837
-
13838
- var crc32 = (function() {
13839
-
13840
- /**
13841
- * A static CRC lookup table
13842
- */
13843
- var crc32Lookup = new Uint32Array([
13844
- 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
13845
- 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
13846
- 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
13847
- 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
13848
- 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
13849
- 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
13850
- 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
13851
- 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
13852
- 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
13853
- 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
13854
- 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
13855
- 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
13856
- 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
13857
- 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
13858
- 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
13859
- 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
13860
- 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
13861
- 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
13862
- 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
13863
- 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
13864
- 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
13865
- 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
13866
- 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
13867
- 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
13868
- 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
13869
- 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
13870
- 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
13871
- 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
13872
- 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
13873
- 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
13874
- 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
13875
- 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
13876
- ]);
13877
-
13878
- var CRC32 = function() {
13879
- /**
13880
- * The current CRC
13881
- */
13882
- var crc = 0xffffffff;
13883
-
13884
- /**
13885
- * @return The current CRC
13886
- */
13887
- this.getCRC = function() {
13888
- return (~crc) >>> 0; // return an unsigned value
13889
- };
13890
-
13891
- /**
13892
- * Update the CRC with a single byte
13893
- * @param value The value to update the CRC with
13894
- */
13895
- this.updateCRC = function(value) {
13896
- crc = (crc << 8) ^ crc32Lookup[((crc >>> 24) ^ value) & 0xff];
13897
- };
13898
-
13899
- /**
13900
- * Update the CRC with a sequence of identical bytes
13901
- * @param value The value to update the CRC with
13902
- * @param count The number of bytes
13903
- */
13904
- this.updateCRCRun = function(value, count) {
13905
- while (count-- > 0) {
13906
- crc = (crc << 8) ^ crc32Lookup[((crc >>> 24) ^ value) & 0xff];
13907
- }
13908
- };
13909
- };
13910
- return CRC32;
13911
- })();
13912
-
13913
- /*
13914
- seek-bzip - a pure-javascript module for seeking within bzip2 data
13915
-
13916
- Copyright (C) 2013 C. Scott Ananian
13917
- Copyright (C) 2012 Eli Skeggs
13918
- Copyright (C) 2011 Kevin Kwok
13919
-
13920
- This library is free software; you can redistribute it and/or
13921
- modify it under the terms of the GNU Lesser General Public
13922
- License as published by the Free Software Foundation; either
13923
- version 2.1 of the License, or (at your option) any later version.
13924
-
13925
- This library is distributed in the hope that it will be useful,
13926
- but WITHOUT ANY WARRANTY; without even the implied warranty of
13927
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13928
- Lesser General Public License for more details.
13929
-
13930
- You should have received a copy of the GNU Lesser General Public
13931
- License along with this library; if not, see
13932
- http://www.gnu.org/licenses/lgpl-2.1.html
13933
-
13934
- Adapted from node-bzip, copyright 2012 Eli Skeggs.
13935
- Adapted from bzip2.js, copyright 2011 Kevin Kwok (antimatter15@gmail.com).
13936
-
13937
- Based on micro-bunzip by Rob Landley (rob@landley.net).
13938
-
13939
- Based on bzip2 decompression code by Julian R Seward (jseward@acm.org),
13940
- which also acknowledges contributions by Mike Burrows, David Wheeler,
13941
- Peter Fenwick, Alistair Moffat, Radford Neal, Ian H. Witten,
13942
- Robert Sedgewick, and Jon L. Bentley.
13943
- */
13944
-
13945
- var BitReader = bitreader;
13946
- var Stream = stream;
13947
- var CRC32 = crc32;
13948
-
13949
- var MAX_HUFCODE_BITS = 20;
13950
- var MAX_SYMBOLS = 258;
13951
- var SYMBOL_RUNA = 0;
13952
- var SYMBOL_RUNB = 1;
13953
- var MIN_GROUPS = 2;
13954
- var MAX_GROUPS = 6;
13955
- var GROUP_SIZE = 50;
13956
-
13957
- var WHOLEPI = "314159265359";
13958
- var SQRTPI = "177245385090";
13959
-
13960
- var mtf = function(array, index) {
13961
- var src = array[index], i;
13962
- for (i = index; i > 0; i--) {
13963
- array[i] = array[i-1];
13964
- }
13965
- array[0] = src;
13966
- return src;
13967
- };
13968
-
13969
- var Err = {
13970
- OK: 0,
13971
- LAST_BLOCK: -1,
13972
- NOT_BZIP_DATA: -2,
13973
- UNEXPECTED_INPUT_EOF: -3,
13974
- UNEXPECTED_OUTPUT_EOF: -4,
13975
- DATA_ERROR: -5,
13976
- OUT_OF_MEMORY: -6,
13977
- OBSOLETE_INPUT: -7,
13978
- END_OF_BLOCK: -8
13979
- };
13980
- var ErrorMessages = {};
13981
- ErrorMessages[Err.LAST_BLOCK] = "Bad file checksum";
13982
- ErrorMessages[Err.NOT_BZIP_DATA] = "Not bzip data";
13983
- ErrorMessages[Err.UNEXPECTED_INPUT_EOF] = "Unexpected input EOF";
13984
- ErrorMessages[Err.UNEXPECTED_OUTPUT_EOF] = "Unexpected output EOF";
13985
- ErrorMessages[Err.DATA_ERROR] = "Data error";
13986
- ErrorMessages[Err.OUT_OF_MEMORY] = "Out of memory";
13987
- ErrorMessages[Err.OBSOLETE_INPUT] = "Obsolete (pre 0.9.5) bzip format not supported.";
13988
-
13989
- var _throw = function(status, optDetail) {
13990
- var msg = ErrorMessages[status] || 'unknown error';
13991
- if (optDetail) { msg += ': '+optDetail; }
13992
- var e = new TypeError(msg);
13993
- e.errorCode = status;
13994
- throw e;
13995
- };
13996
-
13997
- var Bunzip = function(inputStream, outputStream) {
13998
- this.writePos = this.writeCurrent = this.writeCount = 0;
13999
-
14000
- this._start_bunzip(inputStream, outputStream);
14001
- };
14002
- Bunzip.prototype._init_block = function() {
14003
- var moreBlocks = this._get_next_block();
14004
- if ( !moreBlocks ) {
14005
- this.writeCount = -1;
14006
- return false; /* no more blocks */
14007
- }
14008
- this.blockCRC = new CRC32();
14009
- return true;
14010
- };
14011
- /* XXX micro-bunzip uses (inputStream, inputBuffer, len) as arguments */
14012
- Bunzip.prototype._start_bunzip = function(inputStream, outputStream) {
14013
- /* Ensure that file starts with "BZh['1'-'9']." */
14014
- var buf = new Uint8Array(4);
14015
- if (inputStream.read(buf, 0, 4) !== 4 ||
14016
- String.fromCharCode(buf[0], buf[1], buf[2]) !== 'BZh')
14017
- _throw(Err.NOT_BZIP_DATA, 'bad magic');
14018
-
14019
- var level = buf[3] - 0x30;
14020
- if (level < 1 || level > 9)
14021
- _throw(Err.NOT_BZIP_DATA, 'level out of range');
14022
-
14023
- this.reader = new BitReader(inputStream);
14024
-
14025
- /* Fourth byte (ascii '1'-'9'), indicates block size in units of 100k of
14026
- uncompressed data. Allocate intermediate buffer for block. */
14027
- this.dbufSize = 100000 * level;
14028
- this.nextoutput = 0;
14029
- this.outputStream = outputStream;
14030
- this.streamCRC = 0;
14031
- };
14032
- Bunzip.prototype._get_next_block = function() {
14033
- var i, j, k;
14034
- var reader = this.reader;
14035
- // this is get_next_block() function from micro-bunzip:
14036
- /* Read in header signature and CRC, then validate signature.
14037
- (last block signature means CRC is for whole file, return now) */
14038
- var h = reader.pi();
14039
- if (h === SQRTPI) { // last block
14040
- return false; /* no more blocks */
14041
- }
14042
- if (h !== WHOLEPI)
14043
- _throw(Err.NOT_BZIP_DATA);
14044
- this.targetBlockCRC = reader.read(32) >>> 0; // (convert to unsigned)
14045
- this.streamCRC = (this.targetBlockCRC ^
14046
- ((this.streamCRC << 1) | (this.streamCRC>>>31))) >>> 0;
14047
- /* We can add support for blockRandomised if anybody complains. There was
14048
- some code for this in busybox 1.0.0-pre3, but nobody ever noticed that
14049
- it didn't actually work. */
14050
- if (reader.read(1))
14051
- _throw(Err.OBSOLETE_INPUT);
14052
- var origPointer = reader.read(24);
14053
- if (origPointer > this.dbufSize)
14054
- _throw(Err.DATA_ERROR, 'initial position out of bounds');
14055
- /* mapping table: if some byte values are never used (encoding things
14056
- like ascii text), the compression code removes the gaps to have fewer
14057
- symbols to deal with, and writes a sparse bitfield indicating which
14058
- values were present. We make a translation table to convert the symbols
14059
- back to the corresponding bytes. */
14060
- var t = reader.read(16);
14061
- var symToByte = new Uint8Array(256), symTotal = 0;
14062
- for (i = 0; i < 16; i++) {
14063
- if (t & (1 << (0xF - i))) {
14064
- var o = i * 16;
14065
- k = reader.read(16);
14066
- for (j = 0; j < 16; j++)
14067
- if (k & (1 << (0xF - j)))
14068
- symToByte[symTotal++] = o + j;
14069
- }
14070
- }
14071
-
14072
- /* How many different huffman coding groups does this block use? */
14073
- var groupCount = reader.read(3);
14074
- if (groupCount < MIN_GROUPS || groupCount > MAX_GROUPS)
14075
- _throw(Err.DATA_ERROR);
14076
- /* nSelectors: Every GROUP_SIZE many symbols we select a new huffman coding
14077
- group. Read in the group selector list, which is stored as MTF encoded
14078
- bit runs. (MTF=Move To Front, as each value is used it's moved to the
14079
- start of the list.) */
14080
- var nSelectors = reader.read(15);
14081
- if (nSelectors === 0)
14082
- _throw(Err.DATA_ERROR);
14083
-
14084
- var mtfSymbol = new Uint8Array(256);
14085
- for (i = 0; i < groupCount; i++)
14086
- mtfSymbol[i] = i;
14087
-
14088
- var selectors = new Uint8Array(nSelectors); // was 32768...
14089
-
14090
- for (i = 0; i < nSelectors; i++) {
14091
- /* Get next value */
14092
- for (j = 0; reader.read(1); j++)
14093
- if (j >= groupCount) _throw(Err.DATA_ERROR);
14094
- /* Decode MTF to get the next selector */
14095
- selectors[i] = mtf(mtfSymbol, j);
14096
- }
14097
-
14098
- /* Read the huffman coding tables for each group, which code for symTotal
14099
- literal symbols, plus two run symbols (RUNA, RUNB) */
14100
- var symCount = symTotal + 2;
14101
- var groups = [], hufGroup;
14102
- for (j = 0; j < groupCount; j++) {
14103
- var length = new Uint8Array(symCount), temp = new Uint16Array(MAX_HUFCODE_BITS + 1);
14104
- /* Read huffman code lengths for each symbol. They're stored in
14105
- a way similar to mtf; record a starting value for the first symbol,
14106
- and an offset from the previous value for everys symbol after that. */
14107
- t = reader.read(5); // lengths
14108
- for (i = 0; i < symCount; i++) {
14109
- for (;;) {
14110
- if (t < 1 || t > MAX_HUFCODE_BITS) _throw(Err.DATA_ERROR);
14111
- /* If first bit is 0, stop. Else second bit indicates whether
14112
- to increment or decrement the value. */
14113
- if(!reader.read(1))
14114
- break;
14115
- if(!reader.read(1))
14116
- t++;
14117
- else
14118
- t--;
14119
- }
14120
- length[i] = t;
14121
- }
14122
-
14123
- /* Find largest and smallest lengths in this group */
14124
- var minLen, maxLen;
14125
- minLen = maxLen = length[0];
14126
- for (i = 1; i < symCount; i++) {
14127
- if (length[i] > maxLen)
14128
- maxLen = length[i];
14129
- else if (length[i] < minLen)
14130
- minLen = length[i];
14131
- }
14132
-
14133
- /* Calculate permute[], base[], and limit[] tables from length[].
14134
- *
14135
- * permute[] is the lookup table for converting huffman coded symbols
14136
- * into decoded symbols. base[] is the amount to subtract from the
14137
- * value of a huffman symbol of a given length when using permute[].
14138
- *
14139
- * limit[] indicates the largest numerical value a symbol with a given
14140
- * number of bits can have. This is how the huffman codes can vary in
14141
- * length: each code with a value>limit[length] needs another bit.
14142
- */
14143
- hufGroup = {};
14144
- groups.push(hufGroup);
14145
- hufGroup.permute = new Uint16Array(MAX_SYMBOLS);
14146
- hufGroup.limit = new Uint32Array(MAX_HUFCODE_BITS + 2);
14147
- hufGroup.base = new Uint32Array(MAX_HUFCODE_BITS + 1);
14148
- hufGroup.minLen = minLen;
14149
- hufGroup.maxLen = maxLen;
14150
- /* Calculate permute[]. Concurently, initialize temp[] and limit[]. */
14151
- var pp = 0;
14152
- for (i = minLen; i <= maxLen; i++) {
14153
- temp[i] = hufGroup.limit[i] = 0;
14154
- for (t = 0; t < symCount; t++)
14155
- if (length[t] === i)
14156
- hufGroup.permute[pp++] = t;
14157
- }
14158
- /* Count symbols coded for at each bit length */
14159
- for (i = 0; i < symCount; i++)
14160
- temp[length[i]]++;
14161
- /* Calculate limit[] (the largest symbol-coding value at each bit
14162
- * length, which is (previous limit<<1)+symbols at this level), and
14163
- * base[] (number of symbols to ignore at each bit length, which is
14164
- * limit minus the cumulative count of symbols coded for already). */
14165
- pp = t = 0;
14166
- for (i = minLen; i < maxLen; i++) {
14167
- pp += temp[i];
14168
- /* We read the largest possible symbol size and then unget bits
14169
- after determining how many we need, and those extra bits could
14170
- be set to anything. (They're noise from future symbols.) At
14171
- each level we're really only interested in the first few bits,
14172
- so here we set all the trailing to-be-ignored bits to 1 so they
14173
- don't affect the value>limit[length] comparison. */
14174
- hufGroup.limit[i] = pp - 1;
14175
- pp <<= 1;
14176
- t += temp[i];
14177
- hufGroup.base[i + 1] = pp - t;
14178
- }
14179
- hufGroup.limit[maxLen + 1] = Number.MAX_VALUE; /* Sentinal value for reading next sym. */
14180
- hufGroup.limit[maxLen] = pp + temp[maxLen] - 1;
14181
- hufGroup.base[minLen] = 0;
14182
- }
14183
- /* We've finished reading and digesting the block header. Now read this
14184
- block's huffman coded symbols from the file and undo the huffman coding
14185
- and run length encoding, saving the result into dbuf[dbufCount++]=uc */
14186
-
14187
- /* Initialize symbol occurrence counters and symbol Move To Front table */
14188
- var byteCount = new Uint32Array(256);
14189
- for (i = 0; i < 256; i++)
14190
- mtfSymbol[i] = i;
14191
- /* Loop through compressed symbols. */
14192
- var runPos = 0, dbufCount = 0, selector = 0, uc;
14193
- var dbuf = this.dbuf = new Uint32Array(this.dbufSize);
14194
- symCount = 0;
14195
- for (;;) {
14196
- /* Determine which huffman coding group to use. */
14197
- if (!(symCount--)) {
14198
- symCount = GROUP_SIZE - 1;
14199
- if (selector >= nSelectors) { _throw(Err.DATA_ERROR); }
14200
- hufGroup = groups[selectors[selector++]];
14201
- }
14202
- /* Read next huffman-coded symbol. */
14203
- i = hufGroup.minLen;
14204
- j = reader.read(i);
14205
- for (;;i++) {
14206
- if (i > hufGroup.maxLen) { _throw(Err.DATA_ERROR); }
14207
- if (j <= hufGroup.limit[i])
14208
- break;
14209
- j = (j << 1) | reader.read(1);
14210
- }
14211
- /* Huffman decode value to get nextSym (with bounds checking) */
14212
- j -= hufGroup.base[i];
14213
- if (j < 0 || j >= MAX_SYMBOLS) { _throw(Err.DATA_ERROR); }
14214
- var nextSym = hufGroup.permute[j];
14215
- /* We have now decoded the symbol, which indicates either a new literal
14216
- byte, or a repeated run of the most recent literal byte. First,
14217
- check if nextSym indicates a repeated run, and if so loop collecting
14218
- how many times to repeat the last literal. */
14219
- if (nextSym === SYMBOL_RUNA || nextSym === SYMBOL_RUNB) {
14220
- /* If this is the start of a new run, zero out counter */
14221
- if (!runPos){
14222
- runPos = 1;
14223
- t = 0;
14224
- }
14225
- /* Neat trick that saves 1 symbol: instead of or-ing 0 or 1 at
14226
- each bit position, add 1 or 2 instead. For example,
14227
- 1011 is 1<<0 + 1<<1 + 2<<2. 1010 is 2<<0 + 2<<1 + 1<<2.
14228
- You can make any bit pattern that way using 1 less symbol than
14229
- the basic or 0/1 method (except all bits 0, which would use no
14230
- symbols, but a run of length 0 doesn't mean anything in this
14231
- context). Thus space is saved. */
14232
- if (nextSym === SYMBOL_RUNA)
14233
- t += runPos;
14234
- else
14235
- t += 2 * runPos;
14236
- runPos <<= 1;
14237
- continue;
14238
- }
14239
- /* When we hit the first non-run symbol after a run, we now know
14240
- how many times to repeat the last literal, so append that many
14241
- copies to our buffer of decoded symbols (dbuf) now. (The last
14242
- literal used is the one at the head of the mtfSymbol array.) */
14243
- if (runPos){
14244
- runPos = 0;
14245
- if (dbufCount + t > this.dbufSize) { _throw(Err.DATA_ERROR); }
14246
- uc = symToByte[mtfSymbol[0]];
14247
- byteCount[uc] += t;
14248
- while (t--)
14249
- dbuf[dbufCount++] = uc;
14250
- }
14251
- /* Is this the terminating symbol? */
14252
- if (nextSym > symTotal)
14253
- break;
14254
- /* At this point, nextSym indicates a new literal character. Subtract
14255
- one to get the position in the MTF array at which this literal is
14256
- currently to be found. (Note that the result can't be -1 or 0,
14257
- because 0 and 1 are RUNA and RUNB. But another instance of the
14258
- first symbol in the mtf array, position 0, would have been handled
14259
- as part of a run above. Therefore 1 unused mtf position minus
14260
- 2 non-literal nextSym values equals -1.) */
14261
- if (dbufCount >= this.dbufSize) { _throw(Err.DATA_ERROR); }
14262
- i = nextSym - 1;
14263
- uc = mtf(mtfSymbol, i);
14264
- uc = symToByte[uc];
14265
- /* We have our literal byte. Save it into dbuf. */
14266
- byteCount[uc]++;
14267
- dbuf[dbufCount++] = uc;
14268
- }
14269
- /* At this point, we've read all the huffman-coded symbols (and repeated
14270
- runs) for this block from the input stream, and decoded them into the
14271
- intermediate buffer. There are dbufCount many decoded bytes in dbuf[].
14272
- Now undo the Burrows-Wheeler transform on dbuf.
14273
- See http://dogma.net/markn/articles/bwt/bwt.htm
14274
- */
14275
- if (origPointer < 0 || origPointer >= dbufCount) { _throw(Err.DATA_ERROR); }
14276
- /* Turn byteCount into cumulative occurrence counts of 0 to n-1. */
14277
- j = 0;
14278
- for (i = 0; i < 256; i++) {
14279
- k = j + byteCount[i];
14280
- byteCount[i] = j;
14281
- j = k;
14282
- }
14283
- /* Figure out what order dbuf would be in if we sorted it. */
14284
- for (i = 0; i < dbufCount; i++) {
14285
- uc = dbuf[i] & 0xff;
14286
- dbuf[byteCount[uc]] |= (i << 8);
14287
- byteCount[uc]++;
14288
- }
14289
- /* Decode first byte by hand to initialize "previous" byte. Note that it
14290
- doesn't get output, and if the first three characters are identical
14291
- it doesn't qualify as a run (hence writeRunCountdown=5). */
14292
- var pos = 0, current = 0, run = 0;
14293
- if (dbufCount) {
14294
- pos = dbuf[origPointer];
14295
- current = (pos & 0xff);
14296
- pos >>= 8;
14297
- run = -1;
14298
- }
14299
- this.writePos = pos;
14300
- this.writeCurrent = current;
14301
- this.writeCount = dbufCount;
14302
- this.writeRun = run;
14303
-
14304
- return true; /* more blocks to come */
14305
- };
14306
- /* Undo burrows-wheeler transform on intermediate buffer to produce output.
14307
- If start_bunzip was initialized with out_fd=-1, then up to len bytes of
14308
- data are written to outbuf. Return value is number of bytes written or
14309
- error (all errors are negative numbers). If out_fd!=-1, outbuf and len
14310
- are ignored, data is written to out_fd and return is RETVAL_OK or error.
14311
- */
14312
- Bunzip.prototype._read_bunzip = function(outputBuffer, len) {
14313
- var copies, previous, outbyte;
14314
- /* james@jamestaylor.org: writeCount goes to -1 when the buffer is fully
14315
- decoded, which results in this returning RETVAL_LAST_BLOCK, also
14316
- equal to -1... Confusing, I'm returning 0 here to indicate no
14317
- bytes written into the buffer */
14318
- if (this.writeCount < 0) { return 0; }
14319
- var dbuf = this.dbuf, pos = this.writePos, current = this.writeCurrent;
14320
- var dbufCount = this.writeCount; this.outputsize;
14321
- var run = this.writeRun;
14322
-
14323
- while (dbufCount) {
14324
- dbufCount--;
14325
- previous = current;
14326
- pos = dbuf[pos];
14327
- current = pos & 0xff;
14328
- pos >>= 8;
14329
- if (run++ === 3){
14330
- copies = current;
14331
- outbyte = previous;
14332
- current = -1;
14333
- } else {
14334
- copies = 1;
14335
- outbyte = current;
14336
- }
14337
- this.blockCRC.updateCRCRun(outbyte, copies);
14338
- while (copies--) {
14339
- this.outputStream.writeByte(outbyte);
14340
- this.nextoutput++;
14341
- }
14342
- if (current != previous)
14343
- run = 0;
14344
- }
14345
- this.writeCount = dbufCount;
14346
- // check CRC
14347
- if (this.blockCRC.getCRC() !== this.targetBlockCRC) {
14348
- _throw(Err.DATA_ERROR, "Bad block CRC "+
14349
- "(got "+this.blockCRC.getCRC().toString(16)+
14350
- " expected "+this.targetBlockCRC.toString(16)+")");
14351
- }
14352
- return this.nextoutput;
14353
- };
14354
-
14355
- var coerceInputStream = function(input) {
14356
- if ('readByte' in input) { return input; }
14357
- var inputStream = new Stream();
14358
- inputStream.pos = 0;
14359
- inputStream.readByte = function() { return input[this.pos++]; };
14360
- inputStream.seek = function(pos) { this.pos = pos; };
14361
- inputStream.eof = function() { return this.pos >= input.length; };
14362
- return inputStream;
14363
- };
14364
- var coerceOutputStream = function(output) {
14365
- var outputStream = new Stream();
14366
- var resizeOk = true;
14367
- if (output) {
14368
- if (typeof(output)==='number') {
14369
- outputStream.buffer = new Uint8Array(output);
14370
- resizeOk = false;
14371
- } else if ('writeByte' in output) {
14372
- return output;
14373
- } else {
14374
- outputStream.buffer = output;
14375
- resizeOk = false;
14376
- }
14377
- } else {
14378
- outputStream.buffer = new Uint8Array(16384);
14379
- }
14380
- outputStream.pos = 0;
14381
- outputStream.writeByte = function(_byte) {
14382
- if (resizeOk && this.pos >= this.buffer.length) {
14383
- var newBuffer = new Uint8Array(this.buffer.length*2);
14384
- newBuffer.set(this.buffer);
14385
- this.buffer = newBuffer;
14386
- }
14387
- this.buffer[this.pos++] = _byte;
14388
- };
14389
- outputStream.getBuffer = function() {
14390
- // trim buffer
14391
- if (this.pos !== this.buffer.length) {
14392
- if (!resizeOk)
14393
- throw new TypeError('outputsize does not match decoded input');
14394
- var newBuffer = new Uint8Array(this.pos);
14395
- newBuffer.set(this.buffer.subarray(0, this.pos));
14396
- this.buffer = newBuffer;
14397
- }
14398
- return this.buffer;
14399
- };
14400
- outputStream._coerced = true;
14401
- return outputStream;
14402
- };
14403
-
14404
- /* Static helper functions */
14405
- // 'input' can be a stream or a buffer
14406
- // 'output' can be a stream or a buffer or a number (buffer size)
14407
- const decode = function(input, output, multistream) {
14408
- // make a stream from a buffer, if necessary
14409
- var inputStream = coerceInputStream(input);
14410
- var outputStream = coerceOutputStream(output);
14411
-
14412
- var bz = new Bunzip(inputStream, outputStream);
14413
- while (true) {
14414
- if ('eof' in inputStream && inputStream.eof()) break;
14415
- if (bz._init_block()) {
14416
- bz._read_bunzip();
14417
- } else {
14418
- var targetStreamCRC = bz.reader.read(32) >>> 0; // (convert to unsigned)
14419
- if (targetStreamCRC !== bz.streamCRC) {
14420
- _throw(Err.DATA_ERROR, "Bad stream CRC "+
14421
- "(got "+bz.streamCRC.toString(16)+
14422
- " expected "+targetStreamCRC.toString(16)+")");
14423
- }
14424
- if (multistream &&
14425
- 'eof' in inputStream &&
14426
- !inputStream.eof()) {
14427
- // note that start_bunzip will also resync the bit reader to next byte
14428
- bz._start_bunzip(inputStream, outputStream);
14429
- } else break;
14430
- }
14431
- }
14432
- if ('getBuffer' in outputStream)
14433
- return outputStream.getBuffer();
14434
- };
14435
- const decodeBlock = function(input, pos, output) {
14436
- // make a stream from a buffer, if necessary
14437
- var inputStream = coerceInputStream(input);
14438
- var outputStream = coerceOutputStream(output);
14439
- var bz = new Bunzip(inputStream, outputStream);
14440
- bz.reader.seek(pos);
14441
- /* Fill the decode buffer for the block */
14442
- var moreBlocks = bz._get_next_block();
14443
- if (moreBlocks) {
14444
- /* Init the CRC for writing */
14445
- bz.blockCRC = new CRC32();
14446
-
14447
- /* Zero this so the current byte from before the seek is not written */
14448
- bz.writeCopies = 0;
14449
-
14450
- /* Decompress the block and write to stdout */
14451
- bz._read_bunzip();
14452
- // XXX keep writing?
14453
- }
14454
- if ('getBuffer' in outputStream)
14455
- return outputStream.getBuffer();
14456
- };
14457
- /* Reads bzip2 file from stream or buffer `input`, and invoke
14458
- * `callback(position, size)` once for each bzip2 block,
14459
- * where position gives the starting position (in *bits*)
14460
- * and size gives uncompressed size of the block (in *bytes*). */
14461
- const table = function(input, callback, multistream) {
14462
- // make a stream from a buffer, if necessary
14463
- var inputStream = new Stream();
14464
- inputStream.delegate = coerceInputStream(input);
14465
- inputStream.pos = 0;
14466
- inputStream.readByte = function() {
14467
- this.pos++;
14468
- return this.delegate.readByte();
14469
- };
14470
- if (inputStream.delegate.eof) {
14471
- inputStream.eof = inputStream.delegate.eof.bind(inputStream.delegate);
14472
- }
14473
- var outputStream = new Stream();
14474
- outputStream.pos = 0;
14475
- outputStream.writeByte = function() { this.pos++; };
14476
-
14477
- var bz = new Bunzip(inputStream, outputStream);
14478
- var blockSize = bz.dbufSize;
14479
- while (true) {
14480
- if ('eof' in inputStream && inputStream.eof()) break;
14481
-
14482
- var position = inputStream.pos*8 + bz.reader.bitOffset;
14483
- if (bz.reader.hasByte) { position -= 8; }
14484
-
14485
- if (bz._init_block()) {
14486
- var start = outputStream.pos;
14487
- bz._read_bunzip();
14488
- callback(position, outputStream.pos - start);
14489
- } else {
14490
- bz.reader.read(32); // (but we ignore the crc)
14491
- if (multistream &&
14492
- 'eof' in inputStream &&
14493
- !inputStream.eof()) {
14494
- // note that start_bunzip will also resync the bit reader to next byte
14495
- bz._start_bunzip(inputStream, outputStream);
14496
- console.assert(bz.dbufSize === blockSize,
14497
- "shouldn't change block size within multistream file");
14498
- } else break;
14499
- }
14500
- }
14501
- };
14502
-
14503
- var lib = {
14504
- Bunzip,
14505
- Stream,
14506
- Err,
14507
- decode,
14508
- decodeBlock,
14509
- table
14510
- };
14511
-
14512
13715
  // GPG4Browsers - An OpenPGP implementation in javascript
14513
13716
  // Copyright (C) 2011 Recurity Labs GmbH
14514
13717
  //
@@ -16161,12 +15364,12 @@ class CompressedDataPacket {
16161
15364
  */
16162
15365
  async decompress(config$1 = config) {
16163
15366
  const compressionName = enums.read(enums.compression, this.algorithm);
16164
- const decompressionFn = decompress_fns[compressionName];
15367
+ const decompressionFn = decompress_fns[compressionName]; // bzip decompression is async
16165
15368
  if (!decompressionFn) {
16166
15369
  throw new Error(`${compressionName} decompression not supported`);
16167
15370
  }
16168
15371
 
16169
- this.packets = await PacketList.fromBinary(decompressionFn(this.compressed), allowedPackets$5, config$1);
15372
+ this.packets = await PacketList.fromBinary(await decompressionFn(this.compressed), allowedPackets$5, config$1);
16170
15373
  }
16171
15374
 
16172
15375
  /**
@@ -16253,9 +15456,10 @@ function zlib(compressionStreamInstantiator, ZlibStreamedConstructor) {
16253
15456
  };
16254
15457
  }
16255
15458
 
16256
- function bzip2(func) {
16257
- return function(data) {
16258
- return fromAsync(async () => func(await readToEnd(data)));
15459
+ function bzip2Decompress() {
15460
+ return async function(data) {
15461
+ const { decode: bunzipDecode } = await import('./seek-bzip.mjs').then(function (n) { return n.i; });
15462
+ return fromAsync(async () => bunzipDecode(await readToEnd(data)));
16259
15463
  };
16260
15464
  }
16261
15465
 
@@ -16280,7 +15484,7 @@ const decompress_fns = {
16280
15484
  uncompressed: data => data,
16281
15485
  zip: /*#__PURE__*/ zlib(getCompressionStreamInstantiators('deflate-raw').decompressor, Inflate),
16282
15486
  zlib: /*#__PURE__*/ zlib(getCompressionStreamInstantiators('deflate').decompressor, Unzlib),
16283
- bzip2: /*#__PURE__*/ bzip2(lib.decode)
15487
+ bzip2: /*#__PURE__*/ bzip2Decompress() // NB: async due to dynamic lib import
16284
15488
  };
16285
15489
 
16286
15490
  // GPG4Browsers - An OpenPGP implementation in javascript
@@ -16400,6 +15604,16 @@ class SymEncryptedIntegrityProtectedDataPacket {
16400
15604
  * @async
16401
15605
  */
16402
15606
  async encrypt(sessionKeyAlgorithm, key, config$1 = config) {
15607
+ // We check that the session key size matches the one expected by the symmetric algorithm.
15608
+ // This is especially important for SEIPDv2 session keys, as a key derivation step is run where the resulting key will always match the expected cipher size,
15609
+ // but we want to ensure that the input key isn't e.g. too short.
15610
+ // The check is done here, instead of on encrypted session key (ESK) encryption, because v6 ESK packets do not store the session key algorithm,
15611
+ // which is instead included in the SEIPDv2 data.
15612
+ const { blockSize, keySize } = mod.getCipherParams(sessionKeyAlgorithm);
15613
+ if (key.length !== keySize) {
15614
+ throw new Error('Unexpected session key size');
15615
+ }
15616
+
16403
15617
  let bytes = this.packets.write();
16404
15618
  if (isArrayStream(bytes)) bytes = await readToEnd(bytes);
16405
15619
 
@@ -16410,8 +15624,6 @@ class SymEncryptedIntegrityProtectedDataPacket {
16410
15624
  this.chunkSizeByte = config$1.aeadChunkSizeByte;
16411
15625
  this.encrypted = await runAEAD(this, 'encrypt', key, bytes);
16412
15626
  } else {
16413
- const { blockSize } = mod.getCipherParams(sessionKeyAlgorithm);
16414
-
16415
15627
  const prefix = await mod.getPrefixRandom(sessionKeyAlgorithm);
16416
15628
  const mdc = new Uint8Array([0xD3, 0x14]); // modification detection code packet
16417
15629
 
@@ -16434,11 +15646,24 @@ class SymEncryptedIntegrityProtectedDataPacket {
16434
15646
  * @async
16435
15647
  */
16436
15648
  async decrypt(sessionKeyAlgorithm, key, config$1 = config) {
15649
+ // We check that the session key size matches the one expected by the symmetric algorithm.
15650
+ // This is especially important for SEIPDv2 session keys, as a key derivation step is run where the resulting key will always match the expected cipher size,
15651
+ // but we want to ensure that the input key isn't e.g. too short.
15652
+ // The check is done here, instead of on encrypted session key (ESK) decryption, because v6 ESK packets do not store the session key algorithm,
15653
+ // which is instead included in the SEIPDv2 data.
15654
+ if (key.length !== mod.getCipherParams(sessionKeyAlgorithm).keySize) {
15655
+ throw new Error('Unexpected session key size');
15656
+ }
15657
+
16437
15658
  let encrypted = clone(this.encrypted);
16438
15659
  if (isArrayStream(encrypted)) encrypted = await readToEnd(encrypted);
16439
15660
 
16440
15661
  let packetbytes;
16441
15662
  if (this.version === 2) {
15663
+ if (this.cipherAlgorithm !== sessionKeyAlgorithm) {
15664
+ // sanity check
15665
+ throw new Error('Unexpected session key algorithm');
15666
+ }
16442
15667
  packetbytes = await runAEAD(this, 'decrypt', key, encrypted);
16443
15668
  } else {
16444
15669
  const { blockSize } = mod.getCipherParams(sessionKeyAlgorithm);
@@ -16906,11 +16131,14 @@ class PublicKeyEncryptedSessionKeyPacket {
16906
16131
 
16907
16132
  const { sessionKey, sessionKeyAlgorithm } = decodeSessionKey(this.version, this.publicKeyAlgorithm, decryptedData, randomSessionKey);
16908
16133
 
16909
- // v3 Montgomery curves have cleartext cipher algo
16910
- if (this.version === 3 && (
16911
- this.publicKeyAlgorithm !== enums.publicKey.x25519 && this.publicKeyAlgorithm !== enums.publicKey.x448)
16912
- ) {
16913
- this.sessionKeyAlgorithm = sessionKeyAlgorithm;
16134
+ if (this.version === 3) {
16135
+ // v3 Montgomery curves have cleartext cipher algo
16136
+ const hasEncryptedAlgo = this.publicKeyAlgorithm !== enums.publicKey.x25519 && this.publicKeyAlgorithm !== enums.publicKey.x448;
16137
+ this.sessionKeyAlgorithm = hasEncryptedAlgo ? sessionKeyAlgorithm : this.sessionKeyAlgorithm;
16138
+
16139
+ if (sessionKey.length !== mod.getCipherParams(this.sessionKeyAlgorithm).keySize) {
16140
+ throw new Error('Unexpected session key size');
16141
+ }
16914
16142
  }
16915
16143
  this.sessionKey = sessionKey;
16916
16144
  }
@@ -17040,7 +16268,7 @@ class SymEncryptedSessionKeyPacket {
17040
16268
  * Algorithm to encrypt the message with
17041
16269
  * @type {enums.symmetric}
17042
16270
  */
17043
- this.sessionKeyAlgorithm = enums.symmetric.aes256;
16271
+ this.sessionKeyAlgorithm = null;
17044
16272
  /**
17045
16273
  * AEAD mode to encrypt the session key with (if AEAD protection is enabled)
17046
16274
  * @type {enums.aead}
@@ -17161,7 +16389,11 @@ class SymEncryptedSessionKeyPacket {
17161
16389
 
17162
16390
  this.sessionKeyAlgorithm = enums.write(enums.symmetric, decrypted[0]);
17163
16391
  this.sessionKey = decrypted.subarray(1, decrypted.length);
16392
+ if (this.sessionKey.length !== mod.getCipherParams(this.sessionKeyAlgorithm).keySize) {
16393
+ throw new Error('Unexpected session key size');
16394
+ }
17164
16395
  } else {
16396
+ // session key size is checked as part of SEIPDv2 decryption, where we know the expected symmetric algo
17165
16397
  this.sessionKey = key;
17166
16398
  }
17167
16399
  }
@@ -18810,7 +18042,7 @@ async function createBindingSignature(subkey, primaryKey, options, config) {
18810
18042
  const signatureProperties = { signatureType: enums.signature.subkeyBinding };
18811
18043
  if (options.sign) {
18812
18044
  signatureProperties.keyFlags = [enums.keyFlags.signData];
18813
- signatureProperties.embeddedSignature = await createSignaturePacket(dataToSign, null, subkey, {
18045
+ signatureProperties.embeddedSignature = await createSignaturePacket(dataToSign, [], subkey, {
18814
18046
  signatureType: enums.signature.keyBinding
18815
18047
  }, options.date, undefined, undefined, undefined, config);
18816
18048
  } else {
@@ -18822,41 +18054,95 @@ async function createBindingSignature(subkey, primaryKey, options, config) {
18822
18054
  signatureProperties.keyExpirationTime = options.keyExpirationTime;
18823
18055
  signatureProperties.keyNeverExpires = false;
18824
18056
  }
18825
- const subkeySignaturePacket = await createSignaturePacket(dataToSign, null, primaryKey, signatureProperties, options.date, undefined, undefined, undefined, config);
18057
+ const subkeySignaturePacket = await createSignaturePacket(dataToSign, [], primaryKey, signatureProperties, options.date, undefined, undefined, undefined, config);
18826
18058
  return subkeySignaturePacket;
18827
18059
  }
18828
18060
 
18829
18061
  /**
18830
- * Returns the preferred signature hash algorithm of a key
18831
- * @param {Key} [key] - The key to get preferences from
18832
- * @param {SecretKeyPacket|SecretSubkeyPacket} keyPacket - key packet used for signing
18062
+ * Returns the preferred signature hash algorithm for a set of keys.
18063
+ * @param {Array<Key>} [targetKeys] - The keys to get preferences from
18064
+ * @param {SecretKeyPacket|SecretSubkeyPacket} signingKeyPacket - key packet used for signing
18833
18065
  * @param {Date} [date] - Use the given date for verification instead of the current time
18834
- * @param {Object} [userID] - User ID
18066
+ * @param {Object} [targetUserID] - User IDs corresponding to `targetKeys` to get preferences from
18835
18067
  * @param {Object} config - full configuration
18836
18068
  * @returns {Promise<enums.hash>}
18837
18069
  * @async
18838
18070
  */
18839
- async function getPreferredHashAlgo(key, keyPacket, date = new Date(), userID = {}, config) {
18840
- let hashAlgo = config.preferredHashAlgorithm;
18841
- let prefAlgo = hashAlgo;
18842
- if (key) {
18843
- const selfCertification = await key.getPrimarySelfSignature(date, userID, config);
18844
- if (selfCertification.preferredHashAlgorithms) {
18845
- [prefAlgo] = selfCertification.preferredHashAlgorithms;
18846
- hashAlgo = mod.hash.getHashByteLength(hashAlgo) <= mod.hash.getHashByteLength(prefAlgo) ?
18847
- prefAlgo : hashAlgo;
18071
+ async function getPreferredHashAlgo(targetKeys, signingKeyPacket, date = new Date(), targetUserIDs = [], config) {
18072
+ /**
18073
+ * If `preferredSenderAlgo` appears in the prefs of all recipients, we pick it; otherwise, we use the
18074
+ * strongest supported algo (`defaultAlgo` is always implicitly supported by all keys).
18075
+ * if no keys are available, `preferredSenderAlgo` is returned.
18076
+ * For ECC signing key, the curve preferred hash is taken into account as well (see logic below).
18077
+ */
18078
+ const defaultAlgo = enums.hash.sha256; // MUST implement
18079
+ const preferredSenderAlgo = config.preferredHashAlgorithm;
18080
+
18081
+ const supportedAlgosPerTarget = await Promise.all(targetKeys.map(async (key, i) => {
18082
+ const selfCertification = await key.getPrimarySelfSignature(date, targetUserIDs[i], config);
18083
+ const targetPrefs = selfCertification.preferredHashAlgorithms;
18084
+ return targetPrefs;
18085
+ }));
18086
+ const supportedAlgosMap = new Map(); // use Map over object to preserve numeric keys
18087
+ for (const supportedAlgos of supportedAlgosPerTarget) {
18088
+ for (const hashAlgo of supportedAlgos) {
18089
+ try {
18090
+ // ensure that `hashAlgo` is recognized/implemented by us, otherwise e.g. `getHashByteLength` will throw later on
18091
+ const supportedAlgo = enums.write(enums.hash, hashAlgo);
18092
+ supportedAlgosMap.set(
18093
+ supportedAlgo,
18094
+ supportedAlgosMap.has(supportedAlgo) ? supportedAlgosMap.get(supportedAlgo) + 1 : 1
18095
+ );
18096
+ } catch {}
18848
18097
  }
18849
18098
  }
18850
- switch (keyPacket.algorithm) {
18851
- case enums.publicKey.ecdsa:
18852
- case enums.publicKey.eddsaLegacy:
18853
- case enums.publicKey.ed25519:
18854
- case enums.publicKey.ed448:
18855
- prefAlgo = mod.getPreferredCurveHashAlgo(keyPacket.algorithm, keyPacket.publicParams.oid);
18099
+ const isSupportedHashAlgo = hashAlgo => targetKeys.length === 0 || supportedAlgosMap.get(hashAlgo) === targetKeys.length || hashAlgo === defaultAlgo;
18100
+ const getStrongestSupportedHashAlgo = () => {
18101
+ if (supportedAlgosMap.size === 0) {
18102
+ return defaultAlgo;
18103
+ }
18104
+ const sortedHashAlgos = Array.from(supportedAlgosMap.keys())
18105
+ .filter(hashAlgo => isSupportedHashAlgo(hashAlgo))
18106
+ .sort((algoA, algoB) => mod.hash.getHashByteLength(algoA) - mod.hash.getHashByteLength(algoB));
18107
+ const strongestHashAlgo = sortedHashAlgos[0];
18108
+ // defaultAlgo is always implicilty supported, and might be stronger than the rest
18109
+ return mod.hash.getHashByteLength(strongestHashAlgo) >= mod.hash.getHashByteLength(defaultAlgo) ? strongestHashAlgo : defaultAlgo;
18110
+ };
18111
+
18112
+ const eccAlgos = new Set([
18113
+ enums.publicKey.ecdsa,
18114
+ enums.publicKey.eddsaLegacy,
18115
+ enums.publicKey.ed25519,
18116
+ enums.publicKey.ed448
18117
+ ]);
18118
+
18119
+ if (eccAlgos.has(signingKeyPacket.algorithm)) {
18120
+ // For ECC, the returned hash algo MUST be at least as strong as `preferredCurveHashAlgo`, see:
18121
+ // - ECDSA: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.2-5
18122
+ // - EdDSALegacy: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.3-3
18123
+ // - Ed25519: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.4-4
18124
+ // - Ed448: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.5-4
18125
+ // Hence, we return the `preferredHashAlgo` as long as it's supported and strong enough;
18126
+ // Otherwise, we look at the strongest supported algo, and ultimately fallback to the curve
18127
+ // preferred algo, even if not supported by all targets.
18128
+ const preferredCurveAlgo = mod.getPreferredCurveHashAlgo(signingKeyPacket.algorithm, signingKeyPacket.publicParams.oid);
18129
+
18130
+ const preferredSenderAlgoIsSupported = isSupportedHashAlgo(preferredSenderAlgo);
18131
+ const preferredSenderAlgoStrongerThanCurveAlgo = mod.hash.getHashByteLength(preferredSenderAlgo) >= mod.hash.getHashByteLength(preferredCurveAlgo);
18132
+
18133
+ if (preferredSenderAlgoIsSupported && preferredSenderAlgoStrongerThanCurveAlgo) {
18134
+ return preferredSenderAlgo;
18135
+ } else {
18136
+ const strongestSupportedAlgo = getStrongestSupportedHashAlgo();
18137
+ return mod.hash.getHashByteLength(strongestSupportedAlgo) >= mod.hash.getHashByteLength(preferredCurveAlgo) ?
18138
+ strongestSupportedAlgo :
18139
+ preferredCurveAlgo;
18140
+ }
18856
18141
  }
18857
18142
 
18858
- return mod.hash.getHashByteLength(hashAlgo) <= mod.hash.getHashByteLength(prefAlgo) ?
18859
- prefAlgo : hashAlgo;
18143
+ // `preferredSenderAlgo` may be weaker than the default, but we do not guard against this,
18144
+ // since it was manually set by the sender.
18145
+ return isSupportedHashAlgo(preferredSenderAlgo) ? preferredSenderAlgo : getStrongestSupportedHashAlgo();
18860
18146
  }
18861
18147
 
18862
18148
  /**
@@ -18927,7 +18213,7 @@ async function getPreferredCipherSuite(keys = [], date = new Date(), userIDs = [
18927
18213
  /**
18928
18214
  * Create signature packet
18929
18215
  * @param {Object} dataToSign - Contains packets to be signed
18930
- * @param {PrivateKey} privateKey - key to get preferences from
18216
+ * @param {Array<Key>} recipientKeys - keys to get preferences from
18931
18217
  * @param {SecretKeyPacket|
18932
18218
  * SecretSubkeyPacket} signingKeyPacket secret key packet for signing
18933
18219
  * @param {Object} [signatureProperties] - Properties to write on the signature packet before signing
@@ -18938,7 +18224,7 @@ async function getPreferredCipherSuite(keys = [], date = new Date(), userIDs = [
18938
18224
  * @param {Object} config - full configuration
18939
18225
  * @returns {Promise<SignaturePacket>} Signature packet.
18940
18226
  */
18941
- async function createSignaturePacket(dataToSign, privateKey, signingKeyPacket, signatureProperties, date, userID, notations = [], detached = false, config) {
18227
+ async function createSignaturePacket(dataToSign, recipientKeys, signingKeyPacket, signatureProperties, date, recipientUserIDs, notations = [], detached = false, config) {
18942
18228
  if (signingKeyPacket.isDummy()) {
18943
18229
  throw new Error('Cannot sign with a gnu-dummy key.');
18944
18230
  }
@@ -18948,7 +18234,7 @@ async function createSignaturePacket(dataToSign, privateKey, signingKeyPacket, s
18948
18234
  const signaturePacket = new SignaturePacket();
18949
18235
  Object.assign(signaturePacket, signatureProperties);
18950
18236
  signaturePacket.publicKeyAlgorithm = signingKeyPacket.algorithm;
18951
- signaturePacket.hashAlgorithm = await getPreferredHashAlgo(privateKey, signingKeyPacket, date, userID, config);
18237
+ signaturePacket.hashAlgorithm = await getPreferredHashAlgo(recipientKeys, signingKeyPacket, date, recipientUserIDs, config);
18952
18238
  signaturePacket.rawNotations = [...notations];
18953
18239
  await signaturePacket.sign(signingKeyPacket, dataToSign, date, detached, config);
18954
18240
  return signaturePacket;
@@ -19285,7 +18571,7 @@ class User {
19285
18571
  throw new Error("The user's own key can only be used for self-certifications");
19286
18572
  }
19287
18573
  const signingKey = await privateKey.getSigningKey(undefined, date, undefined, config);
19288
- return createSignaturePacket(dataToSign, privateKey, signingKey.keyPacket, {
18574
+ return createSignaturePacket(dataToSign, [privateKey], signingKey.keyPacket, {
19289
18575
  // Most OpenPGP implementations use generic certification (0x10)
19290
18576
  signatureType: enums.signature.certGeneric,
19291
18577
  keyFlags: [enums.keyFlags.certifyKeys | enums.keyFlags.signData]
@@ -19473,7 +18759,7 @@ class User {
19473
18759
  key: primaryKey
19474
18760
  };
19475
18761
  const user = new User(dataToSign.userID || dataToSign.userAttribute, this.mainKey);
19476
- user.revocationSignatures.push(await createSignaturePacket(dataToSign, null, primaryKey, {
18762
+ user.revocationSignatures.push(await createSignaturePacket(dataToSign, [], primaryKey, {
19477
18763
  signatureType: enums.signature.certRevocation,
19478
18764
  reasonForRevocationFlag: enums.write(enums.reasonForRevocation, reasonForRevocationFlag),
19479
18765
  reasonForRevocationString
@@ -19666,7 +18952,7 @@ class Subkey {
19666
18952
  ) {
19667
18953
  const dataToSign = { key: primaryKey, bind: this.keyPacket };
19668
18954
  const subkey = new Subkey(this.keyPacket, this.mainKey);
19669
- subkey.revocationSignatures.push(await createSignaturePacket(dataToSign, null, primaryKey, {
18955
+ subkey.revocationSignatures.push(await createSignaturePacket(dataToSign, [], primaryKey, {
19670
18956
  signatureType: enums.signature.subkeyRevocation,
19671
18957
  reasonForRevocationFlag: enums.write(enums.reasonForRevocation, reasonForRevocationFlag),
19672
18958
  reasonForRevocationString
@@ -20699,7 +19985,7 @@ class PrivateKey extends PublicKey {
20699
19985
  }
20700
19986
  const dataToSign = { key: this.keyPacket };
20701
19987
  const key = this.clone();
20702
- key.revocationSignatures.push(await createSignaturePacket(dataToSign, null, this.keyPacket, {
19988
+ key.revocationSignatures.push(await createSignaturePacket(dataToSign, [], this.keyPacket, {
20703
19989
  signatureType: enums.signature.keyRevocation,
20704
19990
  reasonForRevocationFlag: enums.write(enums.reasonForRevocation, reasonForRevocationFlag),
20705
19991
  reasonForRevocationString
@@ -21012,7 +20298,7 @@ async function wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options, conf
21012
20298
  const signatureProperties = getKeySignatureProperties();
21013
20299
  signatureProperties.signatureType = enums.signature.key;
21014
20300
 
21015
- const signaturePacket = await createSignaturePacket(dataToSign, null, secretKeyPacket, signatureProperties, options.date, undefined, undefined, undefined, config);
20301
+ const signaturePacket = await createSignaturePacket(dataToSign, [], secretKeyPacket, signatureProperties, options.date, undefined, undefined, undefined, config);
21016
20302
  packetlist.push(signaturePacket);
21017
20303
  }
21018
20304
 
@@ -21028,7 +20314,7 @@ async function wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options, conf
21028
20314
  signatureProperties.isPrimaryUserID = true;
21029
20315
  }
21030
20316
 
21031
- const signaturePacket = await createSignaturePacket(dataToSign, null, secretKeyPacket, signatureProperties, options.date, undefined, undefined, undefined, config);
20317
+ const signaturePacket = await createSignaturePacket(dataToSign, [], secretKeyPacket, signatureProperties, options.date, undefined, undefined, undefined, config);
21032
20318
 
21033
20319
  return { userIDPacket, signaturePacket };
21034
20320
  })).then(list => {
@@ -21052,7 +20338,7 @@ async function wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options, conf
21052
20338
  // Add revocation signature packet for creating a revocation certificate.
21053
20339
  // This packet should be removed before returning the key.
21054
20340
  const dataToSign = { key: secretKeyPacket };
21055
- packetlist.push(await createSignaturePacket(dataToSign, null, secretKeyPacket, {
20341
+ packetlist.push(await createSignaturePacket(dataToSign, [], secretKeyPacket, {
21056
20342
  signatureType: enums.signature.keyRevocation,
21057
20343
  reasonForRevocationFlag: enums.reasonForRevocation.noReason,
21058
20344
  reasonForRevocationString: ''
@@ -21727,16 +21013,18 @@ class Message {
21727
21013
  /**
21728
21014
  * Sign the message (the literal data packet of the message)
21729
21015
  * @param {Array<PrivateKey>} signingKeys - private keys with decrypted secret key data for signing
21016
+ * @param {Array<Key>} recipientKeys - recipient keys to get the signing preferences from
21730
21017
  * @param {Signature} [signature] - Any existing detached signature to add to the message
21731
21018
  * @param {Array<module:type/keyid~KeyID>} [signingKeyIDs] - Array of key IDs to use for signing. Each signingKeyIDs[i] corresponds to signingKeys[i]
21732
21019
  * @param {Date} [date] - Override the creation time of the signature
21733
- * @param {Array} [userIDs] - User IDs to sign with, e.g. [{ name:'Steve Sender', email:'steve@openpgp.org' }]
21020
+ * @param {Array<UserID>} [signingUserIDs] - User IDs to sign with, e.g. [{ name:'Steve Sender', email:'steve@openpgp.org' }]
21021
+ * @param {Array<UserID>} [recipientUserIDs] - User IDs associated with `recipientKeys` to get the signing preferences from
21734
21022
  * @param {Array} [notations] - Notation Data to add to the signatures, e.g. [{ name: 'test@example.org', value: new TextEncoder().encode('test'), humanReadable: true, critical: false }]
21735
21023
  * @param {Object} [config] - Full configuration, defaults to openpgp.config
21736
21024
  * @returns {Promise<Message>} New message with signed content.
21737
21025
  * @async
21738
21026
  */
21739
- async sign(signingKeys = [], signature = null, signingKeyIDs = [], date = new Date(), userIDs = [], notations = [], config$1 = config) {
21027
+ async sign(signingKeys = [], recipientKeys = [], signature = null, signingKeyIDs = [], date = new Date(), signingUserIDs = [], recipientUserIDs = [], notations = [], config$1 = config) {
21740
21028
  const packetlist = new PacketList();
21741
21029
 
21742
21030
  const literalDataPacket = this.packets.findPacket(enums.packet.literalData);
@@ -21744,7 +21032,7 @@ class Message {
21744
21032
  throw new Error('No literal data packet to sign.');
21745
21033
  }
21746
21034
 
21747
- const signaturePackets = await createSignaturePackets(literalDataPacket, signingKeys, signature, signingKeyIDs, date, userIDs, notations, false, config$1); // this returns the existing signature packets as well
21035
+ const signaturePackets = await createSignaturePackets(literalDataPacket, signingKeys, recipientKeys, signature, signingKeyIDs, date, signingUserIDs, recipientUserIDs, notations, false, config$1); // this returns the existing signature packets as well
21748
21036
  const onePassSignaturePackets = signaturePackets.map(
21749
21037
  (signaturePacket, i) => OnePassSignaturePacket.fromSignaturePacket(signaturePacket, i === 0))
21750
21038
  .reverse(); // innermost OPS refers to the first signature packet
@@ -21780,21 +21068,23 @@ class Message {
21780
21068
  /**
21781
21069
  * Create a detached signature for the message (the literal data packet of the message)
21782
21070
  * @param {Array<PrivateKey>} signingKeys - private keys with decrypted secret key data for signing
21071
+ * @param {Array<Key>} recipientKeys - recipient keys to get the signing preferences from
21783
21072
  * @param {Signature} [signature] - Any existing detached signature
21784
21073
  * @param {Array<module:type/keyid~KeyID>} [signingKeyIDs] - Array of key IDs to use for signing. Each signingKeyIDs[i] corresponds to signingKeys[i]
21785
21074
  * @param {Date} [date] - Override the creation time of the signature
21786
- * @param {Array} [userIDs] - User IDs to sign with, e.g. [{ name:'Steve Sender', email:'steve@openpgp.org' }]
21075
+ * @param {Array<UserID>} [signingUserIDs] - User IDs to sign with, e.g. [{ name:'Steve Sender', email:'steve@openpgp.org' }]
21076
+ * @param {Array<UserID>} [recipientUserIDs] - User IDs associated with `recipientKeys` to get the signing preferences from
21787
21077
  * @param {Array} [notations] - Notation Data to add to the signatures, e.g. [{ name: 'test@example.org', value: new TextEncoder().encode('test'), humanReadable: true, critical: false }]
21788
21078
  * @param {Object} [config] - Full configuration, defaults to openpgp.config
21789
21079
  * @returns {Promise<Signature>} New detached signature of message content.
21790
21080
  * @async
21791
21081
  */
21792
- async signDetached(signingKeys = [], signature = null, signingKeyIDs = [], date = new Date(), userIDs = [], notations = [], config$1 = config) {
21082
+ async signDetached(signingKeys = [], recipientKeys = [], signature = null, signingKeyIDs = [], recipientKeyIDs = [], date = new Date(), userIDs = [], notations = [], config$1 = config) {
21793
21083
  const literalDataPacket = this.packets.findPacket(enums.packet.literalData);
21794
21084
  if (!literalDataPacket) {
21795
21085
  throw new Error('No literal data packet to sign.');
21796
21086
  }
21797
- return new Signature(await createSignaturePackets(literalDataPacket, signingKeys, signature, signingKeyIDs, date, userIDs, notations, true, config$1));
21087
+ return new Signature(await createSignaturePackets(literalDataPacket, signingKeys, recipientKeys, signature, signingKeyIDs, recipientKeyIDs, date, userIDs, notations, true, config$1));
21798
21088
  }
21799
21089
 
21800
21090
  /**
@@ -21929,10 +21219,12 @@ class Message {
21929
21219
  * Create signature packets for the message
21930
21220
  * @param {LiteralDataPacket} literalDataPacket - the literal data packet to sign
21931
21221
  * @param {Array<PrivateKey>} [signingKeys] - private keys with decrypted secret key data for signing
21222
+ * @param {Array<Key>} [recipientKeys] - recipient keys to get the signing preferences from
21932
21223
  * @param {Signature} [signature] - Any existing detached signature to append
21933
21224
  * @param {Array<module:type/keyid~KeyID>} [signingKeyIDs] - Array of key IDs to use for signing. Each signingKeyIDs[i] corresponds to signingKeys[i]
21934
21225
  * @param {Date} [date] - Override the creationtime of the signature
21935
- * @param {Array} [userIDs] - User IDs to sign with, e.g. [{ name:'Steve Sender', email:'steve@openpgp.org' }]
21226
+ * @param {Array<UserID>} [signingUserIDs] - User IDs to sign to, e.g. [{ name:'Steve Sender', email:'steve@openpgp.org' }]
21227
+ * @param {Array<UserID>} [recipientUserIDs] - User IDs associated with `recipientKeys` to get the signing preferences from
21936
21228
  * @param {Array} [notations] - Notation Data to add to the signatures, e.g. [{ name: 'test@example.org', value: new TextEncoder().encode('test'), humanReadable: true, critical: false }]
21937
21229
  * @param {Array} [signatureSalts] - A list of signature salts matching the number of signingKeys that should be used for v6 signatures
21938
21230
  * @param {Boolean} [detached] - Whether to create detached signature packets
@@ -21941,7 +21233,7 @@ class Message {
21941
21233
  * @async
21942
21234
  * @private
21943
21235
  */
21944
- async function createSignaturePackets(literalDataPacket, signingKeys, signature = null, signingKeyIDs = [], date = new Date(), userIDs = [], notations = [], detached = false, config$1 = config) {
21236
+ async function createSignaturePackets(literalDataPacket, signingKeys, recipientKeys = [], signature = null, signingKeyIDs = [], date = new Date(), signingUserIDs = [], recipientUserIDs = [], notations = [], detached = false, config$1 = config) {
21945
21237
  const packetlist = new PacketList();
21946
21238
 
21947
21239
  // If data packet was created from Uint8Array, use binary, otherwise use text
@@ -21949,12 +21241,12 @@ async function createSignaturePackets(literalDataPacket, signingKeys, signature
21949
21241
  enums.signature.binary : enums.signature.text;
21950
21242
 
21951
21243
  await Promise.all(signingKeys.map(async (primaryKey, i) => {
21952
- const userID = userIDs[i];
21244
+ const signingUserID = signingUserIDs[i];
21953
21245
  if (!primaryKey.isPrivate()) {
21954
21246
  throw new Error('Need private key for signing');
21955
21247
  }
21956
- const signingKey = await primaryKey.getSigningKey(signingKeyIDs[i], date, userID, config$1);
21957
- return createSignaturePacket(literalDataPacket, primaryKey, signingKey.keyPacket, { signatureType }, date, userID, notations, detached, config$1);
21248
+ const signingKey = await primaryKey.getSigningKey(signingKeyIDs[i], date, signingUserID, config$1);
21249
+ return createSignaturePacket(literalDataPacket, recipientKeys.length ? recipientKeys : [primaryKey], signingKey.keyPacket, { signatureType }, date, recipientUserIDs, notations, detached, config$1);
21958
21250
  })).then(signatureList => {
21959
21251
  packetlist.push(...signatureList);
21960
21252
  });
@@ -22204,20 +21496,22 @@ class CleartextMessage {
22204
21496
 
22205
21497
  /**
22206
21498
  * Sign the cleartext message
22207
- * @param {Array<Key>} privateKeys - private keys with decrypted secret key data for signing
21499
+ * @param {Array<Key>} signingKeys - private keys with decrypted secret key data for signing
21500
+ * @param {Array<Key>} recipientKeys - recipient keys to get the signing preferences from
22208
21501
  * @param {Signature} [signature] - Any existing detached signature
22209
21502
  * @param {Array<module:type/keyid~KeyID>} [signingKeyIDs] - Array of key IDs to use for signing. Each signingKeyIDs[i] corresponds to privateKeys[i]
22210
21503
  * @param {Date} [date] - The creation time of the signature that should be created
22211
- * @param {Array} [userIDs] - User IDs to sign with, e.g. [{ name:'Steve Sender', email:'steve@openpgp.org' }]
21504
+ * @param {Array} [signingKeyIDs] - User IDs to sign with, e.g. [{ name:'Steve Sender', email:'steve@openpgp.org' }]
21505
+ * @param {Array} [recipientUserIDs] - User IDs associated with `recipientKeys` to get the signing preferences from
22212
21506
  * @param {Array} [notations] - Notation Data to add to the signatures, e.g. [{ name: 'test@example.org', value: new TextEncoder().encode('test'), humanReadable: true, critical: false }]
22213
21507
  * @param {Object} [config] - Full configuration, defaults to openpgp.config
22214
21508
  * @returns {Promise<CleartextMessage>} New cleartext message with signed content.
22215
21509
  * @async
22216
21510
  */
22217
- async sign(privateKeys, signature = null, signingKeyIDs = [], date = new Date(), userIDs = [], notations = [], config$1 = config) {
21511
+ async sign(signingKeys, recipientKeys = [], signature = null, signingKeyIDs = [], date = new Date(), signingUserIDs = [], recipientUserIDs = [], notations = [], config$1 = config) {
22218
21512
  const literalDataPacket = new LiteralDataPacket();
22219
21513
  literalDataPacket.setText(this.text);
22220
- const newSignature = new Signature(await createSignaturePackets(literalDataPacket, privateKeys, signature, signingKeyIDs, date, userIDs, notations, true, config$1));
21514
+ const newSignature = new Signature(await createSignaturePackets(literalDataPacket, signingKeys, recipientKeys, signature, signingKeyIDs, date, signingUserIDs, recipientUserIDs, notations, true, config$1));
22221
21515
  return new CleartextMessage(this.text, newSignature);
22222
21516
  }
22223
21517
 
@@ -22653,7 +21947,7 @@ async function encrypt({ message, encryptionKeys, signingKeys, passwords, sessio
22653
21947
 
22654
21948
  try {
22655
21949
  if (signingKeys.length || signature) { // sign the message only if signing keys or signature is specified
22656
- message = await message.sign(signingKeys, signature, signingKeyIDs, date, signingUserIDs, signatureNotations, config$1);
21950
+ message = await message.sign(signingKeys, encryptionKeys, signature, signingKeyIDs, date, signingUserIDs, encryptionKeyIDs, signatureNotations, config$1);
22657
21951
  }
22658
21952
  message = message.compress(
22659
21953
  await getPreferredCompressionAlgo(encryptionKeys, date, encryptionUserIDs, config$1),
@@ -22755,21 +22049,23 @@ async function decrypt({ message, decryptionKeys, passwords, sessionKeys, verifi
22755
22049
  * @param {Object} options
22756
22050
  * @param {CleartextMessage|Message} options.message - (cleartext) message to be signed
22757
22051
  * @param {PrivateKey|PrivateKey[]} options.signingKeys - Array of keys or single key with decrypted secret key data to sign cleartext
22052
+ * @param {Key|Key[]} options.recipientKeys - Array of keys or single to get the signing preferences from
22758
22053
  * @param {'armored'|'binary'|'object'} [options.format='armored'] - Format of the returned message
22759
22054
  * @param {Boolean} [options.detached=false] - If the return value should contain a detached signature
22760
22055
  * @param {KeyID|KeyID[]} [options.signingKeyIDs=latest-created valid signing (sub)keys] - Array of key IDs to use for signing. Each signingKeyIDs[i] corresponds to signingKeys[i]
22761
22056
  * @param {Date} [options.date=current date] - Override the creation date of the signature
22762
22057
  * @param {Object|Object[]} [options.signingUserIDs=primary user IDs] - Array of user IDs to sign with, one per key in `signingKeys`, e.g. `[{ name: 'Steve Sender', email: 'steve@openpgp.org' }]`
22058
+ * @param {Object|Object[]} [options.recipientUserIDs=primary user IDs] - Array of user IDs to get the signing preferences from, one per key in `recipientKeys`
22763
22059
  * @param {Object|Object[]} [options.signatureNotations=[]] - Array of notations to add to the signatures, e.g. `[{ name: 'test@example.org', value: new TextEncoder().encode('test'), humanReadable: true, critical: false }]`
22764
22060
  * @param {Object} [options.config] - Custom configuration settings to overwrite those in [config]{@link module:config}
22765
22061
  * @returns {Promise<MaybeStream<String|Uint8Array>>} Signed message (string if `armor` was true, the default; Uint8Array if `armor` was false).
22766
22062
  * @async
22767
22063
  * @static
22768
22064
  */
22769
- async function sign({ message, signingKeys, format = 'armored', detached = false, signingKeyIDs = [], date = new Date(), signingUserIDs = [], signatureNotations = [], config: config$1, ...rest }) {
22065
+ async function sign({ message, signingKeys, recipientKeys = [], format = 'armored', detached = false, signingKeyIDs = [], date = new Date(), signingUserIDs = [], recipientUserIDs = [], signatureNotations = [], config: config$1, ...rest }) {
22770
22066
  config$1 = { ...config, ...config$1 }; checkConfig(config$1);
22771
22067
  checkCleartextOrMessage(message); checkOutputMessageFormat(format);
22772
- signingKeys = toArray(signingKeys); signingKeyIDs = toArray(signingKeyIDs); signingUserIDs = toArray(signingUserIDs); signatureNotations = toArray(signatureNotations);
22068
+ signingKeys = toArray(signingKeys); signingKeyIDs = toArray(signingKeyIDs); signingUserIDs = toArray(signingUserIDs); recipientKeys = toArray(recipientKeys); recipientUserIDs = toArray(recipientUserIDs); signatureNotations = toArray(signatureNotations);
22773
22069
 
22774
22070
  if (rest.privateKeys) throw new Error('The `privateKeys` option has been removed from openpgp.sign, pass `signingKeys` instead');
22775
22071
  if (rest.armor !== undefined) throw new Error('The `armor` option has been removed from openpgp.sign, pass `format` instead.');
@@ -22785,9 +22081,9 @@ async function sign({ message, signingKeys, format = 'armored', detached = false
22785
22081
  try {
22786
22082
  let signature;
22787
22083
  if (detached) {
22788
- signature = await message.signDetached(signingKeys, undefined, signingKeyIDs, date, signingUserIDs, signatureNotations, config$1);
22084
+ signature = await message.signDetached(signingKeys, recipientKeys, undefined, signingKeyIDs, date, signingUserIDs, recipientUserIDs, signatureNotations, config$1);
22789
22085
  } else {
22790
- signature = await message.sign(signingKeys, undefined, signingKeyIDs, date, signingUserIDs, signatureNotations, config$1);
22086
+ signature = await message.sign(signingKeys, recipientKeys, undefined, signingKeyIDs, date, signingUserIDs, recipientUserIDs, signatureNotations, config$1);
22791
22087
  }
22792
22088
  if (format === 'object') return signature;
22793
22089