@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
package/dist/openpgp.mjs CHANGED
@@ -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
  const globalThis = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
3
3
 
4
4
  const doneWritingPromise = Symbol('doneWritingPromise');
@@ -1577,11 +1577,6 @@ var config = {
1577
1577
  * @property {Boolean} passwordCollisionCheck
1578
1578
  */
1579
1579
  passwordCollisionCheck: false,
1580
- /**
1581
- * @memberof module:config
1582
- * @property {Boolean} revocationsExpire If true, expired revocation signatures are ignored
1583
- */
1584
- revocationsExpire: false,
1585
1580
  /**
1586
1581
  * Allow decryption using RSA keys without `encrypt` flag.
1587
1582
  * This setting is potentially insecure, but it is needed to get around an old openpgpjs bug
@@ -1657,7 +1652,7 @@ var config = {
1657
1652
  * @memberof module:config
1658
1653
  * @property {String} versionString A version string to be included in armored messages
1659
1654
  */
1660
- versionString: 'OpenPGP.js 6.0.0-alpha.1.patch.1',
1655
+ versionString: 'OpenPGP.js 6.0.0-beta.0',
1661
1656
  /**
1662
1657
  * @memberof module:config
1663
1658
  * @property {String} commentString A comment string to be included in armored messages
@@ -1677,6 +1672,14 @@ var config = {
1677
1672
  * @property {Array} knownNotations
1678
1673
  */
1679
1674
  knownNotations: [],
1675
+ /**
1676
+ * If true, a salt notation is used to randomize signatures generated by v4 and v5 keys (v6 signatures are always non-deterministic, by design).
1677
+ * This protects EdDSA signatures from potentially leaking the secret key in case of faults (i.e. bitflips) which, in principle, could occur
1678
+ * 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
1679
+ * weaknesses in the hash algo, potentially hindering e.g. some chosen-prefix attacks.
1680
+ * 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.
1681
+ */
1682
+ nonDeterministicSignaturesViaNotation: true,
1680
1683
  /**
1681
1684
  * Whether to use the the noble-curves library for curves (other than Curve25519) that are not supported by the available native crypto API.
1682
1685
  * When false, certain standard curves will not be supported (depending on the platform).
@@ -1707,14 +1710,7 @@ var config = {
1707
1710
  * @memberof module:config
1708
1711
  * @property {Set<String>} rejectCurves {@link module:enums.curve}
1709
1712
  */
1710
- rejectCurves: new Set([enums.curve.secp256k1]),
1711
- /**
1712
- * Whether to validate generated EdDSA signatures before returning them, to ensure they are not faulty signatures.
1713
- * This check will make signing 2-3 times slower.
1714
- * Faulty signatures may be generated (in principle) if random bitflips occur at specific points in the signature
1715
- * computation, and could be used to recover the signer's secret key given a second signature over the same data.
1716
- */
1717
- checkEdDSAFaultySignatures: true
1713
+ rejectCurves: new Set([enums.curve.secp256k1])
1718
1714
  };
1719
1715
 
1720
1716
  /**
@@ -2200,16 +2196,19 @@ const util = {
2200
2196
  },
2201
2197
 
2202
2198
  /**
2203
- * Test email format based on W3C HTML5 specification.
2204
- * This check is not exaustive, and does not match RFC 5322 exactly
2205
- * (see https://html.spec.whatwg.org/multipage/input.html#email-state-(type=email)),
2206
- * but is commonly used for email address validation.
2199
+ * Test email format to ensure basic compliance:
2200
+ * - must include a single @
2201
+ * - no control or space unicode chars allowed
2202
+ * - no backslash and square brackets (as the latter can mess with the userID parsing)
2203
+ * - cannot end with a punctuation char
2204
+ * These checks are not meant to be exhaustive; applications are strongly encouraged to implement stricter validation,
2205
+ * e.g. based on the W3C HTML spec (https://html.spec.whatwg.org/multipage/input.html#email-state-(type=email)).
2207
2206
  */
2208
2207
  isEmailAddress: function(data) {
2209
2208
  if (!util.isString(data)) {
2210
2209
  return false;
2211
2210
  }
2212
- 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])?)*$/;
2211
+ const re = /^[^\p{C}\p{Z}@<>\\]+@[^\p{C}\p{Z}@<>\\]+[^\p{C}\p{Z}\p{P}]$/u;
2213
2212
  return re.test(data);
2214
2213
  },
2215
2214
 
@@ -2615,6 +2614,78 @@ function addheader(customComment, config) {
2615
2614
  return result;
2616
2615
  }
2617
2616
 
2617
+ /**
2618
+ * Calculates a checksum over the given data and returns it base64 encoded
2619
+ * @param {String | ReadableStream<String>} data - Data to create a CRC-24 checksum for
2620
+ * @returns {String | ReadableStream<String>} Base64 encoded checksum.
2621
+ * @private
2622
+ */
2623
+ function getCheckSum(data) {
2624
+ const crc = createcrc24(data);
2625
+ return encode$1(crc);
2626
+ }
2627
+
2628
+ // https://create.stephan-brumme.com/crc32/#slicing-by-8-overview
2629
+
2630
+ const crc_table = [
2631
+ new Array(0xFF),
2632
+ new Array(0xFF),
2633
+ new Array(0xFF),
2634
+ new Array(0xFF)
2635
+ ];
2636
+
2637
+ for (let i = 0; i <= 0xFF; i++) {
2638
+ let crc = i << 16;
2639
+ for (let j = 0; j < 8; j++) {
2640
+ crc = (crc << 1) ^ ((crc & 0x800000) !== 0 ? 0x864CFB : 0);
2641
+ }
2642
+ crc_table[0][i] =
2643
+ ((crc & 0xFF0000) >> 16) |
2644
+ (crc & 0x00FF00) |
2645
+ ((crc & 0x0000FF) << 16);
2646
+ }
2647
+ for (let i = 0; i <= 0xFF; i++) {
2648
+ crc_table[1][i] = (crc_table[0][i] >> 8) ^ crc_table[0][crc_table[0][i] & 0xFF];
2649
+ }
2650
+ for (let i = 0; i <= 0xFF; i++) {
2651
+ crc_table[2][i] = (crc_table[1][i] >> 8) ^ crc_table[0][crc_table[1][i] & 0xFF];
2652
+ }
2653
+ for (let i = 0; i <= 0xFF; i++) {
2654
+ crc_table[3][i] = (crc_table[2][i] >> 8) ^ crc_table[0][crc_table[2][i] & 0xFF];
2655
+ }
2656
+
2657
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView#Endianness
2658
+ const isLittleEndian$1 = (function() {
2659
+ const buffer = new ArrayBuffer(2);
2660
+ new DataView(buffer).setInt16(0, 0xFF, true /* littleEndian */);
2661
+ // Int16Array uses the platform's endianness.
2662
+ return new Int16Array(buffer)[0] === 0xFF;
2663
+ }());
2664
+
2665
+ /**
2666
+ * Internal function to calculate a CRC-24 checksum over a given string (data)
2667
+ * @param {String | ReadableStream<String>} input - Data to create a CRC-24 checksum for
2668
+ * @returns {Uint8Array | ReadableStream<Uint8Array>} The CRC-24 checksum.
2669
+ * @private
2670
+ */
2671
+ function createcrc24(input) {
2672
+ let crc = 0xCE04B7;
2673
+ return transform(input, value => {
2674
+ const len32 = isLittleEndian$1 ? Math.floor(value.length / 4) : 0;
2675
+ const arr32 = new Uint32Array(value.buffer, value.byteOffset, len32);
2676
+ for (let i = 0; i < len32; i++) {
2677
+ crc ^= arr32[i];
2678
+ crc =
2679
+ crc_table[0][(crc >> 24) & 0xFF] ^
2680
+ crc_table[1][(crc >> 16) & 0xFF] ^
2681
+ crc_table[2][(crc >> 8) & 0xFF] ^
2682
+ crc_table[3][(crc >> 0) & 0xFF];
2683
+ }
2684
+ for (let i = len32 * 4; i < value.length; i++) {
2685
+ crc = (crc >> 8) ^ crc_table[0][(crc & 0xFF) ^ value[i]];
2686
+ }
2687
+ }, () => new Uint8Array([crc, crc >> 8, crc >> 16]));
2688
+ }
2618
2689
 
2619
2690
  /**
2620
2691
  * Verify armored headers. crypto-refresh-06, section 6.2:
@@ -2770,10 +2841,13 @@ function unarmor(input) {
2770
2841
  * @param {Integer} [partIndex]
2771
2842
  * @param {Integer} [partTotal]
2772
2843
  * @param {String} [customComment] - Additional comment to add to the armored string
2844
+ * @param {Boolean} [emitChecksum] - Whether to compute and include the CRC checksum
2845
+ * (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)
2846
+ * @param {Object} [config] - Full configuration, defaults to openpgp.config
2773
2847
  * @returns {String | ReadableStream<String>} Armored text.
2774
2848
  * @static
2775
2849
  */
2776
- function armor(messageType, body, partIndex, partTotal, customComment, config$1 = config) {
2850
+ function armor(messageType, body, partIndex, partTotal, customComment, emitChecksum = false, config$1 = config) {
2777
2851
  let text;
2778
2852
  let hash;
2779
2853
  if (messageType === enums.armor.signed) {
@@ -2781,18 +2855,24 @@ function armor(messageType, body, partIndex, partTotal, customComment, config$1
2781
2855
  hash = body.hash;
2782
2856
  body = body.data;
2783
2857
  }
2858
+ // unless explicitly forbidden by the spec, we need to include the checksum to work around a GnuPG bug
2859
+ // where data fails to be decoded if the base64 ends with no padding chars (=) (see https://dev.gnupg.org/T7071)
2860
+ const maybeBodyClone = emitChecksum && passiveClone(body);
2861
+
2784
2862
  const result = [];
2785
2863
  switch (messageType) {
2786
2864
  case enums.armor.multipartSection:
2787
2865
  result.push('-----BEGIN PGP MESSAGE, PART ' + partIndex + '/' + partTotal + '-----\n');
2788
2866
  result.push(addheader(customComment, config$1));
2789
2867
  result.push(encode$1(body));
2868
+ maybeBodyClone && result.push('=', getCheckSum(maybeBodyClone));
2790
2869
  result.push('-----END PGP MESSAGE, PART ' + partIndex + '/' + partTotal + '-----\n');
2791
2870
  break;
2792
2871
  case enums.armor.multipartLast:
2793
2872
  result.push('-----BEGIN PGP MESSAGE, PART ' + partIndex + '-----\n');
2794
2873
  result.push(addheader(customComment, config$1));
2795
2874
  result.push(encode$1(body));
2875
+ maybeBodyClone && result.push('=', getCheckSum(maybeBodyClone));
2796
2876
  result.push('-----END PGP MESSAGE, PART ' + partIndex + '-----\n');
2797
2877
  break;
2798
2878
  case enums.armor.signed:
@@ -2802,30 +2882,35 @@ function armor(messageType, body, partIndex, partTotal, customComment, config$1
2802
2882
  result.push('\n-----BEGIN PGP SIGNATURE-----\n');
2803
2883
  result.push(addheader(customComment, config$1));
2804
2884
  result.push(encode$1(body));
2885
+ maybeBodyClone && result.push('=', getCheckSum(maybeBodyClone));
2805
2886
  result.push('-----END PGP SIGNATURE-----\n');
2806
2887
  break;
2807
2888
  case enums.armor.message:
2808
2889
  result.push('-----BEGIN PGP MESSAGE-----\n');
2809
2890
  result.push(addheader(customComment, config$1));
2810
2891
  result.push(encode$1(body));
2892
+ maybeBodyClone && result.push('=', getCheckSum(maybeBodyClone));
2811
2893
  result.push('-----END PGP MESSAGE-----\n');
2812
2894
  break;
2813
2895
  case enums.armor.publicKey:
2814
2896
  result.push('-----BEGIN PGP PUBLIC KEY BLOCK-----\n');
2815
2897
  result.push(addheader(customComment, config$1));
2816
2898
  result.push(encode$1(body));
2899
+ maybeBodyClone && result.push('=', getCheckSum(maybeBodyClone));
2817
2900
  result.push('-----END PGP PUBLIC KEY BLOCK-----\n');
2818
2901
  break;
2819
2902
  case enums.armor.privateKey:
2820
2903
  result.push('-----BEGIN PGP PRIVATE KEY BLOCK-----\n');
2821
2904
  result.push(addheader(customComment, config$1));
2822
2905
  result.push(encode$1(body));
2906
+ maybeBodyClone && result.push('=', getCheckSum(maybeBodyClone));
2823
2907
  result.push('-----END PGP PRIVATE KEY BLOCK-----\n');
2824
2908
  break;
2825
2909
  case enums.armor.signature:
2826
2910
  result.push('-----BEGIN PGP SIGNATURE-----\n');
2827
2911
  result.push(addheader(customComment, config$1));
2828
2912
  result.push(encode$1(body));
2913
+ maybeBodyClone && result.push('=', getCheckSum(maybeBodyClone));
2829
2914
  result.push('-----END PGP SIGNATURE-----\n');
2830
2915
  break;
2831
2916
  }
@@ -9352,20 +9437,6 @@ async function sign$5(oid, hashAlgo, message, publicKey, privateKey, hashed) {
9352
9437
  }
9353
9438
  const secretKey = util.concatUint8Array([privateKey, publicKey.subarray(1)]);
9354
9439
  const signature = nacl.sign.detached(hashed, secretKey);
9355
- if (config.checkEdDSAFaultySignatures && !nacl.sign.detached.verify(hashed, signature, publicKey.subarray(1))) {
9356
- /**
9357
- * Detect faulty signatures caused by random bitflips during `crypto_sign` which could lead to private key extraction
9358
- * if two signatures over the same message are obtained.
9359
- * See https://github.com/jedisct1/libsodium/issues/170.
9360
- * If the input data is not deterministic, e.g. thanks to the random salt in v6 OpenPGP signatures (not yet implemented),
9361
- * then the generated signature is always safe, and the verification step is skipped.
9362
- * Otherwise, we need to verify the generated to ensure that no bitflip occured:
9363
- * - in M between the computation of `r` and `h`.
9364
- * - in the public key before computing `h`
9365
- * 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.
9366
- */
9367
- throw new Error('Transient signing failure');
9368
- }
9369
9440
  // EdDSA signature params are returned in little-endian format
9370
9441
  return {
9371
9442
  r: signature.subarray(0, 32),
@@ -9486,20 +9557,6 @@ async function sign$4(algo, hashAlgo, message, publicKey, privateKey, hashed) {
9486
9557
  case enums.publicKey.ed25519: {
9487
9558
  const secretKey = util.concatUint8Array([privateKey, publicKey]);
9488
9559
  const signature = nacl.sign.detached(hashed, secretKey);
9489
- if (config.checkEdDSAFaultySignatures && !nacl.sign.detached.verify(hashed, signature, publicKey)) {
9490
- /**
9491
- * Detect faulty signatures caused by random bitflips during `crypto_sign` which could lead to private key extraction
9492
- * if two signatures over the same message are obtained.
9493
- * See https://github.com/jedisct1/libsodium/issues/170.
9494
- * If the input data is not deterministic, e.g. thanks to the random salt in v6 OpenPGP signatures (not yet implemented),
9495
- * then the generated signature is always safe, and the verification step is skipped.
9496
- * Otherwise, we need to verify the generated to ensure that no bitflip occured:
9497
- * - in M between the computation of `r` and `h`.
9498
- * - in the public key before computing `h`
9499
- * 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.
9500
- */
9501
- throw new Error('Transient signing failure');
9502
- }
9503
9560
  return { RS: signature };
9504
9561
  }
9505
9562
  case enums.publicKey.ed448: {
@@ -11232,7 +11289,7 @@ class ECDHXSymmetricKey {
11232
11289
  * Encrypts data using specified algorithm and public key parameters.
11233
11290
  * See {@link https://tools.ietf.org/html/rfc4880#section-9.1|RFC 4880 9.1} for public key algorithms.
11234
11291
  * @param {module:enums.publicKey} keyAlgo - Public key algorithm
11235
- * @param {module:enums.symmetric} symmetricAlgo - Cipher algorithm
11292
+ * @param {module:enums.symmetric|null} symmetricAlgo - Cipher algorithm (v3 only)
11236
11293
  * @param {Object} publicParams - Algorithm-specific public key parameters
11237
11294
  * @param {Object} privateParams - Algorithm-specific private key parameters
11238
11295
  * @param {Uint8Array} data - Data to be encrypted
@@ -11260,7 +11317,7 @@ async function publicKeyEncrypt(keyAlgo, symmetricAlgo, publicParams, privatePar
11260
11317
  }
11261
11318
  case enums.publicKey.x25519:
11262
11319
  case enums.publicKey.x448: {
11263
- if (!util.isAES(symmetricAlgo)) {
11320
+ if (symmetricAlgo && !util.isAES(symmetricAlgo)) {
11264
11321
  // see https://gitlab.com/openpgp-wg/rfc4880bis/-/merge_requests/276
11265
11322
  throw new Error('X25519 and X448 keys can only encrypt AES session keys');
11266
11323
  }
@@ -11892,9 +11949,26 @@ class Argon2OutOfMemoryError extends Error {
11892
11949
  let loadArgonWasmModule;
11893
11950
  let argon2Promise;
11894
11951
  // reload wasm module above this treshold, to deallocated used memory
11895
- const ARGON2_WASM_MEMORY_THRESHOLD_RELOAD = 2 << 19;
11952
+ // (cannot be declared as a simple `static` field as its not supported by Safari 14)
11953
+ let ARGON2_WASM_MEMORY_THRESHOLD_RELOAD = 2 << 19;
11896
11954
 
11897
11955
  class Argon2S2K {
11956
+ static get ARGON2_WASM_MEMORY_THRESHOLD_RELOAD() {
11957
+ return ARGON2_WASM_MEMORY_THRESHOLD_RELOAD;
11958
+ }
11959
+
11960
+ static set ARGON2_WASM_MEMORY_THRESHOLD_RELOAD(memoryThreshold) {
11961
+ ARGON2_WASM_MEMORY_THRESHOLD_RELOAD = memoryThreshold;
11962
+ }
11963
+
11964
+ static reloadWasmModule() {
11965
+ if (!loadArgonWasmModule) return;
11966
+
11967
+ // it will be awaited if needed at the next `produceKey` invocation
11968
+ argon2Promise = loadArgonWasmModule();
11969
+ argon2Promise.catch(() => {});
11970
+ }
11971
+
11898
11972
  /**
11899
11973
  * @param {Object} [config] - Full configuration, defaults to openpgp.config
11900
11974
  */
@@ -11982,10 +12056,8 @@ class Argon2S2K {
11982
12056
  });
11983
12057
 
11984
12058
  // a lot of memory was used, reload to deallocate
11985
- if (decodedM > ARGON2_WASM_MEMORY_THRESHOLD_RELOAD) {
11986
- // it will be awaited if needed at the next `produceKey` invocation
11987
- argon2Promise = loadArgonWasmModule();
11988
- argon2Promise.catch(() => {});
12059
+ if (decodedM > Argon2S2K.ARGON2_WASM_MEMORY_THRESHOLD_RELOAD) {
12060
+ Argon2S2K.reloadWasmModule();
11989
12061
  }
11990
12062
  return hash;
11991
12063
  } catch (e) {
@@ -14234,6 +14306,14 @@ class KeyID {
14234
14306
  // Symbol to store cryptographic validity of the signature, to avoid recomputing multiple times on verification.
14235
14307
  const verified = Symbol('verified');
14236
14308
 
14309
+ // A salt notation is used to randomize signatures.
14310
+ // This is to protect EdDSA signatures in particular, which are known to be vulnerable to fault attacks
14311
+ // leading to secret key extraction if two signatures over the same data can be collected (see https://github.com/jedisct1/libsodium/issues/170).
14312
+ // 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.
14313
+ // some chosen-prefix attacks.
14314
+ // v6 signatures do not need to rely on this notation, as they already include a separate, built-in salt.
14315
+ const SALT_NOTATION_NAME = 'salt@notations.openpgpjs.org';
14316
+
14237
14317
  // GPG puts the Issuer and Signature subpackets in the unhashed area.
14238
14318
  // Tampering with those invalidates the signature, so we still trust them and parse them.
14239
14319
  // All other unhashed subpackets are ignored.
@@ -14403,7 +14483,7 @@ class SignaturePacket {
14403
14483
  * @throws {Error} if signing failed
14404
14484
  * @async
14405
14485
  */
14406
- async sign(key, data, date = new Date(), detached = false) {
14486
+ async sign(key, data, date = new Date(), detached = false, config) {
14407
14487
  this.version = key.version;
14408
14488
 
14409
14489
  this.created = util.normalizeDate(date);
@@ -14413,6 +14493,31 @@ class SignaturePacket {
14413
14493
 
14414
14494
  const arr = [new Uint8Array([this.version, this.signatureType, this.publicKeyAlgorithm, this.hashAlgorithm])];
14415
14495
 
14496
+ // add randomness to the signature
14497
+ if (this.version === 6) {
14498
+ const saltLength = saltLengthForHash(this.hashAlgorithm);
14499
+ if (this.salt === null) {
14500
+ this.salt = mod$1.random.getRandomBytes(saltLength);
14501
+ } else if (saltLength !== this.salt.length) {
14502
+ throw new Error('Provided salt does not have the required length');
14503
+ }
14504
+ } else if (config.nonDeterministicSignaturesViaNotation) {
14505
+ const saltNotations = this.rawNotations.filter(({ name }) => (name === SALT_NOTATION_NAME));
14506
+ // since re-signing the same object is not supported, it's not expected to have multiple salt notations,
14507
+ // but we guard against it as a sanity check
14508
+ if (saltNotations.length === 0) {
14509
+ const saltValue = mod$1.random.getRandomBytes(saltLengthForHash(this.hashAlgorithm));
14510
+ this.rawNotations.push({
14511
+ name: SALT_NOTATION_NAME,
14512
+ value: saltValue,
14513
+ humanReadable: false,
14514
+ critical: false
14515
+ });
14516
+ } else {
14517
+ throw new Error('Unexpected existing salt notation');
14518
+ }
14519
+ }
14520
+
14416
14521
  // Add hashed subpackets
14417
14522
  arr.push(this.writeHashedSubPackets());
14418
14523
 
@@ -14423,14 +14528,6 @@ class SignaturePacket {
14423
14528
 
14424
14529
  this.signatureData = util.concat(arr);
14425
14530
 
14426
- if (this.version === 6) {
14427
- const saltLength = saltLengthForHash(this.hashAlgorithm);
14428
- if (this.salt === null) {
14429
- this.salt = mod$1.random.getRandomBytes(saltLength);
14430
- } else if (saltLength !== this.salt.length) {
14431
- throw new Error('Provided salt does not have the required length');
14432
- }
14433
- }
14434
14531
  const toHash = this.toHash(this.signatureType, data, detached);
14435
14532
  const hash = await this.hash(this.signatureType, data, toHash, detached);
14436
14533
 
@@ -16232,9 +16329,12 @@ class PublicKeyEncryptedSessionKeyPacket {
16232
16329
  }
16233
16330
  this.publicKeyAlgorithm = bytes[offset++];
16234
16331
  this.encrypted = mod$1.parseEncSessionKeyParams(this.publicKeyAlgorithm, bytes.subarray(offset));
16235
- if (this.version === 3 && (
16236
- this.publicKeyAlgorithm === enums.publicKey.x25519 || this.publicKeyAlgorithm === enums.publicKey.x448)) {
16237
- this.sessionKeyAlgorithm = enums.write(enums.symmetric, this.encrypted.C.algorithm);
16332
+ if (this.publicKeyAlgorithm === enums.publicKey.x25519 || this.publicKeyAlgorithm === enums.publicKey.x448) {
16333
+ if (this.version === 3) {
16334
+ this.sessionKeyAlgorithm = enums.write(enums.symmetric, this.encrypted.C.algorithm);
16335
+ } else if (this.encrypted.C.algorithm !== null) {
16336
+ throw new Error('Unexpected cleartext symmetric algorithm');
16337
+ }
16238
16338
  }
16239
16339
  }
16240
16340
 
@@ -16278,10 +16378,13 @@ class PublicKeyEncryptedSessionKeyPacket {
16278
16378
  */
16279
16379
  async encrypt(key) {
16280
16380
  const algo = enums.write(enums.publicKey, this.publicKeyAlgorithm);
16281
- const encoded = encodeSessionKey(this.version, algo, this.sessionKeyAlgorithm, this.sessionKey);
16381
+ // No symmetric encryption algorithm identifier is passed to the public-key algorithm for a
16382
+ // v6 PKESK packet, as it is included in the v2 SEIPD packet.
16383
+ const sessionKeyAlgorithm = this.version === 3 ? this.sessionKeyAlgorithm : null;
16384
+ const encoded = encodeSessionKey(this.version, algo, sessionKeyAlgorithm, this.sessionKey);
16282
16385
  const privateParams = algo === enums.publicKey.aead ? key.privateParams : null;
16283
16386
  this.encrypted = await mod$1.publicKeyEncrypt(
16284
- algo, this.sessionKeyAlgorithm, key.publicParams, privateParams, encoded, key.getFingerprintBytes());
16387
+ algo, sessionKeyAlgorithm, key.publicParams, privateParams, encoded, key.getFingerprintBytes());
16285
16388
  }
16286
16389
 
16287
16390
  /**
@@ -16380,6 +16483,7 @@ function decodeSessionKey(version, keyAlgo, decryptedData, randomSessionKey) {
16380
16483
  case enums.publicKey.x25519:
16381
16484
  case enums.publicKey.x448:
16382
16485
  return {
16486
+ sessionKeyAlgorithm: null,
16383
16487
  sessionKey: decryptedData
16384
16488
  };
16385
16489
  default:
@@ -18067,7 +18171,9 @@ class Signature {
18067
18171
  * @returns {ReadableStream<String>} ASCII armor.
18068
18172
  */
18069
18173
  armor(config$1 = config) {
18070
- return armor(enums.armor.signature, this.write(), undefined, undefined, undefined, config$1);
18174
+ // An ASCII-armored sequence of Signature packets that only includes v6 Signature packets MUST NOT contain a CRC24 footer.
18175
+ const emitChecksum = this.packets.some(packet => packet.constructor.tag === SignaturePacket.tag && packet.version !== 6);
18176
+ return armor(enums.armor.signature, this.write(), undefined, undefined, undefined, emitChecksum, config$1);
18071
18177
  }
18072
18178
 
18073
18179
  /**
@@ -18280,7 +18386,7 @@ async function getPreferredCompressionAlgo(keys = [], date = new Date(), userIDs
18280
18386
  async function getPreferredCipherSuite(keys = [], date = new Date(), userIDs = [], config$1 = config) {
18281
18387
  const selfSigs = await Promise.all(keys.map((key, i) => key.getPrimarySelfSignature(date, userIDs[i], config$1)));
18282
18388
  const withAEAD = keys.length ?
18283
- selfSigs.every(selfSig => selfSig.features[0] & enums.features.seipdv2) :
18389
+ selfSigs.every(selfSig => selfSig.features && (selfSig.features[0] & enums.features.seipdv2)) :
18284
18390
  config$1.aeadProtect;
18285
18391
 
18286
18392
  if (withAEAD) {
@@ -18327,8 +18433,8 @@ async function createSignaturePacket(dataToSign, privateKey, signingKeyPacket, s
18327
18433
  Object.assign(signaturePacket, signatureProperties);
18328
18434
  signaturePacket.publicKeyAlgorithm = signingKeyPacket.algorithm;
18329
18435
  signaturePacket.hashAlgorithm = await getPreferredHashAlgo(privateKey, signingKeyPacket, date, userID, config);
18330
- signaturePacket.rawNotations = notations;
18331
- await signaturePacket.sign(signingKeyPacket, dataToSign, date, detached);
18436
+ signaturePacket.rawNotations = [...notations];
18437
+ await signaturePacket.sign(signingKeyPacket, dataToSign, date, detached, config);
18332
18438
  return signaturePacket;
18333
18439
  }
18334
18440
 
@@ -18391,7 +18497,7 @@ async function isDataRevoked(primaryKey, signatureType, dataToVerify, revocation
18391
18497
  !signature || revocationSignature.issuerKeyID.equals(signature.issuerKeyID)
18392
18498
  ) {
18393
18499
  await revocationSignature.verify(
18394
- key, signatureType, dataToVerify, config.revocationsExpire ? date : null, false, config
18500
+ key, signatureType, dataToVerify, date, false, config
18395
18501
  );
18396
18502
 
18397
18503
  // TODO get an identifier of the revoked object instead
@@ -19661,7 +19767,9 @@ class Key {
19661
19767
  const revocationSignature = await getLatestValidSignature(this.revocationSignatures, this.keyPacket, enums.signature.keyRevocation, dataToVerify, date, config$1);
19662
19768
  const packetlist = new PacketList();
19663
19769
  packetlist.push(revocationSignature);
19664
- return armor(enums.armor.publicKey, packetlist.write(), null, null, 'This is a revocation certificate');
19770
+ // An ASCII-armored Transferable Public Key packet sequence of a v6 key MUST NOT contain a CRC24 footer.
19771
+ const emitChecksum = this.keyPacket.version !== 6;
19772
+ return armor(enums.armor.publicKey, packetlist.write(), null, null, 'This is a revocation certificate', emitChecksum, config$1);
19665
19773
  }
19666
19774
 
19667
19775
  /**
@@ -19851,7 +19959,9 @@ class PublicKey extends Key {
19851
19959
  * @returns {ReadableStream<String>} ASCII armor.
19852
19960
  */
19853
19961
  armor(config$1 = config) {
19854
- return armor(enums.armor.publicKey, this.toPacketList().write(), undefined, undefined, undefined, config$1);
19962
+ // An ASCII-armored Transferable Public Key packet sequence of a v6 key MUST NOT contain a CRC24 footer.
19963
+ const emitChecksum = this.keyPacket.version !== 6;
19964
+ return armor(enums.armor.publicKey, this.toPacketList().write(), undefined, undefined, undefined, emitChecksum, config$1);
19855
19965
  }
19856
19966
  }
19857
19967
 
@@ -19924,7 +20034,9 @@ class PrivateKey extends PublicKey {
19924
20034
  * @returns {ReadableStream<String>} ASCII armor.
19925
20035
  */
19926
20036
  armor(config$1 = config) {
19927
- return armor(enums.armor.privateKey, this.toPacketList().write(), undefined, undefined, undefined, config$1);
20037
+ // An ASCII-armored Transferable Public Key packet sequence of a v6 key MUST NOT contain a CRC24 footer.
20038
+ const emitChecksum = this.keyPacket.version !== 6;
20039
+ return armor(enums.armor.privateKey, this.toPacketList().write(), undefined, undefined, undefined, emitChecksum, config$1);
19928
20040
  }
19929
20041
 
19930
20042
  /**
@@ -21243,7 +21355,13 @@ class Message {
21243
21355
  * @returns {ReadableStream<String>} ASCII armor.
21244
21356
  */
21245
21357
  armor(config$1 = config) {
21246
- return armor(enums.armor.message, this.write(), null, null, null, config$1);
21358
+ const trailingPacket = this.packets[this.packets.length - 1];
21359
+ // An ASCII-armored Encrypted Message packet sequence that ends in an v2 SEIPD packet MUST NOT contain a CRC24 footer.
21360
+ // An ASCII-armored sequence of Signature packets that only includes v6 Signature packets MUST NOT contain a CRC24 footer.
21361
+ const emitChecksum = trailingPacket.constructor.tag === SymEncryptedIntegrityProtectedDataPacket.tag ?
21362
+ trailingPacket.version !== 2 :
21363
+ this.packets.some(packet => packet.constructor.tag === SignaturePacket.tag && packet.version !== 6);
21364
+ return armor(enums.armor.message, this.write(), null, null, null, emitChecksum, config$1);
21247
21365
  }
21248
21366
  }
21249
21367
 
@@ -21578,9 +21696,9 @@ class CleartextMessage {
21578
21696
  * @returns {String | ReadableStream<String>} ASCII armor.
21579
21697
  */
21580
21698
  armor(config$1 = config) {
21581
- // emit header if one of the signatures has a version not 6
21582
- const emitHeader = this.signature.packets.some(packet => packet.version !== 6);
21583
- const hash = emitHeader ?
21699
+ // emit header and checksum if one of the signatures has a version not 6
21700
+ const emitHeaderAndChecksum = this.signature.packets.some(packet => packet.version !== 6);
21701
+ const hash = emitHeaderAndChecksum ?
21584
21702
  Array.from(new Set(this.signature.packets.map(
21585
21703
  packet => enums.read(enums.hash, packet.hashAlgorithm).toUpperCase()
21586
21704
  ))).join() :
@@ -21591,7 +21709,9 @@ class CleartextMessage {
21591
21709
  text: this.text,
21592
21710
  data: this.signature.packets.write()
21593
21711
  };
21594
- return armor(enums.armor.signed, body, undefined, undefined, undefined, config$1);
21712
+
21713
+ // An ASCII-armored sequence of Signature packets that only includes v6 Signature packets MUST NOT contain a CRC24 footer.
21714
+ return armor(enums.armor.signed, body, undefined, undefined, undefined, emitHeaderAndChecksum, config$1);
21595
21715
  }
21596
21716
  }
21597
21717
 
package/openpgp.d.ts CHANGED
@@ -329,7 +329,6 @@ interface Config {
329
329
  allowForwardedMessages: boolean;
330
330
  minRSABits: number;
331
331
  passwordCollisionCheck: boolean;
332
- revocationsExpire: boolean;
333
332
  ignoreUnsupportedPackets: boolean;
334
333
  ignoreMalformedPackets: boolean;
335
334
  versionString: string;
@@ -353,7 +352,7 @@ interface Config {
353
352
  rejectPublicKeyAlgorithms: Set<enums.publicKey>;
354
353
  rejectCurves: Set<enums.curve>;
355
354
  }
356
- export var config: Config & { checkEdDSAFaultySignatures: boolean }; // option only supported if set at the global openpgp.config level
355
+ export var config: Config;
357
356
 
358
357
  // PartialConfig has the same properties as Config, but declared as optional.
359
358
  // This interface is relevant for top-level functions, which accept a subset of configuration options
@@ -738,7 +737,7 @@ export interface VerifyMessageResult<T extends MaybeStream<Data> = MaybeStream<D
738
737
  /**
739
738
  * Armor an OpenPGP binary packet block
740
739
  */
741
- export function armor(messagetype: enums.armor, body: object, partindex?: number, parttotal?: number, customComment?: string, config?: Config): string;
740
+ export function armor(messagetype: enums.armor, body: object, partindex?: number, parttotal?: number, customComment?: string, emitChecksum?: boolean, config?: Config): string;
742
741
 
743
742
  /**
744
743
  * DeArmor an OpenPGP armored message; verify the checksum and return the encoded bytes
@@ -938,6 +937,8 @@ export namespace enums {
938
937
  }
939
938
 
940
939
  export declare class Argon2S2K {
940
+ static reloadWasmModule(): void;
941
+ static ARGON2_WASM_MEMORY_THRESHOLD_RELOAD: number;
941
942
  constructor(config: Config);
942
943
  salt: Uint8Array;
943
944
  /** @throws Argon2OutOfMemoryError */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@protontech/openpgp",
3
3
  "description": "OpenPGP.js is a Javascript implementation of the OpenPGP protocol. This is defined in RFC 4880.",
4
- "version": "6.0.0-alpha.1.patch.1",
4
+ "version": "6.0.0-beta.0",
5
5
  "license": "LGPL-3.0+",
6
6
  "homepage": "https://openpgpjs.org/",
7
7
  "engines": {
@@ -75,7 +75,7 @@
75
75
  "@rollup/plugin-replace": "^5.0.5",
76
76
  "@rollup/plugin-terser": "^0.4.4",
77
77
  "@rollup/plugin-wasm": "^6.2.2",
78
- "@types/chai": "^4.3.12",
78
+ "@types/chai": "^4.3.14",
79
79
  "argon2id": "^1.0.1",
80
80
  "benchmark": "^2.1.4",
81
81
  "c8": "^8.0.1",
@@ -93,17 +93,17 @@
93
93
  "karma": "^6.4.3",
94
94
  "karma-browserstack-launcher": "^1.6.0",
95
95
  "karma-chrome-launcher": "^3.2.0",
96
- "karma-firefox-launcher": "^2.1.2",
96
+ "karma-firefox-launcher": "^2.1.3",
97
97
  "karma-mocha": "^2.0.1",
98
98
  "karma-mocha-reporter": "^2.2.5",
99
99
  "karma-webkit-launcher": "^2.4.0",
100
- "mocha": "^10.3.0",
101
- "playwright": "^1.42.0",
102
- "rollup": "^4.12.0",
103
- "sinon": "^15.2.0",
100
+ "mocha": "^10.4.0",
101
+ "playwright": "^1.43.0",
102
+ "rollup": "^4.14.1",
103
+ "sinon": "^17.0.1",
104
104
  "ts-node": "^10.9.2",
105
- "tsx": "^4.7.1",
106
- "typescript": "^5.3.3",
105
+ "tsx": "^4.7.2",
106
+ "typescript": "^5.4.4",
107
107
  "web-streams-polyfill": "^3.3.3"
108
108
  },
109
109
  "repository": {