Skip to content

Commit

Permalink
Add PQC signing key validation
Browse files Browse the repository at this point in the history
  • Loading branch information
larabr committed Jul 8, 2024
1 parent 5d26a74 commit 3a81caf
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 13 deletions.
7 changes: 5 additions & 2 deletions src/crypto/crypto.js
Original file line number Diff line number Diff line change
Expand Up @@ -596,8 +596,11 @@ export async function validateParams(algo, publicParams, privateParams) {
const { eccPublicKey, mlkemPublicKey } = publicParams;
return publicKey.postQuantum.kem.validateParams(algo, eccPublicKey, eccSecretKey, mlkemPublicKey, mlkemSecretKey);
}
case enums.publicKey.pqc_mldsa_ed25519:
throw new Error('TODO');
case enums.publicKey.pqc_mldsa_ed25519: {
const { eccSecretKey, mldsaSecretKey } = privateParams;
const { eccPublicKey, mldsaPublicKey } = publicParams;
return publicKey.postQuantum.signature.validateParams(algo, eccPublicKey, eccSecretKey, mldsaPublicKey, mldsaSecretKey);
}
default:
throw new Error('Unknown public key algorithm.');
}
Expand Down
9 changes: 9 additions & 0 deletions src/crypto/public_key/post_quantum/signature/ecc_dsa.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,12 @@ export async function verify(signatureAlgo, hashAlgo, eccPublicKey, dataDigest,
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');
}
}
2 changes: 1 addition & 1 deletion src/crypto/public_key/post_quantum/signature/index.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { generate, sign, verify } from './signature';
export { generate, sign, verify, validateParams } from './signature';
16 changes: 16 additions & 0 deletions src/crypto/public_key/post_quantum/signature/ml_dsa.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import enums from '../../../../enums';
import hash from '../../../hash';
import { getRandomBytes } from '../../../random';

export async function generate(algo) {
switch (algo) {
Expand Down Expand Up @@ -34,3 +36,17 @@ export async function verify(algo, mldsaPublicKey, dataDigest, mldsaSignature) {
throw new Error('Unsupported signature algorithm');
}
}

export async function validateParams(algo, mldsaPublicKey, mldsaSecretKey) {
switch (algo) {
case enums.publicKey.pqc_mldsa_ed25519: {
const message = getRandomBytes(8);
const hashAlgo = enums.hash.sha256;
const hashed = await hash.digest(hashAlgo, message);
const { mldsaSignature } = await sign(algo, mldsaSecretKey, hashed);
return verify(algo, mldsaPublicKey, hashed, mldsaSignature);
}
default:
throw new Error('Unsupported signature algorithm');
}
}
7 changes: 7 additions & 0 deletions src/crypto/public_key/post_quantum/signature/signature.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,10 @@ export async function verify(signatureAlgo, hashAlgo, eccPublicKey, mldsaPublicK
throw new Error('Unsupported signature algorithm');
}
}

export async function validateParams(algo, eccPublicKey, eccSecretKey, mldsaPublicKey, mldsaSecretKey) {
const eccValidationPromise = eccdsa.validateParams(algo, eccPublicKey, eccSecretKey);
const mldsaValidationPromise = mldsa.validateParams(algo, mldsaPublicKey, mldsaSecretKey);
const valid = await eccValidationPromise && await mldsaValidationPromise;
return valid;
}
30 changes: 20 additions & 10 deletions test/crypto/validate.js
Original file line number Diff line number Diff line change
Expand Up @@ -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' }] });
pqcEncryptionSubkey = key.subkeys[0];
pqcSigningKey = await generatePrivateKeyObject({ type: 'pqc' });
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');
Expand Down

0 comments on commit 3a81caf

Please sign in to comment.