@protontech/openpgp 6.1.1-patch.2 → 6.1.1-patch.3

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.
package/dist/openpgp.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! OpenPGP.js v6.1.1-patch.2 - 2025-05-14 - this is LGPL licensed code, see LICENSE/our website https://openpgpjs.org/ for more information. */
1
+ /*! OpenPGP.js v6.1.1-patch.3 - 2025-06-18 - this is LGPL licensed code, see LICENSE/our website https://openpgpjs.org/ for more information. */
2
2
  var openpgp = (function (exports) {
3
3
  'use strict';
4
4
 
@@ -1065,11 +1065,10 @@ var openpgp = (function (exports) {
1065
1065
  ed25519: 27,
1066
1066
  /** Ed448 (Sign only) */
1067
1067
  ed448: 28,
1068
- /** Post-quantum ML-KEM-768 + X25519 (Encrypt only) */
1069
- pqc_mlkem_x25519: 105,
1070
1068
  /** Post-quantum ML-DSA-64 + Ed25519 (Sign only) */
1071
- pqc_mldsa_ed25519: 107,
1072
-
1069
+ pqc_mldsa_ed25519: 30,
1070
+ /** Post-quantum ML-KEM-768 + X25519 (Encrypt only) */
1071
+ pqc_mlkem_x25519: 35,
1073
1072
  /** Persistent symmetric keys: encryption algorithm */
1074
1073
  aead: 100,
1075
1074
  /** Persistent symmetric keys: authentication algorithm */
@@ -1720,7 +1719,7 @@ var openpgp = (function (exports) {
1720
1719
  * @memberof module:config
1721
1720
  * @property {String} versionString A version string to be included in armored messages
1722
1721
  */
1723
- versionString: 'OpenPGP.js 6.1.1-patch.2',
1722
+ versionString: 'OpenPGP.js 6.1.1-patch.3',
1724
1723
  /**
1725
1724
  * @memberof module:config
1726
1725
  * @property {String} commentString A comment string to be included in armored messages
@@ -6960,17 +6959,11 @@ var openpgp = (function (exports) {
6960
6959
  * @async
6961
6960
  */
6962
6961
  async function sign$9(algo, hashAlgo, message, publicKey, privateKey, hashed) {
6963
- if (getHashByteLength(hashAlgo) < getHashByteLength(getPreferredHashAlgo$2(algo))) {
6964
- // Enforce digest sizes:
6965
- // - Ed25519: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.4-4
6966
- // - Ed448: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.5-4
6967
- throw new Error('Hash algorithm too weak for EdDSA.');
6968
- }
6969
6962
  switch (algo) {
6970
6963
  case enums.publicKey.ed25519:
6971
6964
  try {
6972
6965
  const webCrypto = util.getWebCrypto();
6973
- const jwk = privateKeyToJWK(algo, publicKey, privateKey);
6966
+ const jwk = privateKeyToJWK$1(algo, publicKey, privateKey);
6974
6967
  const key = await webCrypto.importKey('jwk', jwk, 'Ed25519', false, ['sign']);
6975
6968
 
6976
6969
  const signature = new Uint8Array(
@@ -7010,17 +7003,11 @@ var openpgp = (function (exports) {
7010
7003
  * @async
7011
7004
  */
7012
7005
  async function verify$9(algo, hashAlgo, { RS }, m, publicKey, hashed) {
7013
- if (getHashByteLength(hashAlgo) < getHashByteLength(getPreferredHashAlgo$2(algo))) {
7014
- // Enforce digest sizes:
7015
- // - Ed25519: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.4-4
7016
- // - Ed448: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.5-4
7017
- throw new Error('Hash algorithm too weak for EdDSA.');
7018
- }
7019
7006
  switch (algo) {
7020
7007
  case enums.publicKey.ed25519:
7021
7008
  try {
7022
7009
  const webCrypto = util.getWebCrypto();
7023
- const jwk = publicKeyToJWK(algo, publicKey);
7010
+ const jwk = publicKeyToJWK$1(algo, publicKey);
7024
7011
  const key = await webCrypto.importKey('jwk', jwk, 'Ed25519', false, ['verify']);
7025
7012
  const verified = await webCrypto.verify('Ed25519', key, RS, hashed);
7026
7013
  return verified;
@@ -7095,7 +7082,7 @@ var openpgp = (function (exports) {
7095
7082
  }
7096
7083
  }
7097
7084
 
7098
- const publicKeyToJWK = (algo, publicKey) => {
7085
+ const publicKeyToJWK$1 = (algo, publicKey) => {
7099
7086
  switch (algo) {
7100
7087
  case enums.publicKey.ed25519: {
7101
7088
  const jwk = {
@@ -7111,10 +7098,10 @@ var openpgp = (function (exports) {
7111
7098
  }
7112
7099
  };
7113
7100
 
7114
- const privateKeyToJWK = (algo, publicKey, privateKey) => {
7101
+ const privateKeyToJWK$1 = (algo, publicKey, privateKey) => {
7115
7102
  switch (algo) {
7116
7103
  case enums.publicKey.ed25519: {
7117
- const jwk = publicKeyToJWK(algo, publicKey);
7104
+ const jwk = publicKeyToJWK$1(algo, publicKey);
7118
7105
  jwk.d = uint8ArrayToB64(privateKey);
7119
7106
  return jwk;
7120
7107
  }
@@ -8354,12 +8341,27 @@ var openpgp = (function (exports) {
8354
8341
  */
8355
8342
  async function generate$9(algo) {
8356
8343
  switch (algo) {
8357
- case enums.publicKey.x25519: {
8358
- // k stays in little-endian, unlike legacy ECDH over curve25519
8359
- const k = getRandomBytes(32);
8360
- const { publicKey: A } = nacl.box.keyPair.fromSecretKey(k);
8361
- return { A, k };
8362
- }
8344
+ case enums.publicKey.x25519:
8345
+ try {
8346
+ const webCrypto = util.getWebCrypto();
8347
+ const webCryptoKey = await webCrypto.generateKey('X25519', true, ['deriveKey', 'deriveBits']);
8348
+
8349
+ const privateKey = await webCrypto.exportKey('jwk', webCryptoKey.privateKey);
8350
+ const publicKey = await webCrypto.exportKey('jwk', webCryptoKey.publicKey);
8351
+
8352
+ return {
8353
+ A: new Uint8Array(b64ToUint8Array(publicKey.x)),
8354
+ k: b64ToUint8Array(privateKey.d)
8355
+ };
8356
+ } catch (err) {
8357
+ if (err.name !== 'NotSupportedError') {
8358
+ throw err;
8359
+ }
8360
+ // k stays in little-endian, unlike legacy ECDH over curve25519
8361
+ const k = getRandomBytes(32);
8362
+ const { publicKey: A } = nacl.box.keyPair.fromSecretKey(k);
8363
+ return { A, k };
8364
+ }
8363
8365
 
8364
8366
  case enums.publicKey.x448: {
8365
8367
  const x448 = await util.getNobleCurve(enums.publicKey.x448);
@@ -8501,13 +8503,32 @@ var openpgp = (function (exports) {
8501
8503
  */
8502
8504
  async function generateEphemeralEncryptionMaterial(algo, recipientA) {
8503
8505
  switch (algo) {
8504
- case enums.publicKey.x25519: {
8505
- const ephemeralSecretKey = getRandomBytes(getPayloadSize(algo));
8506
- const sharedSecret = nacl.scalarMult(ephemeralSecretKey, recipientA);
8507
- assertNonZeroArray(sharedSecret);
8508
- const { publicKey: ephemeralPublicKey } = nacl.box.keyPair.fromSecretKey(ephemeralSecretKey);
8509
- return { ephemeralPublicKey, sharedSecret };
8510
- }
8506
+ case enums.publicKey.x25519:
8507
+ try {
8508
+ const webCrypto = util.getWebCrypto();
8509
+ const jwk = publicKeyToJWK(algo, recipientA);
8510
+ const ephemeralKeyPair = await webCrypto.generateKey('X25519', true, ['deriveKey', 'deriveBits']);
8511
+ const recipientPublicKey = await webCrypto.importKey('jwk', jwk, 'X25519', false, []);
8512
+ const sharedSecretBuffer = await webCrypto.deriveBits(
8513
+ { name: 'X25519', public: recipientPublicKey },
8514
+ ephemeralKeyPair.privateKey,
8515
+ getPayloadSize(algo) * 8 // in bits
8516
+ );
8517
+ const ephemeralPublicKeyJwt = await webCrypto.exportKey('jwk', ephemeralKeyPair.publicKey);
8518
+ return {
8519
+ sharedSecret: new Uint8Array(sharedSecretBuffer),
8520
+ ephemeralPublicKey: new Uint8Array(b64ToUint8Array(ephemeralPublicKeyJwt.x))
8521
+ };
8522
+ } catch (err) {
8523
+ if (err.name !== 'NotSupportedError') {
8524
+ throw err;
8525
+ }
8526
+ const ephemeralSecretKey = getRandomBytes(getPayloadSize(algo));
8527
+ const sharedSecret = nacl.scalarMult(ephemeralSecretKey, recipientA);
8528
+ assertNonZeroArray(sharedSecret);
8529
+ const { publicKey: ephemeralPublicKey } = nacl.box.keyPair.fromSecretKey(ephemeralSecretKey);
8530
+ return { ephemeralPublicKey, sharedSecret };
8531
+ }
8511
8532
  case enums.publicKey.x448: {
8512
8533
  const x448 = await util.getNobleCurve(enums.publicKey.x448);
8513
8534
  const ephemeralSecretKey = x448.utils.randomPrivateKey();
@@ -8523,11 +8544,27 @@ var openpgp = (function (exports) {
8523
8544
 
8524
8545
  async function recomputeSharedSecret(algo, ephemeralPublicKey, A, k) {
8525
8546
  switch (algo) {
8526
- case enums.publicKey.x25519: {
8527
- const sharedSecret = nacl.scalarMult(k, ephemeralPublicKey);
8528
- assertNonZeroArray(sharedSecret);
8529
- return sharedSecret;
8530
- }
8547
+ case enums.publicKey.x25519:
8548
+ try {
8549
+ const webCrypto = util.getWebCrypto();
8550
+ const privateKeyJWK = privateKeyToJWK(algo, A, k);
8551
+ const ephemeralPublicKeyJWK = publicKeyToJWK(algo, ephemeralPublicKey);
8552
+ const privateKey = await webCrypto.importKey('jwk', privateKeyJWK, 'X25519', false, ['deriveKey', 'deriveBits']);
8553
+ const ephemeralPublicKeyReference = await webCrypto.importKey('jwk', ephemeralPublicKeyJWK, 'X25519', false, []);
8554
+ const sharedSecretBuffer = await webCrypto.deriveBits(
8555
+ { name: 'X25519', public: ephemeralPublicKeyReference },
8556
+ privateKey,
8557
+ getPayloadSize(algo) * 8 // in bits
8558
+ );
8559
+ return new Uint8Array(sharedSecretBuffer);
8560
+ } catch (err) {
8561
+ if (err.name !== 'NotSupportedError') {
8562
+ throw err;
8563
+ }
8564
+ const sharedSecret = nacl.scalarMult(k, ephemeralPublicKey);
8565
+ assertNonZeroArray(sharedSecret);
8566
+ return sharedSecret;
8567
+ }
8531
8568
  case enums.publicKey.x448: {
8532
8569
  const x448 = await util.getNobleCurve(enums.publicKey.x448);
8533
8570
  const sharedSecret = x448.getSharedSecret(k, ephemeralPublicKey);
@@ -8555,6 +8592,35 @@ var openpgp = (function (exports) {
8555
8592
  }
8556
8593
  }
8557
8594
 
8595
+
8596
+ function publicKeyToJWK(algo, publicKey) {
8597
+ switch (algo) {
8598
+ case enums.publicKey.x25519: {
8599
+ const jwk = {
8600
+ kty: 'OKP',
8601
+ crv: 'X25519',
8602
+ x: uint8ArrayToB64(publicKey),
8603
+ ext: true
8604
+ };
8605
+ return jwk;
8606
+ }
8607
+ default:
8608
+ throw new Error('Unsupported ECDH algorithm');
8609
+ }
8610
+ }
8611
+
8612
+ function privateKeyToJWK(algo, publicKey, privateKey) {
8613
+ switch (algo) {
8614
+ case enums.publicKey.x25519: {
8615
+ const jwk = publicKeyToJWK(algo, publicKey);
8616
+ jwk.d = uint8ArrayToB64(privateKey);
8617
+ return jwk;
8618
+ }
8619
+ default:
8620
+ throw new Error('Unsupported ECDH algorithm');
8621
+ }
8622
+ }
8623
+
8558
8624
  var ecdh_x = /*#__PURE__*/Object.freeze({
8559
8625
  __proto__: null,
8560
8626
  decrypt: decrypt$4,
@@ -9262,12 +9328,6 @@ var openpgp = (function (exports) {
9262
9328
  async function sign$7(oid, hashAlgo, message, publicKey, privateKey, hashed) {
9263
9329
  const curve = new CurveWithOID(oid);
9264
9330
  checkPublicPointEnconding(curve, publicKey);
9265
- if (getHashByteLength(hashAlgo) < getHashByteLength(enums.hash.sha256)) {
9266
- // Enforce digest sizes, since the constraint was already present in RFC4880bis:
9267
- // see https://tools.ietf.org/id/draft-ietf-openpgp-rfc4880bis-10.html#section-15-7.2
9268
- // and https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.3-3
9269
- throw new Error('Hash algorithm too weak for EdDSA.');
9270
- }
9271
9331
  const { RS: signature } = await sign$9(enums.publicKey.ed25519, hashAlgo, message, publicKey.subarray(1), privateKey, hashed);
9272
9332
  // EdDSA signature params are returned in little-endian format
9273
9333
  return {
@@ -9291,12 +9351,6 @@ var openpgp = (function (exports) {
9291
9351
  async function verify$7(oid, hashAlgo, { r, s }, m, publicKey, hashed) {
9292
9352
  const curve = new CurveWithOID(oid);
9293
9353
  checkPublicPointEnconding(curve, publicKey);
9294
- if (getHashByteLength(hashAlgo) < getHashByteLength(enums.hash.sha256)) {
9295
- // Enforce digest sizes, since the constraint was already present in RFC4880bis:
9296
- // see https://tools.ietf.org/id/draft-ietf-openpgp-rfc4880bis-10.html#section-15-7.2
9297
- // and https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.3-3
9298
- throw new Error('Hash algorithm too weak for EdDSA.');
9299
- }
9300
9354
  const RS = util.concatUint8Array([r, s]);
9301
9355
  return verify$9(enums.publicKey.ed25519, hashAlgo, { RS }, m, publicKey.subarray(1), hashed);
9302
9356
  }
@@ -10154,7 +10208,7 @@ var openpgp = (function (exports) {
10154
10208
  async function encrypt$2(algo, eccPublicKey, mlkemPublicKey, sessioneKeyData) {
10155
10209
  const { eccKeyShare, eccCipherText } = await encaps$1(algo, eccPublicKey);
10156
10210
  const { mlkemKeyShare, mlkemCipherText } = await encaps(algo, mlkemPublicKey);
10157
- const kek = await multiKeyCombine(algo, eccKeyShare, eccCipherText, eccPublicKey, mlkemKeyShare, mlkemCipherText, mlkemPublicKey);
10211
+ const kek = await multiKeyCombine(algo, mlkemKeyShare, eccKeyShare, eccCipherText, eccPublicKey);
10158
10212
  const wrappedKey = await wrap(enums.symmetric.aes256, kek, sessioneKeyData); // C
10159
10213
  return { eccCipherText, mlkemCipherText, wrappedKey };
10160
10214
  }
@@ -10162,25 +10216,24 @@ var openpgp = (function (exports) {
10162
10216
  async function decrypt$2(algo, eccCipherText, mlkemCipherText, eccSecretKey, eccPublicKey, mlkemSecretKey, mlkemPublicKey, encryptedSessionKeyData) {
10163
10217
  const eccKeyShare = await decaps$1(algo, eccCipherText, eccSecretKey, eccPublicKey);
10164
10218
  const mlkemKeyShare = await decaps(algo, mlkemCipherText, mlkemSecretKey);
10165
- const kek = await multiKeyCombine(algo, eccKeyShare, eccCipherText, eccPublicKey, mlkemKeyShare, mlkemCipherText, mlkemPublicKey);
10219
+ const kek = await multiKeyCombine(algo, mlkemKeyShare, eccKeyShare, eccCipherText, eccPublicKey);
10166
10220
  const sessionKey = await unwrap(enums.symmetric.aes256, kek, encryptedSessionKeyData);
10167
10221
  return sessionKey;
10168
10222
  }
10169
10223
 
10170
- async function multiKeyCombine(algo, ecdhKeyShare, ecdhCipherText, ecdhPublicKey, mlkemKeyShare, mlkemCipherText, mlkemPublicKey) {
10171
- // LAMPS-aligned and NIST compatible combiner, proposed in: https://mailarchive.ietf.org/arch/msg/openpgp/NMTCy707LICtxIhP3Xt1U5C8MF0/
10172
- // 2a. KDF(mlkemSS || tradSS || tradCT || tradPK || Domain)
10173
- // where Domain is "Domain" for LAMPS, and "mlkemCT || mlkemPK || algId || const" for OpenPGP
10224
+ /**
10225
+ * KEM key combiner
10226
+ */
10227
+ async function multiKeyCombine(algo, mlkemKeyShare, ecdhKeyShare, ecdhCipherText, ecdhPublicKey) {
10228
+ const domSep = util.encodeUTF8('OpenPGPCompositeKDFv1');
10174
10229
  const encData = util.concatUint8Array([
10175
10230
  mlkemKeyShare,
10176
10231
  ecdhKeyShare,
10177
10232
  ecdhCipherText,
10178
10233
  ecdhPublicKey,
10179
- // domSep
10180
- mlkemCipherText,
10181
- mlkemPublicKey,
10182
10234
  new Uint8Array([algo]),
10183
- util.encodeUTF8('OpenPGPCompositeKDFv1')
10235
+ domSep,
10236
+ new Uint8Array([domSep.length])
10184
10237
  ]);
10185
10238
 
10186
10239
  const kek = await computeDigest(enums.hash.sha3_256, encData);
@@ -10317,12 +10370,6 @@ var openpgp = (function (exports) {
10317
10370
  }
10318
10371
 
10319
10372
  async function sign$2(signatureAlgo, hashAlgo, eccSecretKey, eccPublicKey, mldsaSecretKey, dataDigest) {
10320
- if (hashAlgo !== getRequiredHashAlgo(signatureAlgo)) {
10321
- // The signature hash algo MUST be set to the specified algorithm, see
10322
- // https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-pqc#section-5.2.1.
10323
- throw new Error('Unexpected hash algorithm for PQC signature');
10324
- }
10325
-
10326
10373
  switch (signatureAlgo) {
10327
10374
  case enums.publicKey.pqc_mldsa_ed25519: {
10328
10375
  const { eccSignature } = await sign$3(signatureAlgo, hashAlgo, eccSecretKey, eccPublicKey, dataDigest);
@@ -10336,12 +10383,6 @@ var openpgp = (function (exports) {
10336
10383
  }
10337
10384
 
10338
10385
  async function verify$2(signatureAlgo, hashAlgo, eccPublicKey, mldsaPublicKey, dataDigest, { eccSignature, mldsaSignature }) {
10339
- if (hashAlgo !== getRequiredHashAlgo(signatureAlgo)) {
10340
- // The signature hash algo MUST be set to the specified algorithm, see
10341
- // https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-pqc#section-5.2.1.
10342
- throw new Error('Unexpected hash algorithm for PQC signature');
10343
- }
10344
-
10345
10386
  switch (signatureAlgo) {
10346
10387
  case enums.publicKey.pqc_mldsa_ed25519: {
10347
10388
  const eccVerifiedPromise = verify$3(signatureAlgo, hashAlgo, eccPublicKey, dataDigest, eccSignature);
@@ -10354,11 +10395,12 @@ var openpgp = (function (exports) {
10354
10395
  }
10355
10396
  }
10356
10397
 
10357
- function getRequiredHashAlgo(signatureAlgo) {
10358
- // See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-pqc#section-5.2.1.
10398
+ function isCompatibleHashAlgo(signatureAlgo, hashAlgo) {
10399
+ // The signature hash algo MUST have digest larger than 256 bits
10400
+ // https://www.ietf.org/archive/id/draft-ietf-openpgp-pqc-10.html#section-9.4
10359
10401
  switch (signatureAlgo) {
10360
10402
  case enums.publicKey.pqc_mldsa_ed25519:
10361
- return enums.hash.sha3_256;
10403
+ return getHashByteLength(hashAlgo) >= 32;
10362
10404
  default:
10363
10405
  throw new Error('Unsupported signature algorithm');
10364
10406
  }
@@ -12481,6 +12523,12 @@ var openpgp = (function (exports) {
12481
12523
  return verify$8(oid, hashAlgo, { r, s }, data, Q, hashed);
12482
12524
  }
12483
12525
  case enums.publicKey.eddsaLegacy: {
12526
+ if (getHashByteLength(hashAlgo) < getHashByteLength(enums.hash.sha256)) {
12527
+ // Enforce digest sizes, since the constraint was already present in RFC4880bis:
12528
+ // see https://tools.ietf.org/id/draft-ietf-openpgp-rfc4880bis-10.html#section-15-7.2
12529
+ // and https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.3-3
12530
+ throw new Error('Hash algorithm too weak for EdDSALegacy.');
12531
+ }
12484
12532
  const { oid, Q } = publicParams;
12485
12533
  const curveSize = new CurveWithOID(oid).payloadSize;
12486
12534
  // When dealing little-endian MPI data, we always need to left-pad it, as done with big-endian values:
@@ -12491,6 +12539,13 @@ var openpgp = (function (exports) {
12491
12539
  }
12492
12540
  case enums.publicKey.ed25519:
12493
12541
  case enums.publicKey.ed448: {
12542
+ if (getHashByteLength(hashAlgo) < getHashByteLength(getPreferredHashAlgo$2(algo))) {
12543
+ // Enforce digest sizes:
12544
+ // - Ed25519: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.4-4
12545
+ // - Ed448: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.5-4
12546
+ throw new Error('Hash algorithm too weak for EdDSA.');
12547
+ }
12548
+
12494
12549
  const { A } = publicParams;
12495
12550
  return verify$9(algo, hashAlgo, signature, data, A, hashed);
12496
12551
  }
@@ -12503,6 +12558,11 @@ var openpgp = (function (exports) {
12503
12558
  return verify$5(algo.getValue(), keyMaterial, signature.mac.data, hashed);
12504
12559
  }
12505
12560
  case enums.publicKey.pqc_mldsa_ed25519: {
12561
+ if (!isCompatibleHashAlgo(algo, hashAlgo)) {
12562
+ // The signature hash algo MUST have digest larger than 256 bits
12563
+ // https://www.ietf.org/archive/id/draft-ietf-openpgp-pqc-10.html#section-9.4
12564
+ throw new Error('Unexpected hash algorithm for PQC signature: digest size too short');
12565
+ }
12506
12566
  const { eccPublicKey, mldsaPublicKey } = publicParams;
12507
12567
  return verify$2(algo, hashAlgo, eccPublicKey, mldsaPublicKey, hashed, signature);
12508
12568
  }
@@ -12551,12 +12611,24 @@ var openpgp = (function (exports) {
12551
12611
  return sign$8(oid, hashAlgo, data, Q, d, hashed);
12552
12612
  }
12553
12613
  case enums.publicKey.eddsaLegacy: {
12614
+ if (getHashByteLength(hashAlgo) < getHashByteLength(enums.hash.sha256)) {
12615
+ // Enforce digest sizes, since the constraint was already present in RFC4880bis:
12616
+ // see https://tools.ietf.org/id/draft-ietf-openpgp-rfc4880bis-10.html#section-15-7.2
12617
+ // and https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.3-3
12618
+ throw new Error('Hash algorithm too weak for EdDSALegacy.');
12619
+ }
12554
12620
  const { oid, Q } = publicKeyParams;
12555
12621
  const { seed } = privateKeyParams;
12556
12622
  return sign$7(oid, hashAlgo, data, Q, seed, hashed);
12557
12623
  }
12558
12624
  case enums.publicKey.ed25519:
12559
12625
  case enums.publicKey.ed448: {
12626
+ if (getHashByteLength(hashAlgo) < getHashByteLength(getPreferredHashAlgo$2(algo))) {
12627
+ // Enforce digest sizes:
12628
+ // - Ed25519: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.4-4
12629
+ // - Ed448: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.5-4
12630
+ throw new Error('Hash algorithm too weak for EdDSA.');
12631
+ }
12560
12632
  const { A } = publicKeyParams;
12561
12633
  const { seed } = privateKeyParams;
12562
12634
  return sign$9(algo, hashAlgo, data, A, seed, hashed);
@@ -12568,6 +12640,11 @@ var openpgp = (function (exports) {
12568
12640
  return { mac: new ShortByteString(mac) };
12569
12641
  }
12570
12642
  case enums.publicKey.pqc_mldsa_ed25519: {
12643
+ if (!isCompatibleHashAlgo(algo, hashAlgo)) {
12644
+ // The signature hash algo MUST have digest larger than 256 bits
12645
+ // https://www.ietf.org/archive/id/draft-ietf-openpgp-pqc-10.html#section-9.4
12646
+ throw new Error('Unexpected hash algorithm for PQC signature: digest size too short');
12647
+ }
12571
12648
  const { eccPublicKey } = publicKeyParams;
12572
12649
  const { eccSecretKey, mldsaSecretKey } = privateKeyParams;
12573
12650
  return sign$2(algo, hashAlgo, eccSecretKey, eccPublicKey, mldsaSecretKey, hashed);
@@ -16836,12 +16913,8 @@ var openpgp = (function (exports) {
16836
16913
  throw new Error('Legacy curve25519 cannot be used with v6 keys');
16837
16914
  }
16838
16915
  // The composite ML-DSA + EdDSA schemes MUST be used only with v6 keys.
16839
- // The composite ML-KEM + ECDH schemes MUST be used only with v6 keys.
16840
- if (this.version !== 6 && (
16841
- this.algorithm === enums.publicKey.pqc_mldsa_ed25519 ||
16842
- this.algorithm === enums.publicKey.pqc_mlkem_x25519
16843
- )) {
16844
- throw new Error('Unexpected key version: ML-DSA and ML-KEM algorithms can only be used with v6 keys');
16916
+ if (this.version !== 6 && this.algorithm === enums.publicKey.pqc_mldsa_ed25519) {
16917
+ throw new Error('Unexpected key version: ML-DSA algorithms can only be used with v6 keys');
16845
16918
  }
16846
16919
  this.publicParams = publicParams;
16847
16920
  pos += read;
@@ -17841,11 +17914,8 @@ var openpgp = (function (exports) {
17841
17914
  )) {
17842
17915
  throw new Error(`Cannot generate v6 keys of type 'ecc' with curve ${curve}. Generate a key of type 'curve25519' instead`);
17843
17916
  }
17844
- if (this.version !== 6 && (
17845
- this.algorithm === enums.publicKey.pqc_mldsa_ed25519 ||
17846
- this.algorithm === enums.publicKey.pqc_mlkem_x25519
17847
- )) {
17848
- throw new Error(`Cannot generate v${this.version} keys of type 'pqc'. Generate a v6 key instead`);
17917
+ if (this.version !== 6 && this.algorithm === enums.publicKey.pqc_mldsa_ed25519) {
17918
+ throw new Error(`Cannot generate v${this.version} signing keys of type 'pqc'. Generate a v6 key instead`);
17849
17919
  }
17850
17920
  const { privateParams, publicParams } = await generateParams(this.algorithm, bits, curve, symmetric);
17851
17921
  this.privateParams = privateParams;
@@ -18349,12 +18419,6 @@ var openpgp = (function (exports) {
18349
18419
  * @async
18350
18420
  */
18351
18421
  async function getPreferredHashAlgo(targetKeys, signingKeyPacket, date = new Date(), targetUserIDs = [], config) {
18352
- if (signingKeyPacket.algorithm === enums.publicKey.pqc_mldsa_ed25519) {
18353
- // For PQC, the returned hash algo MUST be set to the specified algorithm, see
18354
- // https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-pqc#section-5.2.1.
18355
- return getRequiredHashAlgo(signingKeyPacket.algorithm);
18356
- }
18357
-
18358
18422
  /**
18359
18423
  * If `preferredSenderAlgo` appears in the prefs of all recipients, we pick it; otherwise, we use the
18360
18424
  * strongest supported algo (`defaultAlgo` is always implicitly supported by all keys).
@@ -18402,6 +18466,10 @@ var openpgp = (function (exports) {
18402
18466
  enums.publicKey.ed448
18403
18467
  ]);
18404
18468
 
18469
+ const pqcAlgos = new Set([
18470
+ enums.publicKey.pqc_mldsa_ed25519
18471
+ ]);
18472
+
18405
18473
  if (eccAlgos.has(signingKeyPacket.algorithm)) {
18406
18474
  // For ECC, the returned hash algo MUST be at least as strong as `preferredCurveHashAlgo`, see:
18407
18475
  // - ECDSA: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.2-5
@@ -18424,6 +18492,21 @@ var openpgp = (function (exports) {
18424
18492
  strongestSupportedAlgo :
18425
18493
  preferredCurveAlgo;
18426
18494
  }
18495
+ } else if (pqcAlgos.has(signingKeyPacket.algorithm)) {
18496
+ // For PQC, the returned hash algo MUST be at least 256 bit long, see:
18497
+ // https://www.ietf.org/archive/id/draft-ietf-openpgp-pqc-10.html#section-9.4 .
18498
+ // Hence, we return the `preferredHashAlgo` as long as it's supported and long enough;
18499
+ // Otherwise, we look at the strongest supported algo, and ultimately fallback the default algo (SHA-256).
18500
+ const preferredSenderAlgoIsSupported = isSupportedHashAlgo(preferredSenderAlgo) && isCompatibleHashAlgo(signingKeyPacket.algorithm, preferredSenderAlgo);
18501
+
18502
+ if (preferredSenderAlgoIsSupported) {
18503
+ return preferredSenderAlgo;
18504
+ } else {
18505
+ const strongestSupportedAlgo = getStrongestSupportedHashAlgo();
18506
+ return isCompatibleHashAlgo(signingKeyPacket.algorithm, strongestSupportedAlgo) ?
18507
+ strongestSupportedAlgo :
18508
+ defaultAlgo;
18509
+ }
18427
18510
  }
18428
18511
 
18429
18512
  // `preferredSenderAlgo` may be weaker than the default, but we do not guard against this,