From 0468a41f98e1259d78b83798d50ae342670d7cae Mon Sep 17 00:00:00 2001 From: larabr <7375870+larabr@users.noreply.github.com> Date: Fri, 3 Nov 2023 13:14:36 +0100 Subject: [PATCH] WIP: Add ML-DSA --- package-lock.json | 5 +- src/crypto/crypto.js | 14 +- src/crypto/public_key/post_quantum/index.js | 4 +- .../post_quantum/signature/ecc_dsa.js | 49 + .../post_quantum/signature/index.js | 2 + .../post_quantum/signature/ml_dsa.js | 71 ++ .../post_quantum/signature/signature.js | 48 + src/crypto/signature.js | 15 + src/enums.js | 3 + src/key/helper.js | 3 +- src/packet/public_key.js | 8 +- src/packet/secret_key.js | 5 +- test/crypto/postQuantum.js | 1118 +++++++++++++++++ test/crypto/validate.js | 30 +- test/general/key.js | 6 +- 15 files changed, 1355 insertions(+), 26 deletions(-) create mode 100644 src/crypto/public_key/post_quantum/signature/ecc_dsa.js create mode 100644 src/crypto/public_key/post_quantum/signature/index.js create mode 100644 src/crypto/public_key/post_quantum/signature/ml_dsa.js create mode 100644 src/crypto/public_key/post_quantum/signature/signature.js diff --git a/package-lock.json b/package-lock.json index e94e397c..f6de3301 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3698,7 +3698,6 @@ "url": "https://feross.org/support" } ], - "license": "MIT", "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -3709,7 +3708,6 @@ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", "dev": true, - "license": "MIT", "engines": { "node": ">=8.0.0" } @@ -7028,8 +7026,7 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "license": "BSD-3-Clause" + ] }, "node_modules/ignore": { "version": "5.3.2", diff --git a/src/crypto/crypto.js b/src/crypto/crypto.js index 0ce9beb0..293ab286 100644 --- a/src/crypto/crypto.js +++ b/src/crypto/crypto.js @@ -331,8 +331,9 @@ export async function parsePrivateKeyParams(algo, bytes, publicParams) { } case enums.publicKey.pqc_mldsa_ed25519: { const eccSecretKey = util.readExactSubarray(bytes, read, read + getCurvePayloadSize(enums.publicKey.ed25519)); read += eccSecretKey.length; - const mldsaSecretKey = util.readExactSubarray(bytes, read, read + 4032); read += mldsaSecretKey.length; - return { read, privateParams: { eccSecretKey, mldsaSecretKey } }; + const mldsaSeed = util.readExactSubarray(bytes, read, read + 32); read += mldsaSeed.length; + const { mldsaSecretKey } = await publicKey.postQuantum.signature.mldsaExpandSecretSeed(algo, mldsaSeed); + return { read, privateParams: { eccSecretKey, mldsaSecretKey, mldsaSeed } }; } default: throw new UnsupportedError('Unknown public key encryption algorithm.'); @@ -429,6 +430,7 @@ export function serializeParams(algo, params) { const excludedFields = { [enums.publicKey.pqc_mlkem_x25519]: new Set(['mlkemSecretKey']), // only `mlkemSeed` is serialized + [enums.publicKey.pqc_mldsa_ed25519]: new Set(['mldsaSecretKey']) // only `mldsaSeed` is serialized }; const orderedParams = Object.keys(params).map(name => { @@ -506,8 +508,8 @@ export async function generateParams(algo, bits, oid, symmetric) { publicParams: { eccPublicKey, mlkemPublicKey } })); case enums.publicKey.pqc_mldsa_ed25519: - return publicKey.postQuantum.signature.generate(algo).then(({ eccSecretKey, eccPublicKey, mldsaSecretKey, mldsaPublicKey }) => ({ - privateParams: { eccSecretKey, mldsaSecretKey }, + return publicKey.postQuantum.signature.generate(algo).then(({ eccSecretKey, eccPublicKey, mldsaSeed, mldsaSecretKey, mldsaPublicKey }) => ({ + privateParams: { eccSecretKey, mldsaSeed, mldsaSecretKey }, publicParams: { eccPublicKey, mldsaPublicKey } })); case enums.publicKey.dsa: @@ -607,9 +609,9 @@ export async function validateParams(algo, publicParams, privateParams) { return publicKey.postQuantum.kem.validateParams(algo, eccPublicKey, eccSecretKey, mlkemPublicKey, mlkemSeed); } case enums.publicKey.pqc_mldsa_ed25519: { - const { eccSecretKey, mldsaSecretKey } = privateParams; + const { eccSecretKey, mldsaSeed } = privateParams; const { eccPublicKey, mldsaPublicKey } = publicParams; - return publicKey.postQuantum.signature.validateParams(algo, eccPublicKey, eccSecretKey, mldsaPublicKey, mldsaSecretKey); + return publicKey.postQuantum.signature.validateParams(algo, eccPublicKey, eccSecretKey, mldsaPublicKey, mldsaSeed); } default: throw new Error('Unknown public key algorithm.'); diff --git a/src/crypto/public_key/post_quantum/index.js b/src/crypto/public_key/post_quantum/index.js index 982b28be..cf803ef8 100644 --- a/src/crypto/public_key/post_quantum/index.js +++ b/src/crypto/public_key/post_quantum/index.js @@ -1,5 +1,7 @@ import * as kem from './kem/index'; +import * as signature from './signature'; export { - kem + kem, + signature }; diff --git a/src/crypto/public_key/post_quantum/signature/ecc_dsa.js b/src/crypto/public_key/post_quantum/signature/ecc_dsa.js new file mode 100644 index 00000000..4d7747e8 --- /dev/null +++ b/src/crypto/public_key/post_quantum/signature/ecc_dsa.js @@ -0,0 +1,49 @@ +// TODOOOOO is this file needed? vs inlining calls in signature.js? + + +import * as eddsa from '../../elliptic/eddsa'; +import enums from '../../../../enums'; + +export async function generate(algo) { + switch (algo) { + case enums.publicKey.pqc_mldsa_ed25519: { + const { A, seed } = await eddsa.generate(enums.publicKey.ed25519); + return { + eccPublicKey: A, + eccSecretKey: seed + }; + } + default: + throw new Error('Unsupported signature algorithm'); + } +} + +export async function sign(signatureAlgo, hashAlgo, eccSecretKey, eccPublicKey, dataDigest) { + switch (signatureAlgo) { + case enums.publicKey.pqc_mldsa_ed25519: { + const { RS: eccSignature } = await eddsa.sign(enums.publicKey.ed25519, hashAlgo, null, eccPublicKey, eccSecretKey, dataDigest); + + return { eccSignature }; + } + default: + throw new Error('Unsupported signature algorithm'); + } +} + +export async function verify(signatureAlgo, hashAlgo, eccPublicKey, dataDigest, eccSignature) { + switch (signatureAlgo) { + case enums.publicKey.pqc_mldsa_ed25519: + return eddsa.verify(enums.publicKey.ed25519, hashAlgo, { RS: eccSignature }, null, eccPublicKey, dataDigest); + default: + throw new Error('Unsupported signature algorithm'); + } +} + +export async function validateParams(algo, eccPublicKey, eccSecretKey) { + switch (algo) { + case enums.publicKey.pqc_mldsa_ed25519: + return eddsa.validateParams(enums.publicKey.ed25519, eccPublicKey, eccSecretKey); + default: + throw new Error('Unsupported signature algorithm'); + } +} diff --git a/src/crypto/public_key/post_quantum/signature/index.js b/src/crypto/public_key/post_quantum/signature/index.js new file mode 100644 index 00000000..a972e60f --- /dev/null +++ b/src/crypto/public_key/post_quantum/signature/index.js @@ -0,0 +1,2 @@ +export { generate, sign, verify, validateParams } from './signature'; +export { expandSecretSeed as mldsaExpandSecretSeed } from './ml_dsa'; diff --git a/src/crypto/public_key/post_quantum/signature/ml_dsa.js b/src/crypto/public_key/post_quantum/signature/ml_dsa.js new file mode 100644 index 00000000..ca97c40a --- /dev/null +++ b/src/crypto/public_key/post_quantum/signature/ml_dsa.js @@ -0,0 +1,71 @@ +import enums from '../../../../enums'; +import util from '../../../../util'; +import { getRandomBytes } from '../../../random'; + +export async function generate(algo) { + switch (algo) { + case enums.publicKey.pqc_mldsa_ed25519: { + const mldsaSeed = getRandomBytes(32); + const { mldsaSecretKey, mldsaPublicKey } = await expandSecretSeed(algo, mldsaSeed); + + return { mldsaSeed, mldsaSecretKey, mldsaPublicKey }; + } + default: + throw new Error('Unsupported signature algorithm'); + } +} + +/** + * Expand ML-DSA secret seed and retrieve the secret and public key material + * @param {module:enums.publicKey} algo - Public key algorithm + * @param {Uint8Array} seed - secret seed to expand + * @returns {Promise<{ mldsaPublicKey: Uint8Array, mldsaSecretKey: Uint8Array }>} + */ +export async function expandSecretSeed(algo, seed) { + switch (algo) { + case enums.publicKey.pqc_mldsa_ed25519: { + const { ml_dsa65 } = await import('@noble/post-quantum/ml-dsa'); + const { secretKey: mldsaSecretKey, publicKey: mldsaPublicKey } = ml_dsa65.keygen(seed); + + return { mldsaSecretKey, mldsaPublicKey }; + } + default: + throw new Error('Unsupported signature algorithm'); + } +} + +export async function sign(algo, mldsaSecretKey, dataDigest) { + switch (algo) { + case enums.publicKey.pqc_mldsa_ed25519: { + const { ml_dsa65 } = await import('@noble/post-quantum/ml-dsa'); + const dataDigestWithContext = util.concatUint8Array([new Uint8Array([0, 0]), dataDigest]); + const mldsaSignature = ml_dsa65.sign(mldsaSecretKey, dataDigestWithContext); + return { mldsaSignature }; + } + default: + throw new Error('Unsupported signature algorithm'); + } +} + +export async function verify(algo, mldsaPublicKey, dataDigest, mldsaSignature) { + switch (algo) { + case enums.publicKey.pqc_mldsa_ed25519: { + const { ml_dsa65 } = await import('@noble/post-quantum/ml-dsa'); + const dataDigestWithContext = util.concatUint8Array([new Uint8Array([0, 0]), dataDigest]); + return ml_dsa65.verify(mldsaPublicKey, dataDigestWithContext, mldsaSignature); + } + default: + throw new Error('Unsupported signature algorithm'); + } +} + +export async function validateParams(algo, mldsaPublicKey, mldsaSeed) { + switch (algo) { + case enums.publicKey.pqc_mldsa_ed25519: { + const { mldsaPublicKey: expectedPublicKey } = await expandSecretSeed(algo, mldsaSeed); + return util.equalsUint8Array(mldsaPublicKey, expectedPublicKey); + } + default: + throw new Error('Unsupported signature algorithm'); + } +} diff --git a/src/crypto/public_key/post_quantum/signature/signature.js b/src/crypto/public_key/post_quantum/signature/signature.js new file mode 100644 index 00000000..64ada256 --- /dev/null +++ b/src/crypto/public_key/post_quantum/signature/signature.js @@ -0,0 +1,48 @@ +import enums from '../../../../enums'; +import * as mldsa from './ml_dsa'; +import * as eccdsa from './ecc_dsa'; + +export async function generate(algo) { + switch (algo) { + case enums.publicKey.pqc_mldsa_ed25519: { + const { eccSecretKey, eccPublicKey } = await eccdsa.generate(algo); + const { mldsaSeed, mldsaSecretKey, mldsaPublicKey } = await mldsa.generate(algo); + return { eccSecretKey, eccPublicKey, mldsaSeed, mldsaSecretKey, mldsaPublicKey }; + } + default: + throw new Error('Unsupported signature algorithm'); + } +} + +export async function sign(signatureAlgo, hashAlgo, eccSecretKey, eccPublicKey, mldsaSecretKey, dataDigest) { + switch (signatureAlgo) { + case enums.publicKey.pqc_mldsa_ed25519: { + const { eccSignature } = await eccdsa.sign(signatureAlgo, hashAlgo, eccSecretKey, eccPublicKey, dataDigest); + const { mldsaSignature } = await mldsa.sign(signatureAlgo, mldsaSecretKey, dataDigest); + + return { eccSignature, mldsaSignature }; + } + default: + throw new Error('Unsupported signature algorithm'); + } +} + +export async function verify(signatureAlgo, hashAlgo, eccPublicKey, mldsaPublicKey, dataDigest, { eccSignature, mldsaSignature }) { + switch (signatureAlgo) { + case enums.publicKey.pqc_mldsa_ed25519: { + const eccVerifiedPromise = eccdsa.verify(signatureAlgo, hashAlgo, eccPublicKey, dataDigest, eccSignature); + const mldsaVerifiedPromise = mldsa.verify(signatureAlgo, mldsaPublicKey, dataDigest, mldsaSignature); + const verified = await eccVerifiedPromise && await mldsaVerifiedPromise; + return verified; + } + default: + throw new Error('Unsupported signature algorithm'); + } +} + +export async function validateParams(algo, eccPublicKey, eccSecretKey, mldsaPublicKey, mldsaSeed) { + const eccValidationPromise = eccdsa.validateParams(algo, eccPublicKey, eccSecretKey); + const mldsaValidationPromise = mldsa.validateParams(algo, mldsaPublicKey, mldsaSeed); + const valid = await eccValidationPromise && await mldsaValidationPromise; + return valid; +} diff --git a/src/crypto/signature.js b/src/crypto/signature.js index e8c04ba7..9b7d6a89 100644 --- a/src/crypto/signature.js +++ b/src/crypto/signature.js @@ -70,6 +70,12 @@ export function parseSignatureParams(algo, signature) { const mac = new ShortByteString(); read += mac.read(signature.subarray(read)); return { read, signatureParams: { mac } }; } + case enums.publicKey.pqc_mldsa_ed25519: { + const eccSignatureSize = 2 * publicKey.elliptic.eddsa.getPayloadSize(enums.publicKey.ed25519); + const eccSignature = util.readExactSubarray(signature, read, read + eccSignatureSize); read += eccSignature.length; + const mldsaSignature = util.readExactSubarray(signature, read, read + 3309); read += mldsaSignature.length; + return { read, signatureParams: { eccSignature, mldsaSignature } }; + } default: throw new UnsupportedError('Unknown signature algorithm.'); } @@ -134,6 +140,10 @@ export async function verify(algo, hashAlgo, signature, publicParams, privatePar const { keyMaterial } = privateParams; return publicKey.hmac.verify(algo.getValue(), keyMaterial, signature.mac.data, hashed); } + case enums.publicKey.pqc_mldsa_ed25519: { + const { eccPublicKey, mldsaPublicKey } = publicParams; + return publicKey.postQuantum.signature.verify(algo, hashAlgo, eccPublicKey, mldsaPublicKey, hashed, signature); + } default: throw new Error('Unknown signature algorithm.'); } @@ -195,6 +205,11 @@ export async function sign(algo, hashAlgo, publicKeyParams, privateKeyParams, da const mac = await publicKey.hmac.sign(algo.getValue(), keyMaterial, hashed); return { mac: new ShortByteString(mac) }; } + case enums.publicKey.pqc_mldsa_ed25519: { + const { eccPublicKey } = publicKeyParams; + const { eccSecretKey, mldsaSecretKey } = privateKeyParams; + return publicKey.postQuantum.signature.sign(algo, hashAlgo, eccSecretKey, eccPublicKey, mldsaSecretKey, hashed); + } default: throw new Error('Unknown signature algorithm.'); } diff --git a/src/enums.js b/src/enums.js index 5455f6b0..e53f6667 100644 --- a/src/enums.js +++ b/src/enums.js @@ -98,6 +98,9 @@ export default { ed448: 28, /** Post-quantum ML-KEM-768 + X25519 (Encrypt only) */ pqc_mlkem_x25519: 105, + /** Post-quantum ML-DSA-64 + Ed25519 (Sign only) */ + pqc_mldsa_ed25519: 107, + /** Persistent symmetric keys: encryption algorithm */ aead: 100, /** Persistent symmetric keys: authentication algorithm */ diff --git a/src/key/helper.js b/src/key/helper.js index 29921dea..ba08bb19 100644 --- a/src/key/helper.js +++ b/src/key/helper.js @@ -399,7 +399,7 @@ export function sanitizeKeyOptions(options, subkeyDefaults = {}) { switch (options.type) { case 'pqc': if (options.sign) { - throw new Error('Post-quantum signing algorithms are not yet supported.'); + options.algorithm = enums.publicKey.pqc_mldsa_ed25519; } else { options.algorithm = enums.publicKey.pqc_mlkem_x25519; } @@ -462,6 +462,7 @@ export function validateSigningKeyPacket(keyPacket, signature, config) { case enums.publicKey.ed25519: case enums.publicKey.ed448: case enums.publicKey.hmac: + case enums.publicKey.pqc_mldsa_ed25519: if (!signature.keyFlags && !config.allowMissingKeyFlags) { throw new Error('None of the key flags is set: consider passing `config.allowMissingKeyFlags`'); } diff --git a/src/packet/public_key.js b/src/packet/public_key.js index e444f750..09e2fe45 100644 --- a/src/packet/public_key.js +++ b/src/packet/public_key.js @@ -138,9 +138,13 @@ class PublicKeyPacket { ) { throw new Error('Legacy curve25519 cannot be used with v6 keys'); } + // The composite ML-DSA + EdDSA schemes MUST be used only with v6 keys. // The composite ML-KEM + ECDH schemes MUST be used only with v6 keys. - if (this.version !== 6 && this.algorithm === enums.publicKey.pqc_mlkem_x25519) { - throw new Error('Unexpected key version: ML-KEM algorithms can only be used with v6 keys'); + if (this.version !== 6 && ( + this.algorithm === enums.publicKey.pqc_mldsa_ed25519 || + this.algorithm === enums.publicKey.pqc_mlkem_x25519 + )) { + throw new Error('Unexpected key version: ML-DSA and ML-KEM algorithms can only be used with v6 keys'); } this.publicParams = publicParams; pos += read; diff --git a/src/packet/secret_key.js b/src/packet/secret_key.js index 7356ac1e..e94e00a6 100644 --- a/src/packet/secret_key.js +++ b/src/packet/secret_key.js @@ -532,7 +532,10 @@ class SecretKeyPacket extends PublicKeyPacket { )) { throw new Error(`Cannot generate v6 keys of type 'ecc' with curve ${curve}. Generate a key of type 'curve25519' instead`); } - if (this.version !== 6 && this.algorithm === enums.publicKey.pqc_mlkem_x25519) { + if (this.version !== 6 && ( + this.algorithm === enums.publicKey.pqc_mldsa_ed25519 || + this.algorithm === enums.publicKey.pqc_mlkem_x25519 + )) { throw new Error(`Cannot generate v${this.version} keys of type 'pqc'. Generate a v6 key instead`); } const { privateParams, publicParams } = await crypto.generateParams(this.algorithm, bits, curve, symmetric); diff --git a/test/crypto/postQuantum.js b/test/crypto/postQuantum.js index a1c899de..60a72c3b 100644 --- a/test/crypto/postQuantum.js +++ b/test/crypto/postQuantum.js @@ -1,9 +1,11 @@ +/* eslint-disable max-lines */ import { use as chaiUse, expect } from 'chai'; import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import chaiUse(chaiAsPromised); import openpgp from '../initOpenpgp.js'; import { generateParams, publicKeyEncrypt, publicKeyDecrypt } from '../../src/crypto/crypto.js'; +import { sign, verify } from '../../src/crypto/signature.js'; export default () => describe('PQC', function () { it('ML-KEM + X25519 - Generate/encrypt/decrypt', async function () { @@ -155,4 +157,1120 @@ BoWQifC9dbHD5JNv0/6CMXFZagQABA== }); expect(decryptedData).to.equal('Testing\n'); }); + + it('ML-DSA + Ed25519 - Generate/sign/verify', async function () { + const digest = new Uint8Array(32).fill(1); + const hashAlgo = openpgp.enums.hash.sha256; + + const { privateParams, publicParams } = await generateParams(openpgp.enums.publicKey.pqc_mldsa_ed25519); + const signature = await sign(openpgp.enums.publicKey.pqc_mldsa_ed25519, hashAlgo, publicParams, privateParams, null, digest); + const verified = await verify(openpgp.enums.publicKey.pqc_mldsa_ed25519, hashAlgo, signature, publicParams, null, null, digest); + expect(verified).to.be.true; + }); + + it('ML-DSA + Ed25519 - private key is correctly serialized using the seed instead of the expanded secret key material', async function () { + const armoredKey = `-----BEGIN PGP PRIVATE KEY BLOCK----- + +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 +BoWQifC9dbHD5JNv0/6CMXFZagQABA== +-----END PGP PRIVATE KEY BLOCK-----`; + + const { data: expectedBinaryKey } = await openpgp.unarmor(armoredKey); + + const privateKey = await openpgp.readKey({ armoredKey }); + expect(privateKey.write()).to.deep.equal(expectedBinaryKey); + }); + + it('ML-DSA + Ed25519 - Test vector', async function () { + const privateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK----- + +xcdLBlHQxoBrAAAHwECaYVPMABTO9YEkuglz9uBemTGeFOe1RlXaln/uzeQCPvPP +I/KoSrdDi+B3vB4TLzjw2Z6akw2BXzU8ewDR0JB/xsZKoo4xKL/tMcZa4gV5P8PY +24xz4KutCiWzrz9YI9Uqv0kL5MZr/gdF/Zpnoe9rEhCZQ0wMOHUTlebFzi6AmRsV +tcu4fU6yn/LZcU8+bJfNfkidlTKKRJHzB7qDn6+QHKyM2zfq8BktuInIeeRDorbR +NNWC0Qsh4qornG2salZrnVhkc3OcBsVTtYGS/a93gEA4+sjEexTW4wNy26g2AavS +jGZl/Iujc0OJ/1LGZOfZa2K60oAsm6jVo0x1uy7tbrPm3LYxfL7i9/BcZodW6FDq +e1pWK+9FfNKpDXfDyTR5nX8KIfhYio/0PXRvpCDuSxs3Sg3HfoNUysIicSzKAGsx +Ke7PZ9l+Y4W/5cExbb/5YVE9+9tRMxNWkPdgPYlvaHDWHh+weU5Ae3sLsUb7mpdN +UbkJa0CuBO+tRRSwbZfKrk/H2YJSTkbbfm8ACK1stqg+zDc9R8PVfTbk7UeZ2k/4 +ydWo3jzvB3FtMS2SeBwgqYhwjpxYRlmE/3Pz42msB88fZFs2WDbrGC+BNGFXcA7N +lAL53ptL22JC/XvhwXHE/wmlsJJE1nTv6mfSCSMp8Y+7CTK8P98reHBZecXsrijK +BQCQfmRtUAL0XgYjMmDZ63glB8sm3sDX9rbkr5QmTTcSKUiDaJz7ImfXizCk7K10 +LqDbLZ7L987jvCBeuYjmRQwcjqYafUYlbfaTT3a3AthZ8ZBBVOZipd8BxBkVSrTL +xSDg/BZvmAqHdWGZzg1HuwfjAgpk2h9AbH9bbgR/6aOAPFE1Vwj00EPiJj6DuRup +ozPHzda1Kn8w97hWAqBU+9Jwu5uXkJfyjiOQobQpWBGl1HWwKjT6mg7J/Ik9Py99 +jV5FlRotfrIP+hlaQ7VFFk00ps4LJr/D4+ib4COKsCUJNT8sD+tCj2crUmGGDVtz +zINXyBjA84Se/CNGy7Gn1X4FKaJdZuvgj5sIvU/A0nsIbJAdl8JbeTSJnJsQN61b +ofxbCV7iyLpOYx4ctZh5ugzPrPuhGNNYQpmzMlfI9MefhLKU2JpoM2cBzqrAHg9o +4f/ynrPk1AMLY2UIB53y3pZS/bZzqjvOlAmaMYspptKbOVWWnJx6ddro9BNj+LPh +8vOvPjVBpSgDbSTY3jtxVFaz30GrB7RD3QbD63rRqr+xlK4a8EMmthyW/9pEvlTT +i/HJGM5sXq8g3L0Ang4txQKoGdssqsFpWLLiW9qfsHWAY4Ri8dBUHpD//IdHS92h +LlpapsDZ/IWeoQiSkpk0tXjVfRh6EN2Ev2sy19IhTXA5rhgFdWF5GO1MNWaTZoBC +lZF4COLJOSeFpbfZgQ4sxGcmDUoPWm0+vI4uCaihOr7uMRn+xZIAGOmTwxBnO/Oz +BeeLO0mesrsidSq/QTkN1/e9Y6xvdr9z9j+rj/wcAQPPtQwQtav+BQctdZ07OH94 +a4deOXauXKkwq7nOCqENz3aQ/AL1YDMIGbg9YiJZZHdJEQckCtWa7gqQGQOR+Htr +GyYiKnwNuRqI3gLx8gdrrtGER1WvLkfl415Mb9lOZjzhC+IokE6KSkOPWxDVpaQK +tmQlEKnglguWD0TbOrdGzyku++2V5Ct+YPzYSXlJMu5kR2dVjYNqrU1W+RXnS/2s +7GfQI/+094V+c7dZV9HSnV7gdsgZwggVOA0Qp9tRyAQfg/JvkRGmu3EFzW0qFL1s +XCumIaye11TjkSM4xcfz9EwfcLwjeolbWDhQqhqGsOTNPp8FamusZUYgW+SWuoWT +EhOSxuqXFG2n9BgVyzwwl28yjc/qIxlztUcZdjrIqKnCPHc6jmjmAZT9Yfz5sxEn +JCiR5rEOgwM4tvy7lrEZ+2aShriT610TtY/LfiYV9iibrN/4MFEBEKo3LgG2Mkd8 +tfUD90/lkFyCSU46Dtwmuu8Wd7A5JMO3CRAu1QlbuejCMvBVs51ElTkolqwa1VCz +WpNmydpGKhBI5YTgy9GDA6E9daHA6y/cGrmKxbCyf4qr/9aRb1MDO6tgwsf69U+L +4aCLto0R3aaRdzGOnxelbERStWfe47EsbAHq6GUme4q7R+pQp5sWMmCY2yl9QHEE +jOMynGYkqDWnGVTort1jIWZ1bhwwOhqRYM15YnCpSobOgpr4YEmPjVqQspemtlwf +TqKaIP9vXeB+bo8ZTL1NnhY1wLvQJqceY4O7elQ/wHwnZMUsTuj3+kLs30RrBIWD +8/IlI2rSKolTbYBOKk46/dX4a0widC0JTBZ19zWvVVvWbwKihx7i95Eeqp1iO0oZ +fSDxeui825bJlOKFIFBPd2wYNre9nCTKuIEK6q3hiDKxi/Kpu15BkriKaZCFJ/oX +pFVJEdvo/riq0Et/W3JyZC6tcXIyuoRVvIIBAfGzlVGBZksi0e9E5exdOztDkfiN +7LPf1DrgVt0hCAQ6IoP5NVY8aCxhMxPkQZGukc/bIGnoFFVH95SqSo3MfISlrn+8 +3mXivxWAYNAfXzsup5CIFhhEmaMvleAfAAkLGVJqOzgn5HiApl7TS8hyw2A7ZYZp +UdYw/qbkRzlgYDpBHxMHsy1xV5fVxkpc/ngSf7MAsCPe6w+2NUFNr1jnMoZEAaOu +b51HuSlcMSmprhIVpbMgh9tR5NGPLQSnsy5zFxKU0ZNSX3s+kqWSxf5o2vJ9/cLM +3AYfawoAAABABYJR0MaAAwsJBwMVCggCFgACmwMCHgkioQa0cT77GQAH3u+EaO8v +lRQSRAjg5cu+eTVFVPGCgCaYqwUnCQIHAgAAAAA/1SCNpqdnKUMDbsb4fBkeo0Bz +KNByIG+y4qqVGI6llxYIY1BqBSFF8fMW6Nq2IhWg5zYA+3Sgr/mt7MV9mSoX2Ml2 +bEKfsmUnwV0GHn347OAip/QczdUjQ00fw4rh4RlH/wQINzIAz6MBRCmSF8OciPZO +NuZHfRI6cjNtNglnAna3aMqU9TZFfs7GT9cTphYIBhL73nrLf1AGUk/lcA0CNJhI +cPIaYMbXDy40FQq86nc/R+o5CfZS0LgeYCAhdIrCX1Y83c4gNfB7brHvXtxE3kW9 +pS0cYKBVCq0hvOs8eVzjAZ4mHerunAAfTgF+iLh/XksOPuxybel2p3iQNbmAoNgi +Xiki0d3nxW+/u8+G1RBUDGBBvaOrnuMuots1MXRmmB7d3/4HCDUr9UXbgRV9hwan +Zj1/xOKZ/k4oTl3KIcbyvkNHS+FnIYVjzn4FXLfXRBI+K7h/hmkZw4NgRnLZWYf/ +UR8KrybY5889RdpP7b2HOFRs9hfJ6d9yKAjTexCBr3/9pfG9G8SR4Xasbk2xOasQ +SOxS+p9uSWzLCCCHes+nhOIuF5Z6FHTB2ymJE468SdqYI4zfima1enc8VCh8xs3u +kCBAhkfNtK9xCUI8EG3DKqw/MRsKEAOqsPPzcTK/YNHvz7dAPTcvv9uBKwsjyYXi +NLVMC+zy+EhXHmmupDYAMpSeM9QW1Pn0R0TOHDMaCf2VSxHNWB5ysMTTtsQsq4G/ +78rKR9ySCINf+lphaD79UU73NDzLElqWgi/krCGRL7aaoFWTHrMgRwkEIO6/2m9Q +dLyB5+4w8Tg3m7NQHwrhpIGoyfXUqhubCxNM0xqpaNNdpvl66FTbQbUKn13BsSDp +ez2i8ofvEoFwrK2gm+4+HcZHtBGCO8lp0uf+ju7BsUS1VLj6egR8B6atDfqBmZyJ +LbMY8B5Nd3BoI6DfKEdY5oYnEnMVrvsHb2PJ6ciJLUkWngf485XeiRTc8MIpaJxF +6H4PaPL2LqW7kVQfP28TwMDNHvCEvi5hqGZLcNGWCD4cSObIqFFt1l5iQ7jBpeBf +F7NTds6padGFVV1EgWmf4IN0V+E8YmziFmkCVW9lxcSmZ4GnZ2ncWs8qoYptp89A +19wnePChEvx1/o5KTVP2jHtKM7N2DqazeEwbMnrn9n4Hbtg7LLH+DYQjMGQdX+Sr +qI9YOQIMOPiXJNe3r9TjGo/OSEtovgoo9zswoK+Z4NyHWAiOr6s6FzfObFujerLK +6x4P77h8tPjZ3rME1ePIt/IjathygQl94MoGqOBJ8feLGia7K0U6s1AsARm82yYg +Cof3pDkYxry8fhENVIFkwbIkdoDRqEA+kbI/uACODKeodjIuN17a6Hk6tqg4ql8H +R9HLvqURbPZaaVQ0gZzFZSRRmaU+I8Kv7sEcVWdz0PW/CE6MfSkXRWC9YIIsHwG9 +AMZV6l1I3dMMHt747bL2cKNXnScWuUpbZ4KZmzGhje3PZf2Bjk2sTwmVTM6j2Csi +pC4M15cBUe0JrQ/Eg8jFzGqZXxxLlx8onARVwLrlYcNu9Sm+OH7z5E0n9liuZN5U +QtjeX+N/ZMdgrIU76+ztvx0ArXqIjFALHAD/guCm/3iJbog0yJ9tKoKydAMVP+0z +XOwI+vCOSMC9kB/jeo7pX+9rTjMZhV8CNdEX1bTTMNA9cXUI5AHXG0/RnVmjoTnj +G5/3OaSy4Ln91mzVSZ2JlW0Ufo53qAWBIMsXUb0V+CKS8mj5oLLxKFy4LL2yR9ay +0qC18M7I1mWNDI5ryETLN7Al6Qs+i6/g2+Bims+52Sct7INZOJ9rydL11Qz4x7zs +xCA584tPJNjK/M2vqJCiNYM3xcPYFBT/9yqnyho9ua/YaknZDBHXkJxyvPEDfnhE ++Zsp/v2UepcXqFiLi+2lp/AxxTaQ6RaEZP8vjQAkGKgk9WDWNs2Uwdn+xyzpzMVg +cYkQJ/Yv6hOjD3AOuSZCWpDFoF86sXALokNeQuWkKkkscQSpxZUhFeBUl8Ha+j/j +kE+XNN5DgDWReF7EUJuJKLv3RauJ7TDnlSdWck4k8rUo5n+chWBbitnjjELRfuvg +kMuuO3pQO/5d5ZEPAAytUGDnRSUGmvXPifpwyl0C5Qb3EKNrhjCOshz/mVRRks0c +cEdx6hzk9dl2TUVDIwTHZzy86BgL/11ogoSvxXgupH4lmIT33avBnS0bYtp47d58 ++b+JvSyn9C4rrQSS6Sq1Cwk2cz7KUw2MCXMsFsYxmjs/B7JfeJ0g0dUrDcaTGFaQ +U1S5xONcCVQrguPI+ZPAkP/swNk4X2/MvQrg4esRT4ll/3/hvIb5+BBOzoS0M6dn +Dy3A/w3KxovCT7eTzGNgeHEh4ZCXfIG7iJRnLBb6ZIbPkMuArLzePRZFnTzkmune +I9B9+3fMZqO3u6AwrRK+yQ/DFuia8l5OFzhlATw36d+Tngcv8bKVT0DcIssxL2pt +o9oqEeYeDQfv77y/y4kByuwR0/yFZZ8dSjS2prrPLwSrjLVlv/0bKQOeEiT5nM5B +Hwg9EGXRE2MT4NbM7TIsdaN6/dRj09uIqrDsg7LbgI8bMackAZ+1aEix/V4+vZlm +xHqeLElsf34CZk0sSyP44oOAkZfOM9+hwKS2E4i0dpXdZ/JCeWev0inX7+/UWbk8 +VlsME/vujYTExYRmqVdGH2X6dSS6xDPVqkPpn/8befTDtmNrG3l45NJOEi19Pf8U +AGfU8a9k88mxG8aw5YRl7WX5to3bu25l+OQjPCUpuVTv7i/nRbY9Id56QPn7eCVr +DCzWz7XtEhgw7Myy76MIB+xwdEKni8P+/zxpGH0rwigT4Jy8cxEW5TJiI5FXCZkz +nH9cKi1kAXKmhDV4E5y1mfxYOPT1cwGQNuVOfx7ZqKVXz3zT3jSkhRQ3NQ5rJLCn +aPBX3B+Y6eTpSzT1IMi0PC9r+m8rj38ChFmnk2XeQiO4b9ofbdu8ixMIEVLw+rPt +CvXPE0ad6g94rA3ZYyrS6NKOZYRszE6w+vQeBHz8rmw8MV6tl6Y1h+WaKALh+QLN +g0aqPH+7S4FlZ0ItmsTAno3wPvMa/q+uo3I/mbMuvO3yYSiwX73b3cAAfdqtbXrc +AUf48CUpQ9V1N1HcVdpICX8duoxnznOCNIJmF95d3cK4WW04tFxcDwefGodGVwRU +7JmTBPpATqucxpTOkQn48G2Kh9nt31HVx86oqvOoahpmk2Px9lyPFSNJOURa86Dp +v+dpsbxtyUcjcSKHaXoEBzmfcQ9wJNDKiYXK3CmbS/1qhXhHeaejW0YeKN5qQL+h +DoonLZFpWgv4WZtsMiLSYoT62o9wpdtBQi7VvZdzafRqdttq38ic9CshBGYm8/qo +lvtcvJ0+f/BY71EN2bxo7BJFMY/AnYE83gXRoeCtEl7ETgQzIkDW8J4FrsH4Tk4M +9F9bEQqbKpCs5NvhNdLR6i1y3GwOU3oPgQ+BVr59orgIV59x5ZifQb/26BynIp9W +baxHtd8wZpI4k9q/u6DNm2mB4OLXu3MZxomXoYeUSZWuNzKVGEDSfC0fZMpFfm1h +pI4FrZBM8HktE0jZSodHUqNzPBNenPXvLKAR24qseyX1tV/H5WqM1B9lYWxmu4JV +eI6FqMy8K53iKdb7ufBPdl8Nn9pFIQ+F26joASbrfbaXMyfWbESISXV79u8wwBqB +opNHoufKNAi8CPRgRATMe4b+S0cyDsKSgjJT7TmArRnwC6Y+fwKxQmNF2h+4J6LI +JowUE6N2As/En6R39wtdmz+kW8dyCUpY4vsNCilDPBISEWh0Aea9bYQjkjHLMtof +IDKjJaAKnvh1QpMQ8Kwk3rnWvrcNofNgzy3KO93rT+A7GT+VQ7KmhXMFgv8jof99 +WAlon35Yx/rkp/g/w92j6r/nGF34dd7jfLvliG28V/BOJJ/yWupzdU92b4EkeDwL +2izAwWPw+NxINTE7CAfKo0sM0GB7oFfjUKvfx34nL5jM0cKyAAaM+aTA+gxlyjij +9VKAWyPDzbbLqkzGUEY8AbDncVlwaI8CpZdBOCmO/bmiuMeAzgoTeXBT9/PioXFx +kLbROlUq5Ml9i2eFikl/LF6oFpEviuLVPScN9EZdqOd0KZ3WKiZqdAxXExsxdewa +BnQ6rXJDRt/OaMHKoJnb3ykCfotpNkYk/bnqEH9N9w5Ap5ZzIxl86ZlBK8VTitKD +h49N4t+/WJoO6wJvsihrmqPC7fZuRA12Sd4YGxNHhVG8BwEMaya19poixdlT8MJl +97tMRmPd9oUfC8EskaqHsNuWl59S1+hm8ChvhodkRwtDkvGXVO4PMyHsaBhoElKb +QtQWk3BAeZ10qFeAW7D89IR6FLL0lffahSLpx5qlEgnXx7PQ33po5KBfZscTBVTX +rAbU0wqsuciYbwDb2S2+wapz0fqp9E0WoVCAiUZacrZX3aG6plzCt92txG9DlA9b +380BdJ0OfnZ8iFjxGu9GKGOLjc/UJkBOb6Gtvt3sdIa64Ok4TllwsuMfe6jJ6QAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBQ4TGR7NLlBRQyB1c2VyIChUZXN0IEtl +eSkgPHBxYy10ZXN0LWtleUBleGFtcGxlLmNvbT7CzMgGE2sKAAAALAWCUdDGgAIZ +ASKhBrRxPvsZAAfe74Ro7y+VFBJECODly755NUVU8YKAJpirAAAAABw5IDvdhgyN +any9XGQMooThi4Rgcljl0z/DJuswRUPvW+YBCaS4eVJVG5Ia8pV80EoK3KvbSnjs +nWtdymxsTdRpOIMUUfCxX6mgxp1QOhoXayWU0xgFzQ5buQtEn4exl6EpDX83SmBm +/RZgoZV6BWwK1InAsSUzkk5xX0aMyY/Pn9pTwy/qotAMzypeErB8tQ6RxbjVZ7fW +wVw4V4b575SSpBS9ueR+3aOGOtbqL/l+KVCVS8ajUxfHevu+yyhvxS+ycp4mWXGQ +vibC/XitvToEnR0nbY0Y/EEksWV277ysUFfh6vWFcEGO+cymrm4hRL3RXmgNnNuR +NmN0ogPP3mVcGaufk/Ro9GOxVXFld6ygAsuCo7wMUGNUQ9wuYmDT8Kwcgf7bHqSl +VWcByqID9trZGOWiHl+l8roIsjEuMZ4bqvG30KOSOJTl95LHAjqgYQsuPBehx178 ++Ra+Ne7KCFFOjc4xlYw9DunDJ9wiUAjZJw6IXDw8tJNbl5cZnMj+39eCjwx8SVXA +NIvWYMjxA+FOT8iKQNGtbGip3So/5Wv2uu/zSjISgvxwAgMt/2esnt4R45lBfrV/ +yStEyBG1JJxaEc540vPhksTppnJojPz/K84B3J+7dHqah6kzmRRl2sp+1gztXNp9 +Q70cK7c57SUPVylLA9e+s2lE5Qff6CnNbmGscznASXvgpFJK94hezwvEUwRXWsmu +qqLInfF+2rRqOZCnEs/xiBeK96jpJzfvldlqEiMo8/OWTEUPEZp3kPQcs1UyNx/Z +/r+Hhj9bfvfUMavyTNNzXyrp9jsKyv6mO9dTxqQ/zkgoIH6owR3bfb78HHEYOXBw +guTRswPMZXDweqlASimJ4O8Qu9c6dS6pAN5MWjuAJYm3tLhQv2V9ETi3uKNBfT6T +H3M8JO2K3zcjKOzernDC5A1KUYaMCKXF3VV3HpfptV/cHhlURzpTmVrICRVn04Tn +mhubnuAgo+2whJIY7YDubtOfxF9kbOyp0Oy9KfbD2EYmrgEFJ88u4bSeX1v0HUMH +pLbQISUFCLH6zSFO3Vy/pbfNAGFfd2/n1eLx/QjHJyVjdvKQpHKkfZuwnkUUT1J3 +IQG7MqOjDvM2tt4+l6ahYuGLY9U0XsqIwruLh3zNnDlJH2xbvjsBxTFrl2moDscb +9okrkqwkJK1lJXJTbIjwrN2zJyOh9ROlRIqzYO9tGfnMGSiy4hnWxScjVoBUsL17 +g2597ZWGuq/ardvezr8cbCN/VEJf9vhe8an+Hg0xAs8rXFB3IpjpZoGoAjxUvSFi +ZQlf+W0ynb9XXsdFEymts66YTpvLhzTgO56MCYXHoXtQPYIwNGCNj528pG+8xF8/ +Idm1E81Uf254TKut4TgDoOnvWeGO58DniNZGEV+Be6V/18dcEif0ci+u7dVtoT08 +7yAiUyL+UzYu6qzhezpypWXdm+8+d0itXMxh8S14WA0NrCt0k/i3AwxQ57v/RRFg +RT3cgVNYLL187romUkp//m989ruxP3+Yc1HA6Ymg/1v7w3P38U8nzEr3+IQFEHQY +4KiQfGSqy1Qnb0iKr1K/nUcwmKJSSTAZqrcVV6YxT55zCxCGscYcSE4fP9whfc4k +Zuf+hEt0f4rYZDwg9EcZhfIJmpzAyVs9DzSlOK264VcBnxPnY17Kdm93gG+gISVk +g2vS6sjfBMzyF1TrF7BP/q2gQ/7sAb+PAQVXGpn90EQTbzimg5i1l+MPV/UtD3yK +0r2gnbmQ6WdpRyNfyiMylixj3P7Bq5SrySBrpl08V8c8xtLnXpTYxLCFiOfMqagU +U+Ohw3GeNkcX5HN2Z4AsxVurXyRqiwQMgZ1yMiTzgHAVLg97TkPmyp7AF2zP74qO +IARPgD6q/xo+vnbKLmqEbJWpKkVAi8WuJaRLIe4rqiNN3LZq/ppPcauzzwUUbi3U +lKzsorFTiSn7qikpfPYGZEp2rCl2qIiUK6U1rsuEFBCDgEfENK76Zu8yOUwozQpp +HayWVVKlJ9Y8eoKHialmbhvFUNmCftn3l6d7rNip/teu/bmiRtIrnlaluZOztYvb +ZJuDUYMkYdeig3YGL5zbJ27IwfjEaFTizf63SmhzHWJj5x2oH5Q/SSyE0H25MvTB +KgI+di2gQA6Wo9ZcOcHSJXlFBGvZIXM+iUmdwBUBoAWL6OsGRAUSTC+HJiCL3Ayi +Bl4uFheiYtwSocAT35Fers3kE7E6Bzd1U3qkCEwveesyTwuOUaO7vM/diDODpq+W +7chbC94+skhN6KtQqPQjx5Nk9xNbulmCeR54RLgSwoP1cyoxMXjXDbH3y9sbmN6R +ZHKqLqSIC+hozBryFDJrhZnPrdXm7/ocRAPPI46hkSbTIV6Cp08RKH4OYMISH8ba +6Hq0iSk145/MXkNbcioTjXcv6nTB0+4B9sUI+w0iVHA+w57sRLV7BoFUYo/ymA5g +PEdsgb8hWZFH8fQx8LXXDLOWCnGW5J3k2BGybZeNW8FdIedE9STr0z7jS8bEllLb +LwXuKBJDRDM5yW4p/FrQGBm2X7Oui4mKIpep9Nzc+bNzNXlnoXJR156lQAVPuL6x +7ivfW9DRtkh3TM4eOTAMfNS7lUIUbdpKOHfTCAG+HGkPX8tzd4CeukUM+I08wHgn +r40JK3De7xsZLN3cZZLG4v99oe+kqg+KMLO1PhRt77DE6Xf+82RiPWHb/KDmF99n +0qvGyxOd8wCh5prd7iKKzmAxdb5SfnMzYcYOSilx3lScSV2DYRKGqIB2B678zbIv +N4DDzbfFnNswVr5MCTPf200u134KsHbLZJ3KMA0h7MdcCoMJOd2VFxt3QgnsNkQd +G4e/hkHbUYW4DOfNCGBiM4PIuiSqjZsEsSxEtYyLYVHEzCIqCm0Fl8W3sELjdeGM +KvQzk/p6UqdQWLPvoyjcznzrvmDAq/nQJe40NMAIajlmuv2i4c5TG4ORJwTkHaiE +Bj9ytcwWKaPtJ4KcFXK/udW4axufpY5ctODJ0uGu0pVSzQEJhI+AMAtsstrL6i3/ +pVu5HzRyJk9/C1hMdraOSvF0UOLWH9Z8J+9B213FEx4K3h1D6VmB67j8MzKE+Hp/ +MeVW7oTGTPECYyQTaAV+mcnk5Uow2Z6uYZiOPY0ilQksuUuOza8Ldm3bmyCSNCc9 +c7d5vNrriwLxIZGQRgbZwj9pKXWTVUkmZuL0r2K5pQjFw9z3vZfqA1g+8PAkEDuX +DRepwDHqTF8tk21UXyCF47AJHPD96fy3c/jJgt0uQREJ35DuN0chaChsXBiK5m5E +aeN7Bd8A7/y/3rujmZG6YJr9OVmySUvTtI6y/KFBj1s9N1mhF0KVxnAB72ZHWBZK +WcVybuzmj0LUG9tNV34ruCN0gwvL6WN3Dk1wlM3mrqQhhTaXibGmgEYqBBSACgxk +1Otfyj34aWpBNFdAfj+5MkOin7qOnQJumFpKUdcNpER/JA/OwwTfMAIwV4N7+uRJ +EYRuGOEuwDqpENRpRPWHBTOCrLnT22u0aS+szz/89hxVfeE5DtfO+fQhDN2LzkdE +xdI1mwhm5oXcGtoYpZ6bzinH16lVaxXq0XJ/4VOWBxCJELvxhzT1T//oLr0bTiV/ +jQodrCNmhcXrliqBffqEY6lKXfCvbavh4VsllLWNlLJnupDnkClsymXqWFUSifwM +/Z3uRN0DrQQWiFN4ocqnz3T/l7Vj6JfDoWZTLgvj4oEkFyb09VJ9xR2B25bbssjQ ++UDOanfTQMcvfbp1qdeBw92Jd4gjmbMdoTf2PHwepE0UU/lCAsPRQN91/TDfEkP4 +PBH7qfWYXByKoQDi6TUcxOftY7lgZHgQhS7QOupZcAaR5iZHcB2WupdSK3tXUdzY +HYct+VwdF8UwFiKLxeWPmYx6C4YCjYA/jWI81nGnJz4UHdttOgr9NV06apBKsjjk +YrpFhNEyu+VqAHdKKKjH4Elg0AZukBmVX8mVvXj3P+5EJj5Laut9KXEeBbF8YVcv +7+kd33zgPz75hREccx4yXFtmN5Au670vSB9caA2vOdUmjBrIW4pZweszGMI/BG9i +oJ/TzE6oH7zm2e1QmU5+oV7tIDoP2TxalsX7XpDv9OQarBCq3Lu7E0KFbfdNqQ5Y +pitoy5fwIMWUF3Rkwc/8fa81B/Mr26Mx1zp475p3VM9t79pPb9bCw92Ke7COBBIy +vltdMcrZllEgnq85HEkfKqyiP8n0ikijDMEdU1kHtB3MPmQw/GPmmVBb1kLkbwCj +upnzZFIpCweXDi2ggJjEEl+6/metqUglj3L/XT8QGXvvsND3hu1fZOpeyAbO63XK +1KYhzHiiz4zjkvxMxYaFKfbjNi3qcsNFbryrnbj/sIa97URV8TS1VWpgUjNGXsqH +VHHfNgq0eSFO0/KqlHPa4IOvhWitRl228iZE8kRTaNc/dRrTGazt7i75Ov0pmZkZ +27d0YT7ntGkoSHItYLUyq968ecr7F1SfPC6rX3XB1OYoQlJdeXye1OIMT5o1RlNU +VYO10PAZHTNnjcbUMjdZadwAAAAAAAAAAAAAAAAAAAAAAAUOERohJsfEawZR0MaA +aQAABMATLAq5oapniWknjWnAfmn6pYAZFod1eAxgMb2vgCPMA8bEoYF4juT5Tvn7 +d7VSqP2WS7OUq4kLULJTa7TpJJ2zIoj0sb+BeG0Jnfrhhwe3M4L1d7HKZsegJYla +uB0SKAdlRBRYZ3+4C2dmTI1qxTQAj/d3tFZmFXMrmis2U1gxe0CaihoGui1kVjLb +uWoWWsxMv0YIEmHjmDhHjYXZGv9Qt8vIqfD4Kvs2WoSxp58StmNACKExJy3RHGam +P4FslC6XGAa3AtKqxLO5tpZkbaXmCwajxg/5HbzhYz2nSHA4Q9+bsuVICIUAcK/l +i+fMEzs8jySbCW3pcz/qaS5VeOfVYMfCs9b7wAlWz55wyYNzj4b7Nf+0lue7fali +IArlhPOCkYI6cYuARfAwVAGJuPtHVt/TeTA3GEp5uUbLNKw7Okh6XEAUeWaqsjug +mcjDWBeQKXLjEA1zr7HXM2QZOLVsqIyHjX7Wo3pavtYCLTymSAKLiHJniJw5aQaY +WxLyPKmkMCjGxjf2l0/gYsoHGQIsQMoyqnY6HZvIdOvxadKoEpWkMVWTFFNQdEMq +O67jBBzKgbGnLuI6b8IBbxZjW3b3AHjlT0zTd3rkPSkUiua7FbmWS6swYmQwAq5L +UTu4qPPVvUS3qYuHPF91Xk4lfQZ7mz1Lt1/GFAp4pEPXk9YMuHVCGvgVB/oZQ7sr +n6S1cHdnDunbzcbFpoDEptlSnHHZdAD4uiBje+v5UVdVHir5oYcVY45oAhzYbnYL +OTU1qfm2rfEpk2/LaexpWR5gDd9cCeo5vdyama9JXyhHpKPFgjMzDviEQtiXfaxV +teVgFQtsEwWhSQXXq7KHOfHKvyBlc3d8tsdQlOrVMb4Kd3TGX7BjWQ+EEUtEgsu4 +v/qSUIECXVkmy1KIfEYyPJYiuHAMb/h6yynbx5A5PR2QvO3WFGlyDXQCeCc4f1xE +Kf8IlNVQXlz2bnDcF2JGaOKBmYKcoXrLvvIgYmQbYTgDQjQQRiuhcQz6oHd8ihdc +TqY8OQjynTxStcyGc/Nch9TyGJHby1AgraJSx3rsp8BbaY07mDRqGS0GsmaSj57r +oMLknpbTQTVXzW0FbECGVTkskYfkUxWws5FyoqKnQu7RZMSGzkfRjgBQR8HSMlA7 +MfxHavi7HfxFQtKQCHzggR1VbTjQC8Qat5Igqg3XQRXkQTPXUfQwmE/1cCdoTdDa +RNc3XMlHU494xLdVTM6gNuiGatEySSh5Nt0ZpBZATSDyjkPDgvdjFJEAjzWJBGMz +hgmghZ/sxdQJoQDjuqg8FOtis/eoMjUnFuBrSN/8cXa6xn7TmFSmHh35ERZgH7DU +AkMJL93IX40zpd0mL9ihtSXcWlrJY8kjqxiVO7/DYqGmoxPmBwx8Om3Djk2zbl8A +i/EAVg8kWzolJXBCpgL4GRV7bIHSpSD0Prcxsno2EjZFrsPyUornbKqUuz3bDbbj +UQWxMnLBKxI0R+b2u0IYoqQ2oibntl4ROUdjZ9RCES3IWtP7DEOkbzjTzd92otOY +J3NkNynIml4hVf31kj/zudhlHBNRH66CQsp3zLWVKOtlm064Jv7azWwT8YroGarQ +25zoCt6yOpg8Rjy6nFVq1USEGMImALtkeAuD5VzXDp62ywkyCe4P5Cf/9B8parUy +Jkibbbr+mtlG7Osf5cJGP+b89JVXtUtXueHRsEaZKJDEAKx617xYHP3meUG2H+Y1 +iV0FQRWrd5Sfa9bYTUGjW0jjYAeNOsLMyAYYawoAAAAsBYJR0MaAApsMIqEGtHE+ ++xkAB97vhGjvL5UUEkQI4OXLvnk1RVTxgoAmmKsAAAAAad8g8vh/MfP8372fjARy +TXKqhHHSnfvEaml9t5UVsWCFVDBt5vv1e1ZYkeU4nFxqKDIJGQVj+vGEcEGw6gD5 +SATaMk7ViFWWRzpVRc209Yx93jz049pE7fRQ9CYRNXb7FUQBcN4lJL7zlHlmTJLL +v6hMCXQUIAm0tht4EgVdDA3CHyzORsKnJ00FYrrHokQRil2A51k50HzaA2B+a2Y8 +MdWzEUmkaZyxwrxddbT9jXFEMWwp7opXhFs6321lWOziVgFTa0uYQoWaUbqFZFtK ++9uEToLYuL1hSAMQ7YqDdl5Fib5xD+tr7bbk8lHYBii0ZFJFVXvsjTtWD+cTf7nL +938ceYwHhaYxH7r0L/yYOO07/RqRP8ELUxpBPjjr4esp31R+hzzwsPkjmFRYMJV9 +U9UtcNilj2VwzfOg51IfPaZ3NjVdWgABUuLQnTlyfbaKumLXuWN4CnJP1vflKQ5D +uCjly6NHvRJES4LfKsW7KMJ9VAJ5a4sPMiu+nmCHSj6xbvhJzzuJKlOWzSkmksSe +tkSPqCic3Y1ResG8SvmMEYfXkG0PIVDQs93NuICtCkU6lRUGARmW2OV0O2pqt7Mu +nOXmK8iQOuOqqjQ/8Gvms66HGHCx0tA+qzOk5KpYkwFdQpCwUiVNLOX1djeH1RgK +QkebRJCZxZG/RCVh66PXOpv3JKQY2VscDzf7x22FDxuCDiKR72Mi15XydCi6fnQI +ug1/j6olqArvt51WpBoM/aN5uD7fuzqcv5OaCXuhyck6lhLRfp0/YRaYdlciihOb +1jHtdO4545qpeb/qETayE7R88zrUQLkiNsjdGdxHgs+MHl64KFC3D6mDvkqnFdqb +7Nd4FxDCBGv5ktQlKFKhGWtrR7PWnOYif6JqzzgsxWnC1nmVEAeWtw17s4tuke4c +Rh5owUNJBZZygKBJsn37H5cXoZHw8uzmESNxgMxw9zVUoeOc+l4eX5ynM+FxmXhx +IhOH1sQluFb1MpQglVPBrWzz/2NKvV9tsQq+lISpoewliGawL6Vh7X8qyvzad1Lm +ofEp0p9RrUwl/iGveCR0bdX11D5P/JyetN97OmQoLGmI9FWWrCZ46rlqMuH6+53i +ejXDUGXOnn0D27y3MdmFtklIMOMNapEt5Bz7iFbtA0uxPBD6TjlYwP5l6FEzjVyE +/KeOyv+oVZzTFsKW2mfyfPrj2N+DyPrMknZzI2joNGUkKfcuRcO681OU6tX3bj01 +sTWo7F6wg4ZQdT6Aje2ryScj24eHAjbGRqI7VQGvDx/kYmSXdrbhHG4Hnmk6mhG5 +NO1kR6Wu8EioJ2wCjfxBmzHGu4RP2+pWji8KIVeIy3LYfyKpgP8jxx62VbGYrUV4 +Iag+OPBukfe3QLhr3p5iMnoPI0ihwNYmCzCvJ76IKLmfjwchvT/W0a29syQuKcNa +ofjSihIlUs3ug1T/ZG3Xyl7NF2h0YFHnF7Rpm3WRSZQsePbMGmwiEck0UFP/Z/DP +Fe1V8lkH3hEty4NtMUqtn5F1VHalFs4C5UYKHtBRuZvqjvr0xnbZDFouCc7m4Vjp +lzsS1tSjLl6EAyonAbbQ3vCtTn3v9k8Ro8J1p9mRHA1NdBCTI9J8Lkml+f1IIn8g +VdHTTiYcqDxM/zRPmC5ve6fAD+BFh7qvDkIGqpB0FIkHnstjp2/XFaxJ1Xso7e0Q +Yo30tzVyBFNu8KQF8Okeh2Mz6M2oKn8GInjeDMWD9DxlZwHOnlcWuXFeurj79G5Y +iUffg9el18KCwIMrnDD48xUqv1gYDRy/1LAp3AE3nnm5cIPq1Rp4Nsi8DQBOW/ZL +J7HW1IXs6o2U7Hytlx+KLZ2a3ETlZ5Nu86OwZYhErsLxDd3wF/85NYUzMxvO5uAV +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 +-----END PGP PRIVATE KEY BLOCK-----` }); + + const publicKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +R7PWnOYif6JqzzgsxWnC1nmVEAeWtw17s4tuke4cRh5owUNJBZZygKBJsn37H5cX +oZHw8uzmESNxgMxw9zVUoeOc+l4eX5ynM+FxmXhxIhOH1sQluFb1MpQglVPBrWzz +/2NKvV9tsQq+lISpoewliGawL6Vh7X8qyvzad1LmofEp0p9RrUwl/iGveCR0bdX1 +1D5P/JyetN97OmQoLGmI9FWWrCZ46rlqMuH6+53iejXDUGXOnn0D27y3MdmFtklI +MOMNapEt5Bz7iFbtA0uxPBD6TjlYwP5l6FEzjVyE/KeOyv+oVZzTFsKW2mfyfPrj +2N+DyPrMknZzI2joNGUkKfcuRcO681OU6tX3bj01sTWo7F6wg4ZQdT6Aje2ryScj +24eHAjbGRqI7VQGvDx/kYmSXdrbhHG4Hnmk6mhG5NO1kR6Wu8EioJ2wCjfxBmzHG +u4RP2+pWji8KIVeIy3LYfyKpgP8jxx62VbGYrUV4Iag+OPBukfe3QLhr3p5iMnoP +I0ihwNYmCzCvJ76IKLmfjwchvT/W0a29syQuKcNaofjSihIlUs3ug1T/ZG3Xyl7N +F2h0YFHnF7Rpm3WRSZQsePbMGmwiEck0UFP/Z/DPFe1V8lkH3hEty4NtMUqtn5F1 +VHalFs4C5UYKHtBRuZvqjvr0xnbZDFouCc7m4VjplzsS1tSjLl6EAyonAbbQ3vCt +Tn3v9k8Ro8J1p9mRHA1NdBCTI9J8Lkml+f1IIn8gVdHTTiYcqDxM/zRPmC5ve6fA +D+BFh7qvDkIGqpB0FIkHnstjp2/XFaxJ1Xso7e0QYo30tzVyBFNu8KQF8Okeh2Mz +6M2oKn8GInjeDMWD9DxlZwHOnlcWuXFeurj79G5YiUffg9el18KCwIMrnDD48xUq +v1gYDRy/1LAp3AE3nnm5cIPq1Rp4Nsi8DQBOW/ZLJ7HW1IXs6o2U7Hytlx+KLZ2a +3ETlZ5Nu86OwZYhErsLxDd3wF/85NYUzMxvO5uAVO2LO54jKjpTkQIHpMC4n4laH +M3bQJf2HqJIOwEdL44M5vcXV8jgfoKgoVqUlJDP9SBUQZ8aoLWCq9fAaDgjCjh38 +62zrcfclfNlAIFnje1bWz7S+Wr6IkG1vkj7ViGLix2+40wftuzo1+igIutUyRdHN +7I+ggoFBf+zXEbSlMhV6sW5/4PFw//n0+julq35FKj5psG8/XmLZun2E0CMOTNDJ +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 +AAAAAAAAAAAACgwOExkk +-----END PGP PUBLIC KEY BLOCK-----` }); + + // `getSigningKey()` internally verifies the ML-DSA binding sigs + const signingKey1 = await privateKey.getSigningKey(); + const signingKey2 = await publicKey.getSigningKey(); + + expect(signingKey1.getKeyID().equals(signingKey2.getKeyID())).to.be.true; + }); + + it('ML-DSA + ML-KEM - Test vector: decrypt/verify', async function () { + const privateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK----- + +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 +QkebRJCZxZG/RCVh66PXOpv3JKQY2VscDzf7x22FDxuCDiKR72Mi15XydCi6fnQI +ug1/j6olqArvt51WpBoM/aN5uD7fuzqcv5OaCXuhyck6lhLRfp0/YRaYdlciihOb +1jHtdO4545qpeb/qETayE7R88zrUQLkiNsjdGdxHgs+MHl64KFC3D6mDvkqnFdqb +7Nd4FxDCBGv5ktQlKFKhGWtrR7PWnOYif6JqzzgsxWnC1nmVEAeWtw17s4tuke4c +Rh5owUNJBZZygKBJsn37H5cXoZHw8uzmESNxgMxw9zVUoeOc+l4eX5ynM+FxmXhx +IhOH1sQluFb1MpQglVPBrWzz/2NKvV9tsQq+lISpoewliGawL6Vh7X8qyvzad1Lm +ofEp0p9RrUwl/iGveCR0bdX11D5P/JyetN97OmQoLGmI9FWWrCZ46rlqMuH6+53i +ejXDUGXOnn0D27y3MdmFtklIMOMNapEt5Bz7iFbtA0uxPBD6TjlYwP5l6FEzjVyE +/KeOyv+oVZzTFsKW2mfyfPrj2N+DyPrMknZzI2joNGUkKfcuRcO681OU6tX3bj01 +sTWo7F6wg4ZQdT6Aje2ryScj24eHAjbGRqI7VQGvDx/kYmSXdrbhHG4Hnmk6mhG5 +NO1kR6Wu8EioJ2wCjfxBmzHGu4RP2+pWji8KIVeIy3LYfyKpgP8jxx62VbGYrUV4 +Iag+OPBukfe3QLhr3p5iMnoPI0ihwNYmCzCvJ76IKLmfjwchvT/W0a29syQuKcNa +ofjSihIlUs3ug1T/ZG3Xyl7NF2h0YFHnF7Rpm3WRSZQsePbMGmwiEck0UFP/Z/DP +Fe1V8lkH3hEty4NtMUqtn5F1VHalFs4C5UYKHtBRuZvqjvr0xnbZDFouCc7m4Vjp +lzsS1tSjLl6EAyonAbbQ3vCtTn3v9k8Ro8J1p9mRHA1NdBCTI9J8Lkml+f1IIn8g +VdHTTiYcqDxM/zRPmC5ve6fAD+BFh7qvDkIGqpB0FIkHnstjp2/XFaxJ1Xso7e0Q +Yo30tzVyBFNu8KQF8Okeh2Mz6M2oKn8GInjeDMWD9DxlZwHOnlcWuXFeurj79G5Y +iUffg9el18KCwIMrnDD48xUqv1gYDRy/1LAp3AE3nnm5cIPq1Rp4Nsi8DQBOW/ZL +J7HW1IXs6o2U7Hytlx+KLZ2a3ETlZ5Nu86OwZYhErsLxDd3wF/85NYUzMxvO5uAV +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 +-----END PGP PRIVATE KEY BLOCK-----` }); + + const publicKey = privateKey.toPublic(); + + const armoredMessage = `-----BEGIN PGP MESSAGE----- + +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 +-----END PGP MESSAGE-----`; + + const { data: decryptedData, signatures: [{ verified }] } = await openpgp.decrypt({ + message: await openpgp.readMessage({ armoredMessage }), + decryptionKeys: privateKey, + verificationKeys: publicKey + }); + expect(decryptedData).to.equal('Testing\n'); + expect(await verified).to.be.true; + }); + + it('ML-DSA + ML-KEM - encrypt/sign and decrypt/verify', async function () { + const privateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK----- + +xUsGUdDGgBsAAAAgoqT/71tSJR8iwTTL04KHMCQPkA/hzws9IS9XIOaDeCQADJT8 +QsDoLSnhKcdIiebWP4SjTjripGF8Ts4ToMFQEMfCrwYfGwoAAABABYJR0MaAAwsJ +BwMVCggCFgACmwMCHgkioQZvmMbg5VVdnVgHJHsuCi6TZqsB2ingw/HQ6kw4sTQz +8QUnCQIHAgAAAABTCCAcorV7OTWoI+oc6cJHH7sQwt58r/zl67/IGhs4IriTdJDo +zEDjgfDQ+xdUnlNDAH26XFsCpuZlViHCWx7d2+UHYSl5RoXSl7nUJZwXD+Q14pJe ++pXhruANfqpjih0JfA7NLlBRQyB1c2VyIChUZXN0IEtleSkgPHBxYy10ZXN0LWtl +eUBleGFtcGxlLmNvbT7CmwYTGwoAAAAsBYJR0MaAAhkBIqEGb5jG4OVVXZ1YByR7 +Lgouk2arAdop4MPx0OpMOLE0M/EAAAAAdU0gQGuJLou9irG3sTNROnX/x4zsskxb +kkpcBQAzEVrH9u/T8HsDJwodnFZSoPvvvrJ6L64wItfdB6t4zAzd0YL76vTn+V4r +zIADNDy4WyqTeysUzJDQQDvLpuOJ2uK2uoIAx8RrBlHQxoBpAAAEwLnXFoEjTQ/Z +ow5/AEqq8vXgv0Kkvz3m9FSpXip7+MsTAVhfO8fOLsy2grZ1BZl0q2rBaRfPv/jF +4Fpq4lpfUdlZ8QCZ6nB/zGtmYAcQQ3qWjCZS8VJB6oC7hHoGOUOkRxIhZ5kaa9sy +juwe97eLz3l/HFwJOVZCj5ROpkCUBgW+7mwnqxCOWkl1A/gd9moaIFZhcPKVkxEn +ErYrRmGs0tzKaoBfejetTWMlw8bLQGWq+hC+wQBfSzNs1bmt2xO08DxZFZFyxSkI +xDUy/doh8HlWbdg65zwbZgC9Xfq1RAgpj2AT38MarlElJYqqpdgsI8pz0Qyg9rUp +I1iJRaIToNBzpBWyKkGC+hwyrgTNXRhANQZK8pkKMXGQffo93jJiBquiF7t8QFIE +SiJhiCrByCyCagpLhfG3/uQ4aNAxMhspK6amFAONLGwFLIVJIYwJBgtJstJSAOO5 +F4eSdYOVTsc015bNVWHD6aBG6RdInvEalRYA2vo43kJPJpXOWbGxrSN29fc4D4KM +qBQ11zuHwxcoUxvLoGlHF5xNU7skSsG8VKBz4suqagqLoWgMJkxs17Mj+/YNt/Uo +6cMBmOC6Dkgz1dIAQPCS93VRy5RnZ/ksOwNvojZrISG2qjK4zdM3oSbF6OQNpLst +GGajRpcrOzWJgXZ1w3ddZwll2DuY9/k4SypuritMljCh8EVb8YK5T1SmrEx4MZcU +eFE5M4uLdwWrvOeOPNJWn2OimJYW25q9X3a7cocItKQUL6Rog9WYzIeuyleATUlG +9kQarVZ9vLLLBpfFXdmuS6nIx0NIPYqrsktYKWkbMYimRRwJp8OUbXu/E9TB0tG5 +48NVYNVeBQSrgGK9cnAJSPVd1yiXivCzUTRZytCUrFeA6FUVJyOF0gFR5BIkQhcj +6zao5TdhFoURG/VI2ok42xtvK2MIdUGSecCN8cqUUclNe8YFVZRGUwiAapJTzvpF +kzO6otd99eJbuPyagjG6BadalZkuntllEzF3LamcllsgGMZkfjm3Y+df6KiStNlG +jXXL7oEXeRgSnWWhccVu/jot4JGoFKMK/UHBapG7GDuVKrWcNRiSHdZ09yJDxqEY +ZkEmESdzX7AB6nKN1yi0e2NChGgh2Ag5TTSfmVFHrPUytMBD7+VLLgfCn9XMiezN +FzdKwCUMWybF1fpur7aG5JalAEaJCvMhw4l8ovJGfBEV4rMvVwgb88svQTc3hIWV +0VNCYfSWkvxXy4AXeFQ1p6sKP4pt9wphdTo+fYm5krMQK7HHsixxFpzA9UNy7jxp +y8Wt+rKPc1Rk4wkPDPlziHmCqyOQoBQIqywyYlB0SJpZ7qgY4miGkMu4BNujOcoI ++HuaV1uS6Ax0dko2ycvC4zODUrahkKg8ZRPNhLmq05h7uTGjsudQ5iWQ7JKzUvPC +IjyLVZFqA/af22t6m8oZ/ZefCkgAHRAdGZGZvbxEUYNG3+U8uNqNIpV3oGFefKGt +dtq8b5HEp9xUDOOOPfVP3OSicnpI0FZV7IaTSRemrsFLV9UPeKo8jeyDFJQCvnQm +M5ygZYmysEiTmKnNX3I7xjhOXtkHGdsF/eatr8BoVWPQqqslLuFQ7bvNDj+JrFhp +H7SnPRs8wf0APxvBELBWHS358MzYhgHl2qlB98eNlpYONMLC1OKwcdZtBaQLK1mS +0E3CFsyhm8aNsed5h3INCONDDB69NDnKcECHyEHEmi80B3PrTSvQEhu86Icku7kE +ci7WflvsjTyVwpsGGBsKAAAALAWCUdDGgAKbDCKhBm+YxuDlVV2dWAckey4KLpNm +qwHaKeDD8dDqTDixNDPxAAAAANrrIF2vwK+ev6toBw/VGv6eWcvSqr1cCaNXR+z2 +R7sK+lxrgTGbHvqDFrevkCwv1wtJ2AY6uTkFzMTRN8ZafNdUc8oeR3FbfVNO0Phv +BoWQifC9dbHD5JNv0/6CMXFZagQABA== +-----END PGP PRIVATE KEY BLOCK-----` }); + const publicKey = privateKey.toPublic(); + + const plaintext = 'test'; + const encrypted = await openpgp.encrypt({ message: await openpgp.createMessage({ text: plaintext }), signingKeys: privateKey, encryptionKeys: publicKey }); + const { data, signatures: [{ verified }] } = await openpgp.decrypt({ message: await openpgp.readMessage({ armoredMessage: encrypted }), verificationKeys: publicKey, decryptionKeys: privateKey }); + expect(data).to.equal(plaintext); + await expect(verified).to.eventually.be.true; + }); }); diff --git a/test/crypto/validate.js b/test/crypto/validate.js index 97f7d3a9..ca448c74 100644 --- a/test/crypto/validate.js +++ b/test/crypto/validate.js @@ -315,31 +315,41 @@ export default () => { }); describe('PQC parameter validation', function() { + let pqcSigningKey; let pqcEncryptionSubkey; before(async () => { - const key = await generatePrivateKeyObject({ type: 'symmetric', subkeys: [{ type: 'pqc', config: { v6Keys: true } }] }); - pqcEncryptionSubkey = key.subkeys[0]; + pqcSigningKey = await generatePrivateKeyObject({ type: 'pqc', config: { v6Keys: true } }); + pqcEncryptionSubkey = pqcSigningKey.subkeys[0]; }); - async function cloneSubeyPacket(subkey) { - const subkeyPacket = new openpgp.SecretSubkeyPacket(); - await subkeyPacket.read(subkey.keyPacket.write()); - return subkeyPacket; - } - it('generated params are valid', async function() { + await expect(pqcSigningKey.keyPacket.validate()).to.not.be.rejected; await expect(pqcEncryptionSubkey.keyPacket.validate()).to.not.be.rejected; }); it('detect invalid ML-KEM public key part', async function() { - const keyPacket = await cloneSubeyPacket(pqcEncryptionSubkey); + const keyPacket = await cloneKeyPacket(pqcEncryptionSubkey); const { mlkemPublicKey } = keyPacket.publicParams; mlkemPublicKey[0]++; await expect(keyPacket.validate()).to.be.rejectedWith('Key is invalid'); }); it('detect invalid ECC-KEM key part', async function() { - const keyPacket = await cloneSubeyPacket(pqcEncryptionSubkey); + const keyPacket = await cloneKeyPacket(pqcEncryptionSubkey); + const { eccPublicKey } = keyPacket.publicParams; + eccPublicKey[0]++; + await expect(keyPacket.validate()).to.be.rejectedWith('Key is invalid'); + }); + + it('detect invalid ML-DSA public key part', async function() { + const keyPacket = await cloneKeyPacket(pqcSigningKey); + const { mldsaPublicKey } = keyPacket.publicParams; + mldsaPublicKey[0]++; + await expect(keyPacket.validate()).to.be.rejectedWith('Key is invalid'); + }); + + it('detect invalid ECC part', async function() { + const keyPacket = await cloneKeyPacket(pqcSigningKey); const { eccPublicKey } = keyPacket.publicParams; eccPublicKey[0]++; await expect(keyPacket.validate()).to.be.rejectedWith('Key is invalid'); diff --git a/test/general/key.js b/test/general/key.js index 2392bf63..ace5298d 100644 --- a/test/general/key.js +++ b/test/general/key.js @@ -4607,15 +4607,19 @@ I8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUrk0mXubZvyl4GBg== expect(v6Key.subkeys).to.have.length(1); }); - it('should throw when trying to add a ML-KEM PQC key to a v4 key', async function() { + it('should throw when trying to add a ML-KEM or ML-DSA PQC key to a v4 key', async function() { const v4Key = await openpgp.decryptKey({ privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }), passphrase: 'hello world' }); expect(v4Key.keyPacket.version).to.equal(4); expect(v4Key.subkeys).to.have.length(1); + // try adding an ML-KEM subkey await expect(v4Key.addSubkey({ type: 'pqc', sign: false })).to.be.rejectedWith(/Cannot generate v4 keys of type 'pqc'/); expect(v4Key.subkeys).to.have.length(1); + // try adding an ML-DSA subkey + await expect(v4Key.addSubkey({ type: 'pqc', sign: true })).to.be.rejectedWith(/Cannot generate v4 keys of type 'pqc'/); + expect(v4Key.subkeys).to.have.length(1); }); it('should throw when trying to encrypt a subkey separately from key', async function() {