@protontech/openpgp 6.0.0-alpha.1.patch.1 → 6.0.0-beta.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 (36) hide show
  1. package/dist/lightweight/argon2id.min.mjs +1 -1
  2. package/dist/lightweight/argon2id.mjs +1 -1
  3. package/dist/lightweight/bn.interface.min.mjs +2 -2
  4. package/dist/lightweight/bn.interface.min.mjs.map +1 -1
  5. package/dist/lightweight/bn.interface.mjs +1 -1
  6. package/dist/lightweight/interface.min.mjs +1 -1
  7. package/dist/lightweight/interface.mjs +1 -1
  8. package/dist/lightweight/legacy_ciphers.min.mjs +1 -1
  9. package/dist/lightweight/legacy_ciphers.mjs +1 -1
  10. package/dist/lightweight/native.interface.min.mjs +1 -1
  11. package/dist/lightweight/native.interface.mjs +1 -1
  12. package/dist/lightweight/noble_curves.min.mjs +3 -3
  13. package/dist/lightweight/noble_curves.min.mjs.map +1 -1
  14. package/dist/lightweight/noble_curves.mjs +1 -1
  15. package/dist/lightweight/noble_hashes.min.mjs +1 -1
  16. package/dist/lightweight/noble_hashes.mjs +1 -1
  17. package/dist/lightweight/openpgp.min.mjs +2 -2
  18. package/dist/lightweight/openpgp.min.mjs.map +1 -1
  19. package/dist/lightweight/openpgp.mjs +203 -83
  20. package/dist/lightweight/sha3.min.mjs +2 -2
  21. package/dist/lightweight/sha3.min.mjs.map +1 -1
  22. package/dist/lightweight/sha3.mjs +1 -1
  23. package/dist/node/openpgp.cjs +203 -83
  24. package/dist/node/openpgp.min.cjs +11 -11
  25. package/dist/node/openpgp.min.cjs.map +1 -1
  26. package/dist/node/openpgp.min.mjs +11 -11
  27. package/dist/node/openpgp.min.mjs.map +1 -1
  28. package/dist/node/openpgp.mjs +203 -83
  29. package/dist/openpgp.js +203 -83
  30. package/dist/openpgp.min.js +11 -11
  31. package/dist/openpgp.min.js.map +1 -1
  32. package/dist/openpgp.min.mjs +11 -11
  33. package/dist/openpgp.min.mjs.map +1 -1
  34. package/dist/openpgp.mjs +203 -83
  35. package/openpgp.d.ts +4 -3
  36. package/package.json +9 -9
@@ -1,4 +1,4 @@
1
- /*! OpenPGP.js v6.0.0-alpha.1.patch.1 - 2024-03-11 - this is LGPL licensed code, see LICENSE/our website https://openpgpjs.org/ for more information. */
1
+ /*! OpenPGP.js v6.0.0-beta.0 - 2024-04-18 - this is LGPL licensed code, see LICENSE/our website https://openpgpjs.org/ for more information. */
2
2
  'use strict';
3
3
 
4
4
  const globalThis = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
@@ -1602,11 +1602,6 @@ var config = {
1602
1602
  * @property {Boolean} passwordCollisionCheck
1603
1603
  */
1604
1604
  passwordCollisionCheck: false,
1605
- /**
1606
- * @memberof module:config
1607
- * @property {Boolean} revocationsExpire If true, expired revocation signatures are ignored
1608
- */
1609
- revocationsExpire: false,
1610
1605
  /**
1611
1606
  * Allow decryption using RSA keys without `encrypt` flag.
1612
1607
  * This setting is potentially insecure, but it is needed to get around an old openpgpjs bug
@@ -1682,7 +1677,7 @@ var config = {
1682
1677
  * @memberof module:config
1683
1678
  * @property {String} versionString A version string to be included in armored messages
1684
1679
  */
1685
- versionString: 'OpenPGP.js 6.0.0-alpha.1.patch.1',
1680
+ versionString: 'OpenPGP.js 6.0.0-beta.0',
1686
1681
  /**
1687
1682
  * @memberof module:config
1688
1683
  * @property {String} commentString A comment string to be included in armored messages
@@ -1702,6 +1697,14 @@ var config = {
1702
1697
  * @property {Array} knownNotations
1703
1698
  */
1704
1699
  knownNotations: [],
1700
+ /**
1701
+ * If true, a salt notation is used to randomize signatures generated by v4 and v5 keys (v6 signatures are always non-deterministic, by design).
1702
+ * This protects EdDSA signatures from potentially leaking the secret key in case of faults (i.e. bitflips) which, in principle, could occur
1703
+ * during the signing computation. It is added to signatures of any algo for simplicity, and as it may also serve as protection in case of
1704
+ * weaknesses in the hash algo, potentially hindering e.g. some chosen-prefix attacks.
1705
+ * NOTE: the notation is interoperable, but will reveal that the signature has been generated using OpenPGP.js, which may not be desirable in some cases.
1706
+ */
1707
+ nonDeterministicSignaturesViaNotation: true,
1705
1708
  /**
1706
1709
  * Whether to use the the noble-curves library for curves (other than Curve25519) that are not supported by the available native crypto API.
1707
1710
  * When false, certain standard curves will not be supported (depending on the platform).
@@ -1732,14 +1735,7 @@ var config = {
1732
1735
  * @memberof module:config
1733
1736
  * @property {Set<String>} rejectCurves {@link module:enums.curve}
1734
1737
  */
1735
- rejectCurves: new Set([enums.curve.secp256k1]),
1736
- /**
1737
- * Whether to validate generated EdDSA signatures before returning them, to ensure they are not faulty signatures.
1738
- * This check will make signing 2-3 times slower.
1739
- * Faulty signatures may be generated (in principle) if random bitflips occur at specific points in the signature
1740
- * computation, and could be used to recover the signer's secret key given a second signature over the same data.
1741
- */
1742
- checkEdDSAFaultySignatures: true
1738
+ rejectCurves: new Set([enums.curve.secp256k1])
1743
1739
  };
1744
1740
 
1745
1741
  /**
@@ -2224,16 +2220,19 @@ const util = {
2224
2220
  },
2225
2221
 
2226
2222
  /**
2227
- * Test email format based on W3C HTML5 specification.
2228
- * This check is not exaustive, and does not match RFC 5322 exactly
2229
- * (see https://html.spec.whatwg.org/multipage/input.html#email-state-(type=email)),
2230
- * but is commonly used for email address validation.
2223
+ * Test email format to ensure basic compliance:
2224
+ * - must include a single @
2225
+ * - no control or space unicode chars allowed
2226
+ * - no backslash and square brackets (as the latter can mess with the userID parsing)
2227
+ * - cannot end with a punctuation char
2228
+ * These checks are not meant to be exhaustive; applications are strongly encouraged to implement stricter validation,
2229
+ * e.g. based on the W3C HTML spec (https://html.spec.whatwg.org/multipage/input.html#email-state-(type=email)).
2231
2230
  */
2232
2231
  isEmailAddress: function(data) {
2233
2232
  if (!util.isString(data)) {
2234
2233
  return false;
2235
2234
  }
2236
- const re = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
2235
+ const re = /^[^\p{C}\p{Z}@<>\\]+@[^\p{C}\p{Z}@<>\\]+[^\p{C}\p{Z}\p{P}]$/u;
2237
2236
  return re.test(data);
2238
2237
  },
2239
2238
 
@@ -2639,6 +2638,78 @@ function addheader(customComment, config) {
2639
2638
  return result;
2640
2639
  }
2641
2640
 
2641
+ /**
2642
+ * Calculates a checksum over the given data and returns it base64 encoded
2643
+ * @param {String | ReadableStream<String>} data - Data to create a CRC-24 checksum for
2644
+ * @returns {String | ReadableStream<String>} Base64 encoded checksum.
2645
+ * @private
2646
+ */
2647
+ function getCheckSum(data) {
2648
+ const crc = createcrc24(data);
2649
+ return encode$1(crc);
2650
+ }
2651
+
2652
+ // https://create.stephan-brumme.com/crc32/#slicing-by-8-overview
2653
+
2654
+ const crc_table = [
2655
+ new Array(0xFF),
2656
+ new Array(0xFF),
2657
+ new Array(0xFF),
2658
+ new Array(0xFF)
2659
+ ];
2660
+
2661
+ for (let i = 0; i <= 0xFF; i++) {
2662
+ let crc = i << 16;
2663
+ for (let j = 0; j < 8; j++) {
2664
+ crc = (crc << 1) ^ ((crc & 0x800000) !== 0 ? 0x864CFB : 0);
2665
+ }
2666
+ crc_table[0][i] =
2667
+ ((crc & 0xFF0000) >> 16) |
2668
+ (crc & 0x00FF00) |
2669
+ ((crc & 0x0000FF) << 16);
2670
+ }
2671
+ for (let i = 0; i <= 0xFF; i++) {
2672
+ crc_table[1][i] = (crc_table[0][i] >> 8) ^ crc_table[0][crc_table[0][i] & 0xFF];
2673
+ }
2674
+ for (let i = 0; i <= 0xFF; i++) {
2675
+ crc_table[2][i] = (crc_table[1][i] >> 8) ^ crc_table[0][crc_table[1][i] & 0xFF];
2676
+ }
2677
+ for (let i = 0; i <= 0xFF; i++) {
2678
+ crc_table[3][i] = (crc_table[2][i] >> 8) ^ crc_table[0][crc_table[2][i] & 0xFF];
2679
+ }
2680
+
2681
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView#Endianness
2682
+ const isLittleEndian$1 = (function() {
2683
+ const buffer = new ArrayBuffer(2);
2684
+ new DataView(buffer).setInt16(0, 0xFF, true /* littleEndian */);
2685
+ // Int16Array uses the platform's endianness.
2686
+ return new Int16Array(buffer)[0] === 0xFF;
2687
+ }());
2688
+
2689
+ /**
2690
+ * Internal function to calculate a CRC-24 checksum over a given string (data)
2691
+ * @param {String | ReadableStream<String>} input - Data to create a CRC-24 checksum for
2692
+ * @returns {Uint8Array | ReadableStream<Uint8Array>} The CRC-24 checksum.
2693
+ * @private
2694
+ */
2695
+ function createcrc24(input) {
2696
+ let crc = 0xCE04B7;
2697
+ return transform(input, value => {
2698
+ const len32 = isLittleEndian$1 ? Math.floor(value.length / 4) : 0;
2699
+ const arr32 = new Uint32Array(value.buffer, value.byteOffset, len32);
2700
+ for (let i = 0; i < len32; i++) {
2701
+ crc ^= arr32[i];
2702
+ crc =
2703
+ crc_table[0][(crc >> 24) & 0xFF] ^
2704
+ crc_table[1][(crc >> 16) & 0xFF] ^
2705
+ crc_table[2][(crc >> 8) & 0xFF] ^
2706
+ crc_table[3][(crc >> 0) & 0xFF];
2707
+ }
2708
+ for (let i = len32 * 4; i < value.length; i++) {
2709
+ crc = (crc >> 8) ^ crc_table[0][(crc & 0xFF) ^ value[i]];
2710
+ }
2711
+ }, () => new Uint8Array([crc, crc >> 8, crc >> 16]));
2712
+ }
2642
2713
 
2643
2714
  /**
2644
2715
  * Verify armored headers. crypto-refresh-06, section 6.2:
@@ -2794,10 +2865,13 @@ function unarmor(input) {
2794
2865
  * @param {Integer} [partIndex]
2795
2866
  * @param {Integer} [partTotal]
2796
2867
  * @param {String} [customComment] - Additional comment to add to the armored string
2868
+ * @param {Boolean} [emitChecksum] - Whether to compute and include the CRC checksum
2869
+ * (NB: some types of data must not include it, but compliance is left as responsibility of the caller: this function does not carry out any checks)
2870
+ * @param {Object} [config] - Full configuration, defaults to openpgp.config
2797
2871
  * @returns {String | ReadableStream<String>} Armored text.
2798
2872
  * @static
2799
2873
  */
2800
- function armor(messageType, body, partIndex, partTotal, customComment, config$1 = config) {
2874
+ function armor(messageType, body, partIndex, partTotal, customComment, emitChecksum = false, config$1 = config) {
2801
2875
  let text;
2802
2876
  let hash;
2803
2877
  if (messageType === enums.armor.signed) {
@@ -2805,18 +2879,24 @@ function armor(messageType, body, partIndex, partTotal, customComment, config$1
2805
2879
  hash = body.hash;
2806
2880
  body = body.data;
2807
2881
  }
2882
+ // unless explicitly forbidden by the spec, we need to include the checksum to work around a GnuPG bug
2883
+ // where data fails to be decoded if the base64 ends with no padding chars (=) (see https://dev.gnupg.org/T7071)
2884
+ const maybeBodyClone = emitChecksum && passiveClone(body);
2885
+
2808
2886
  const result = [];
2809
2887
  switch (messageType) {
2810
2888
  case enums.armor.multipartSection:
2811
2889
  result.push('-----BEGIN PGP MESSAGE, PART ' + partIndex + '/' + partTotal + '-----\n');
2812
2890
  result.push(addheader(customComment, config$1));
2813
2891
  result.push(encode$1(body));
2892
+ maybeBodyClone && result.push('=', getCheckSum(maybeBodyClone));
2814
2893
  result.push('-----END PGP MESSAGE, PART ' + partIndex + '/' + partTotal + '-----\n');
2815
2894
  break;
2816
2895
  case enums.armor.multipartLast:
2817
2896
  result.push('-----BEGIN PGP MESSAGE, PART ' + partIndex + '-----\n');
2818
2897
  result.push(addheader(customComment, config$1));
2819
2898
  result.push(encode$1(body));
2899
+ maybeBodyClone && result.push('=', getCheckSum(maybeBodyClone));
2820
2900
  result.push('-----END PGP MESSAGE, PART ' + partIndex + '-----\n');
2821
2901
  break;
2822
2902
  case enums.armor.signed:
@@ -2826,30 +2906,35 @@ function armor(messageType, body, partIndex, partTotal, customComment, config$1
2826
2906
  result.push('\n-----BEGIN PGP SIGNATURE-----\n');
2827
2907
  result.push(addheader(customComment, config$1));
2828
2908
  result.push(encode$1(body));
2909
+ maybeBodyClone && result.push('=', getCheckSum(maybeBodyClone));
2829
2910
  result.push('-----END PGP SIGNATURE-----\n');
2830
2911
  break;
2831
2912
  case enums.armor.message:
2832
2913
  result.push('-----BEGIN PGP MESSAGE-----\n');
2833
2914
  result.push(addheader(customComment, config$1));
2834
2915
  result.push(encode$1(body));
2916
+ maybeBodyClone && result.push('=', getCheckSum(maybeBodyClone));
2835
2917
  result.push('-----END PGP MESSAGE-----\n');
2836
2918
  break;
2837
2919
  case enums.armor.publicKey:
2838
2920
  result.push('-----BEGIN PGP PUBLIC KEY BLOCK-----\n');
2839
2921
  result.push(addheader(customComment, config$1));
2840
2922
  result.push(encode$1(body));
2923
+ maybeBodyClone && result.push('=', getCheckSum(maybeBodyClone));
2841
2924
  result.push('-----END PGP PUBLIC KEY BLOCK-----\n');
2842
2925
  break;
2843
2926
  case enums.armor.privateKey:
2844
2927
  result.push('-----BEGIN PGP PRIVATE KEY BLOCK-----\n');
2845
2928
  result.push(addheader(customComment, config$1));
2846
2929
  result.push(encode$1(body));
2930
+ maybeBodyClone && result.push('=', getCheckSum(maybeBodyClone));
2847
2931
  result.push('-----END PGP PRIVATE KEY BLOCK-----\n');
2848
2932
  break;
2849
2933
  case enums.armor.signature:
2850
2934
  result.push('-----BEGIN PGP SIGNATURE-----\n');
2851
2935
  result.push(addheader(customComment, config$1));
2852
2936
  result.push(encode$1(body));
2937
+ maybeBodyClone && result.push('=', getCheckSum(maybeBodyClone));
2853
2938
  result.push('-----END PGP SIGNATURE-----\n');
2854
2939
  break;
2855
2940
  }
@@ -9377,20 +9462,6 @@ async function sign$5(oid, hashAlgo, message, publicKey, privateKey, hashed) {
9377
9462
  }
9378
9463
  const secretKey = util.concatUint8Array([privateKey, publicKey.subarray(1)]);
9379
9464
  const signature = nacl.sign.detached(hashed, secretKey);
9380
- if (config.checkEdDSAFaultySignatures && !nacl.sign.detached.verify(hashed, signature, publicKey.subarray(1))) {
9381
- /**
9382
- * Detect faulty signatures caused by random bitflips during `crypto_sign` which could lead to private key extraction
9383
- * if two signatures over the same message are obtained.
9384
- * See https://github.com/jedisct1/libsodium/issues/170.
9385
- * If the input data is not deterministic, e.g. thanks to the random salt in v6 OpenPGP signatures (not yet implemented),
9386
- * then the generated signature is always safe, and the verification step is skipped.
9387
- * Otherwise, we need to verify the generated to ensure that no bitflip occured:
9388
- * - in M between the computation of `r` and `h`.
9389
- * - in the public key before computing `h`
9390
- * The verification step is almost 2-3 times as slow as signing, but it's faster than re-signing + re-deriving the public key for separate checks.
9391
- */
9392
- throw new Error('Transient signing failure');
9393
- }
9394
9465
  // EdDSA signature params are returned in little-endian format
9395
9466
  return {
9396
9467
  r: signature.subarray(0, 32),
@@ -9511,20 +9582,6 @@ async function sign$4(algo, hashAlgo, message, publicKey, privateKey, hashed) {
9511
9582
  case enums.publicKey.ed25519: {
9512
9583
  const secretKey = util.concatUint8Array([privateKey, publicKey]);
9513
9584
  const signature = nacl.sign.detached(hashed, secretKey);
9514
- if (config.checkEdDSAFaultySignatures && !nacl.sign.detached.verify(hashed, signature, publicKey)) {
9515
- /**
9516
- * Detect faulty signatures caused by random bitflips during `crypto_sign` which could lead to private key extraction
9517
- * if two signatures over the same message are obtained.
9518
- * See https://github.com/jedisct1/libsodium/issues/170.
9519
- * If the input data is not deterministic, e.g. thanks to the random salt in v6 OpenPGP signatures (not yet implemented),
9520
- * then the generated signature is always safe, and the verification step is skipped.
9521
- * Otherwise, we need to verify the generated to ensure that no bitflip occured:
9522
- * - in M between the computation of `r` and `h`.
9523
- * - in the public key before computing `h`
9524
- * The verification step is almost 2-3 times as slow as signing, but it's faster than re-signing + re-deriving the public key for separate checks.
9525
- */
9526
- throw new Error('Transient signing failure');
9527
- }
9528
9585
  return { RS: signature };
9529
9586
  }
9530
9587
  case enums.publicKey.ed448: {
@@ -11257,7 +11314,7 @@ class ECDHXSymmetricKey {
11257
11314
  * Encrypts data using specified algorithm and public key parameters.
11258
11315
  * See {@link https://tools.ietf.org/html/rfc4880#section-9.1|RFC 4880 9.1} for public key algorithms.
11259
11316
  * @param {module:enums.publicKey} keyAlgo - Public key algorithm
11260
- * @param {module:enums.symmetric} symmetricAlgo - Cipher algorithm
11317
+ * @param {module:enums.symmetric|null} symmetricAlgo - Cipher algorithm (v3 only)
11261
11318
  * @param {Object} publicParams - Algorithm-specific public key parameters
11262
11319
  * @param {Object} privateParams - Algorithm-specific private key parameters
11263
11320
  * @param {Uint8Array} data - Data to be encrypted
@@ -11285,7 +11342,7 @@ async function publicKeyEncrypt(keyAlgo, symmetricAlgo, publicParams, privatePar
11285
11342
  }
11286
11343
  case enums.publicKey.x25519:
11287
11344
  case enums.publicKey.x448: {
11288
- if (!util.isAES(symmetricAlgo)) {
11345
+ if (symmetricAlgo && !util.isAES(symmetricAlgo)) {
11289
11346
  // see https://gitlab.com/openpgp-wg/rfc4880bis/-/merge_requests/276
11290
11347
  throw new Error('X25519 and X448 keys can only encrypt AES session keys');
11291
11348
  }
@@ -11917,9 +11974,26 @@ class Argon2OutOfMemoryError extends Error {
11917
11974
  let loadArgonWasmModule;
11918
11975
  let argon2Promise;
11919
11976
  // reload wasm module above this treshold, to deallocated used memory
11920
- const ARGON2_WASM_MEMORY_THRESHOLD_RELOAD = 2 << 19;
11977
+ // (cannot be declared as a simple `static` field as its not supported by Safari 14)
11978
+ let ARGON2_WASM_MEMORY_THRESHOLD_RELOAD = 2 << 19;
11921
11979
 
11922
11980
  class Argon2S2K {
11981
+ static get ARGON2_WASM_MEMORY_THRESHOLD_RELOAD() {
11982
+ return ARGON2_WASM_MEMORY_THRESHOLD_RELOAD;
11983
+ }
11984
+
11985
+ static set ARGON2_WASM_MEMORY_THRESHOLD_RELOAD(memoryThreshold) {
11986
+ ARGON2_WASM_MEMORY_THRESHOLD_RELOAD = memoryThreshold;
11987
+ }
11988
+
11989
+ static reloadWasmModule() {
11990
+ if (!loadArgonWasmModule) return;
11991
+
11992
+ // it will be awaited if needed at the next `produceKey` invocation
11993
+ argon2Promise = loadArgonWasmModule();
11994
+ argon2Promise.catch(() => {});
11995
+ }
11996
+
11923
11997
  /**
11924
11998
  * @param {Object} [config] - Full configuration, defaults to openpgp.config
11925
11999
  */
@@ -12007,10 +12081,8 @@ class Argon2S2K {
12007
12081
  });
12008
12082
 
12009
12083
  // a lot of memory was used, reload to deallocate
12010
- if (decodedM > ARGON2_WASM_MEMORY_THRESHOLD_RELOAD) {
12011
- // it will be awaited if needed at the next `produceKey` invocation
12012
- argon2Promise = loadArgonWasmModule();
12013
- argon2Promise.catch(() => {});
12084
+ if (decodedM > Argon2S2K.ARGON2_WASM_MEMORY_THRESHOLD_RELOAD) {
12085
+ Argon2S2K.reloadWasmModule();
12014
12086
  }
12015
12087
  return hash;
12016
12088
  } catch (e) {
@@ -14259,6 +14331,14 @@ class KeyID {
14259
14331
  // Symbol to store cryptographic validity of the signature, to avoid recomputing multiple times on verification.
14260
14332
  const verified = Symbol('verified');
14261
14333
 
14334
+ // A salt notation is used to randomize signatures.
14335
+ // This is to protect EdDSA signatures in particular, which are known to be vulnerable to fault attacks
14336
+ // leading to secret key extraction if two signatures over the same data can be collected (see https://github.com/jedisct1/libsodium/issues/170).
14337
+ // For simplicity, we add the salt to all algos, as it may also serve as protection in case of weaknesses in the hash algo, potentially hindering e.g.
14338
+ // some chosen-prefix attacks.
14339
+ // v6 signatures do not need to rely on this notation, as they already include a separate, built-in salt.
14340
+ const SALT_NOTATION_NAME = 'salt@notations.openpgpjs.org';
14341
+
14262
14342
  // GPG puts the Issuer and Signature subpackets in the unhashed area.
14263
14343
  // Tampering with those invalidates the signature, so we still trust them and parse them.
14264
14344
  // All other unhashed subpackets are ignored.
@@ -14428,7 +14508,7 @@ class SignaturePacket {
14428
14508
  * @throws {Error} if signing failed
14429
14509
  * @async
14430
14510
  */
14431
- async sign(key, data, date = new Date(), detached = false) {
14511
+ async sign(key, data, date = new Date(), detached = false, config) {
14432
14512
  this.version = key.version;
14433
14513
 
14434
14514
  this.created = util.normalizeDate(date);
@@ -14438,6 +14518,31 @@ class SignaturePacket {
14438
14518
 
14439
14519
  const arr = [new Uint8Array([this.version, this.signatureType, this.publicKeyAlgorithm, this.hashAlgorithm])];
14440
14520
 
14521
+ // add randomness to the signature
14522
+ if (this.version === 6) {
14523
+ const saltLength = saltLengthForHash(this.hashAlgorithm);
14524
+ if (this.salt === null) {
14525
+ this.salt = mod$1.random.getRandomBytes(saltLength);
14526
+ } else if (saltLength !== this.salt.length) {
14527
+ throw new Error('Provided salt does not have the required length');
14528
+ }
14529
+ } else if (config.nonDeterministicSignaturesViaNotation) {
14530
+ const saltNotations = this.rawNotations.filter(({ name }) => (name === SALT_NOTATION_NAME));
14531
+ // since re-signing the same object is not supported, it's not expected to have multiple salt notations,
14532
+ // but we guard against it as a sanity check
14533
+ if (saltNotations.length === 0) {
14534
+ const saltValue = mod$1.random.getRandomBytes(saltLengthForHash(this.hashAlgorithm));
14535
+ this.rawNotations.push({
14536
+ name: SALT_NOTATION_NAME,
14537
+ value: saltValue,
14538
+ humanReadable: false,
14539
+ critical: false
14540
+ });
14541
+ } else {
14542
+ throw new Error('Unexpected existing salt notation');
14543
+ }
14544
+ }
14545
+
14441
14546
  // Add hashed subpackets
14442
14547
  arr.push(this.writeHashedSubPackets());
14443
14548
 
@@ -14448,14 +14553,6 @@ class SignaturePacket {
14448
14553
 
14449
14554
  this.signatureData = util.concat(arr);
14450
14555
 
14451
- if (this.version === 6) {
14452
- const saltLength = saltLengthForHash(this.hashAlgorithm);
14453
- if (this.salt === null) {
14454
- this.salt = mod$1.random.getRandomBytes(saltLength);
14455
- } else if (saltLength !== this.salt.length) {
14456
- throw new Error('Provided salt does not have the required length');
14457
- }
14458
- }
14459
14556
  const toHash = this.toHash(this.signatureType, data, detached);
14460
14557
  const hash = await this.hash(this.signatureType, data, toHash, detached);
14461
14558
 
@@ -16257,9 +16354,12 @@ class PublicKeyEncryptedSessionKeyPacket {
16257
16354
  }
16258
16355
  this.publicKeyAlgorithm = bytes[offset++];
16259
16356
  this.encrypted = mod$1.parseEncSessionKeyParams(this.publicKeyAlgorithm, bytes.subarray(offset));
16260
- if (this.version === 3 && (
16261
- this.publicKeyAlgorithm === enums.publicKey.x25519 || this.publicKeyAlgorithm === enums.publicKey.x448)) {
16262
- this.sessionKeyAlgorithm = enums.write(enums.symmetric, this.encrypted.C.algorithm);
16357
+ if (this.publicKeyAlgorithm === enums.publicKey.x25519 || this.publicKeyAlgorithm === enums.publicKey.x448) {
16358
+ if (this.version === 3) {
16359
+ this.sessionKeyAlgorithm = enums.write(enums.symmetric, this.encrypted.C.algorithm);
16360
+ } else if (this.encrypted.C.algorithm !== null) {
16361
+ throw new Error('Unexpected cleartext symmetric algorithm');
16362
+ }
16263
16363
  }
16264
16364
  }
16265
16365
 
@@ -16303,10 +16403,13 @@ class PublicKeyEncryptedSessionKeyPacket {
16303
16403
  */
16304
16404
  async encrypt(key) {
16305
16405
  const algo = enums.write(enums.publicKey, this.publicKeyAlgorithm);
16306
- const encoded = encodeSessionKey(this.version, algo, this.sessionKeyAlgorithm, this.sessionKey);
16406
+ // No symmetric encryption algorithm identifier is passed to the public-key algorithm for a
16407
+ // v6 PKESK packet, as it is included in the v2 SEIPD packet.
16408
+ const sessionKeyAlgorithm = this.version === 3 ? this.sessionKeyAlgorithm : null;
16409
+ const encoded = encodeSessionKey(this.version, algo, sessionKeyAlgorithm, this.sessionKey);
16307
16410
  const privateParams = algo === enums.publicKey.aead ? key.privateParams : null;
16308
16411
  this.encrypted = await mod$1.publicKeyEncrypt(
16309
- algo, this.sessionKeyAlgorithm, key.publicParams, privateParams, encoded, key.getFingerprintBytes());
16412
+ algo, sessionKeyAlgorithm, key.publicParams, privateParams, encoded, key.getFingerprintBytes());
16310
16413
  }
16311
16414
 
16312
16415
  /**
@@ -16405,6 +16508,7 @@ function decodeSessionKey(version, keyAlgo, decryptedData, randomSessionKey) {
16405
16508
  case enums.publicKey.x25519:
16406
16509
  case enums.publicKey.x448:
16407
16510
  return {
16511
+ sessionKeyAlgorithm: null,
16408
16512
  sessionKey: decryptedData
16409
16513
  };
16410
16514
  default:
@@ -18092,7 +18196,9 @@ class Signature {
18092
18196
  * @returns {ReadableStream<String>} ASCII armor.
18093
18197
  */
18094
18198
  armor(config$1 = config) {
18095
- return armor(enums.armor.signature, this.write(), undefined, undefined, undefined, config$1);
18199
+ // An ASCII-armored sequence of Signature packets that only includes v6 Signature packets MUST NOT contain a CRC24 footer.
18200
+ const emitChecksum = this.packets.some(packet => packet.constructor.tag === SignaturePacket.tag && packet.version !== 6);
18201
+ return armor(enums.armor.signature, this.write(), undefined, undefined, undefined, emitChecksum, config$1);
18096
18202
  }
18097
18203
 
18098
18204
  /**
@@ -18305,7 +18411,7 @@ async function getPreferredCompressionAlgo(keys = [], date = new Date(), userIDs
18305
18411
  async function getPreferredCipherSuite(keys = [], date = new Date(), userIDs = [], config$1 = config) {
18306
18412
  const selfSigs = await Promise.all(keys.map((key, i) => key.getPrimarySelfSignature(date, userIDs[i], config$1)));
18307
18413
  const withAEAD = keys.length ?
18308
- selfSigs.every(selfSig => selfSig.features[0] & enums.features.seipdv2) :
18414
+ selfSigs.every(selfSig => selfSig.features && (selfSig.features[0] & enums.features.seipdv2)) :
18309
18415
  config$1.aeadProtect;
18310
18416
 
18311
18417
  if (withAEAD) {
@@ -18352,8 +18458,8 @@ async function createSignaturePacket(dataToSign, privateKey, signingKeyPacket, s
18352
18458
  Object.assign(signaturePacket, signatureProperties);
18353
18459
  signaturePacket.publicKeyAlgorithm = signingKeyPacket.algorithm;
18354
18460
  signaturePacket.hashAlgorithm = await getPreferredHashAlgo(privateKey, signingKeyPacket, date, userID, config);
18355
- signaturePacket.rawNotations = notations;
18356
- await signaturePacket.sign(signingKeyPacket, dataToSign, date, detached);
18461
+ signaturePacket.rawNotations = [...notations];
18462
+ await signaturePacket.sign(signingKeyPacket, dataToSign, date, detached, config);
18357
18463
  return signaturePacket;
18358
18464
  }
18359
18465
 
@@ -18416,7 +18522,7 @@ async function isDataRevoked(primaryKey, signatureType, dataToVerify, revocation
18416
18522
  !signature || revocationSignature.issuerKeyID.equals(signature.issuerKeyID)
18417
18523
  ) {
18418
18524
  await revocationSignature.verify(
18419
- key, signatureType, dataToVerify, config.revocationsExpire ? date : null, false, config
18525
+ key, signatureType, dataToVerify, date, false, config
18420
18526
  );
18421
18527
 
18422
18528
  // TODO get an identifier of the revoked object instead
@@ -19686,7 +19792,9 @@ class Key {
19686
19792
  const revocationSignature = await getLatestValidSignature(this.revocationSignatures, this.keyPacket, enums.signature.keyRevocation, dataToVerify, date, config$1);
19687
19793
  const packetlist = new PacketList();
19688
19794
  packetlist.push(revocationSignature);
19689
- return armor(enums.armor.publicKey, packetlist.write(), null, null, 'This is a revocation certificate');
19795
+ // An ASCII-armored Transferable Public Key packet sequence of a v6 key MUST NOT contain a CRC24 footer.
19796
+ const emitChecksum = this.keyPacket.version !== 6;
19797
+ return armor(enums.armor.publicKey, packetlist.write(), null, null, 'This is a revocation certificate', emitChecksum, config$1);
19690
19798
  }
19691
19799
 
19692
19800
  /**
@@ -19876,7 +19984,9 @@ class PublicKey extends Key {
19876
19984
  * @returns {ReadableStream<String>} ASCII armor.
19877
19985
  */
19878
19986
  armor(config$1 = config) {
19879
- return armor(enums.armor.publicKey, this.toPacketList().write(), undefined, undefined, undefined, config$1);
19987
+ // An ASCII-armored Transferable Public Key packet sequence of a v6 key MUST NOT contain a CRC24 footer.
19988
+ const emitChecksum = this.keyPacket.version !== 6;
19989
+ return armor(enums.armor.publicKey, this.toPacketList().write(), undefined, undefined, undefined, emitChecksum, config$1);
19880
19990
  }
19881
19991
  }
19882
19992
 
@@ -19949,7 +20059,9 @@ class PrivateKey extends PublicKey {
19949
20059
  * @returns {ReadableStream<String>} ASCII armor.
19950
20060
  */
19951
20061
  armor(config$1 = config) {
19952
- return armor(enums.armor.privateKey, this.toPacketList().write(), undefined, undefined, undefined, config$1);
20062
+ // An ASCII-armored Transferable Public Key packet sequence of a v6 key MUST NOT contain a CRC24 footer.
20063
+ const emitChecksum = this.keyPacket.version !== 6;
20064
+ return armor(enums.armor.privateKey, this.toPacketList().write(), undefined, undefined, undefined, emitChecksum, config$1);
19953
20065
  }
19954
20066
 
19955
20067
  /**
@@ -21268,7 +21380,13 @@ class Message {
21268
21380
  * @returns {ReadableStream<String>} ASCII armor.
21269
21381
  */
21270
21382
  armor(config$1 = config) {
21271
- return armor(enums.armor.message, this.write(), null, null, null, config$1);
21383
+ const trailingPacket = this.packets[this.packets.length - 1];
21384
+ // An ASCII-armored Encrypted Message packet sequence that ends in an v2 SEIPD packet MUST NOT contain a CRC24 footer.
21385
+ // An ASCII-armored sequence of Signature packets that only includes v6 Signature packets MUST NOT contain a CRC24 footer.
21386
+ const emitChecksum = trailingPacket.constructor.tag === SymEncryptedIntegrityProtectedDataPacket.tag ?
21387
+ trailingPacket.version !== 2 :
21388
+ this.packets.some(packet => packet.constructor.tag === SignaturePacket.tag && packet.version !== 6);
21389
+ return armor(enums.armor.message, this.write(), null, null, null, emitChecksum, config$1);
21272
21390
  }
21273
21391
  }
21274
21392
 
@@ -21603,9 +21721,9 @@ class CleartextMessage {
21603
21721
  * @returns {String | ReadableStream<String>} ASCII armor.
21604
21722
  */
21605
21723
  armor(config$1 = config) {
21606
- // emit header if one of the signatures has a version not 6
21607
- const emitHeader = this.signature.packets.some(packet => packet.version !== 6);
21608
- const hash = emitHeader ?
21724
+ // emit header and checksum if one of the signatures has a version not 6
21725
+ const emitHeaderAndChecksum = this.signature.packets.some(packet => packet.version !== 6);
21726
+ const hash = emitHeaderAndChecksum ?
21609
21727
  Array.from(new Set(this.signature.packets.map(
21610
21728
  packet => enums.read(enums.hash, packet.hashAlgorithm).toUpperCase()
21611
21729
  ))).join() :
@@ -21616,7 +21734,9 @@ class CleartextMessage {
21616
21734
  text: this.text,
21617
21735
  data: this.signature.packets.write()
21618
21736
  };
21619
- return armor(enums.armor.signed, body, undefined, undefined, undefined, config$1);
21737
+
21738
+ // An ASCII-armored sequence of Signature packets that only includes v6 Signature packets MUST NOT contain a CRC24 footer.
21739
+ return armor(enums.armor.signed, body, undefined, undefined, undefined, emitHeaderAndChecksum, config$1);
21620
21740
  }
21621
21741
  }
21622
21742