Store named key params in key objects (#1141)

- Store private and public params separately and by name in objects,
  instead of as an array

- Do not keep params in MPI form, but convert them to Uint8Arrays when
  generating/parsing the key

- Modify low-level crypto functions to always accept and return
  Uint8Arrays instead of BigIntegers

- Move PKCS1 padding to lower level functions
This commit is contained in:
larabr
2020-09-04 14:23:17 +02:00
committed by Daniel Huigens
parent 8854b097b4
commit 3a75eadaa0
24 changed files with 634 additions and 776 deletions

View File

@@ -8,7 +8,7 @@ const expect = chai.expect;
module.exports = () => describe('API functional testing', function() {
const util = openpgp.util;
const crypto = openpgp.crypto;
const RSApubMPIstrs = [
const RSAPublicKeyMaterial = util.concatUint8Array([
new Uint8Array([0x08,0x00,0xac,0x15,0xb3,0xd6,0xd2,0x0f,0xf0,0x7a,0xdd,0x21,0xb7,
0xbf,0x61,0xfa,0xca,0x93,0x86,0xc8,0x55,0x5a,0x4b,0xa6,0xa4,0x1a,
0x60,0xa2,0x3a,0x37,0x06,0x08,0xd8,0x15,0x8e,0x85,0x45,0xaa,0xb7,
@@ -30,8 +30,8 @@ module.exports = () => describe('API functional testing', function() {
0xee,0xc9,0xa4,0xcd,0x15,0xdc,0x1b,0x8d,0x64,0xc1,0x36,0x17,0xc4,
0x8d,0x5e,0x99,0x7a,0x5b,0x9f,0x39,0xd0,0x00,0x6e,0xf9]),
new Uint8Array([0x00,0x11,0x01,0x00,0x01])
];
const RSAsecMPIstrs = [
]);
const RSAPrivateKeyMaterial = util.concatUint8Array([
new Uint8Array([0x07,0xfe,0x23,0xff,0xce,0x45,0x6c,0x60,0x65,0x40,0x6e,0xae,0x35,
0x10,0x56,0x60,0xee,0xab,0xfa,0x10,0x42,0xba,0xc7,0x04,0xaf,0x63,
0xcd,0x3f,0x62,0xca,0x4b,0xfa,0xe1,0xa9,0x70,0xcd,0x34,0x8b,0xc8,
@@ -82,9 +82,9 @@ module.exports = () => describe('API functional testing', function() {
0x51,0xe0,0x22,0xf0,0xff,0xa7,0x42,0xd4,0xde,0x0b,0x47,0x8f,0x2b,
0xf5,0x4d,0x04,0x32,0x91,0x89,0x4b,0x0e,0x05,0x8d,0x70,0xf9,0xbb,
0xe7,0xd6,0x76,0xea,0x0e,0x1a,0x90,0x30,0xf5,0x98,0x01,0xc5,0x73])
];
]);
const DSApubMPIstrs = [
const DSAPublicKeyMaterial = util.concatUint8Array([
new Uint8Array([0x08,0x00,0xa8,0x85,0x5c,0x28,0x05,0x94,0x03,0xbe,0x07,0x6c,0x13,0x3e,0x65,
0xfb,0xb5,0xe1,0x99,0x7c,0xfa,0x84,0xe3,0xac,0x47,0xa5,0xc4,0x46,0xd8,0x5f,
0x44,0xe9,0xc1,0x6b,0x69,0xf7,0x10,0x76,0x49,0xa7,0x25,0x85,0xf4,0x1b,0xed,
@@ -142,14 +142,14 @@ module.exports = () => describe('API functional testing', function() {
0x67,0x8d,0x9d,0x14,0xb6,0x9d,0x32,0x82,0xd0,0xb5,0xc6,0x57,0xf0,0x91,0xd9,
0xc3,0x26,0xae,0x9f,0xa9,0x67,0x49,0x96,0x5c,0x07,0x3e,0x47,0x5c,0xed,0x60,
0x07,0xac,0x6a])
];
const DSAsecMPIstrs = [
]);
const DSAPrivateKeyMaterial = util.concatUint8Array([
new Uint8Array([0x01,0x00,0x9b,0x58,0xa8,0xf4,0x04,0xb1,0xd5,0x14,0x09,0xe1,0xe1,0xa1,0x8a,
0x0b,0xa3,0xc3,0xa3,0x66,0xaa,0x27,0x99,0x50,0x1c,0x4d,0xba,0x24,0xee,0xdf,
0xdf,0xb8,0x8e,0x8e])
];
]);
const ElgamalpubMPIstrs = [
const elGamalPublicKeyMaterial = util.concatUint8Array([
new Uint8Array([0x08,0x00,0xea,0xcc,0xbe,0xe2,0xe4,0x5a,0x51,0x18,0x93,0xa1,0x12,0x2f,0x00,
0x99,0x42,0xd8,0x5c,0x1c,0x2f,0xb6,0x3c,0xd9,0x94,0x61,0xb4,0x55,0x8d,0x4e,
0x73,0xe6,0x69,0xbc,0x1d,0x33,0xe3,0x2d,0x91,0x23,0x69,0x95,0x98,0xd7,0x18,
@@ -187,64 +187,37 @@ module.exports = () => describe('API functional testing', function() {
0xda,0xba,0x19,0xf3,0xcb,0x10,0xa0,0x6b,0xd0,0x2d,0xbe,0x40,0x42,0x7b,0x9b,
0x15,0xa4,0x2d,0xec,0xcf,0x09,0xd6,0xe3,0x92,0xc3,0x8d,0x65,0x6b,0x60,0x97,
0xda,0x6b,0xca])
];
]);
const ElgamalsecMPIstrs = [
const elGamalPrivateKeyMaterial = util.concatUint8Array([
new Uint8Array([0x01,0x52,0x02,0x80,0x87,0xf6,0xe4,0x49,0xd7,0x2e,0x3e,0xfe,0x60,0xb9,0xa3,
0x2a,0xf0,0x67,0x58,0xe9,0xf6,0x47,0x83,0xde,0x7e,0xfb,0xbb,0xbd,0xdf,0x48,
0x12,0x1b,0x06,0x7d,0x13,0xbc,0x3b,0x49,0xf9,0x86,0xd4,0x53,0xed,0x2d,0x68])
];
]);
const RSApubMPIs = [];
let i;
for (i = 0; i < 2; i++) {
RSApubMPIs[i] = new openpgp.MPI();
RSApubMPIs[i].read(RSApubMPIstrs[i]);
}
const algoRSA = openpgp.enums.publicKey.rsaEncryptSign;
const RSAPublicParams = crypto.parsePublicKeyParams(algoRSA, RSAPublicKeyMaterial).publicParams;
const RSAPrivateParams = crypto.parsePrivateKeyParams(algoRSA, RSAPrivateKeyMaterial).privateParams;
const RSAsecMPIs = [];
for (i = 0; i < 4; i++) {
RSAsecMPIs[i] = new openpgp.MPI();
RSAsecMPIs[i].read(RSAsecMPIstrs[i]);
}
const algoDSA = openpgp.enums.publicKey.dsa;
const DSAPublicParams = crypto.parsePublicKeyParams(algoDSA, DSAPublicKeyMaterial).publicParams;
const DSAPrivateParams = crypto.parsePrivateKeyParams(algoDSA, DSAPrivateKeyMaterial).privateParams;
const DSAsecMPIs = [];
for (i = 0; i < 1; i++) {
DSAsecMPIs[i] = new openpgp.MPI();
DSAsecMPIs[i].read(DSAsecMPIstrs[i]);
}
const DSApubMPIs = [];
for (i = 0; i < 4; i++) {
DSApubMPIs[i] = new openpgp.MPI();
DSApubMPIs[i].read(DSApubMPIstrs[i]);
}
const ElgamalsecMPIs = [];
for (i = 0; i < 1; i++) {
ElgamalsecMPIs[i] = new openpgp.MPI();
ElgamalsecMPIs[i].read(ElgamalsecMPIstrs[i]);
}
const ElgamalpubMPIs = [];
for (i = 0; i < 3; i++) {
ElgamalpubMPIs[i] = new openpgp.MPI();
ElgamalpubMPIs[i].read(ElgamalpubMPIstrs[i]);
}
const algoElGamal = openpgp.enums.publicKey.elgamal;
const elGamalPublicParams = crypto.parsePublicKeyParams(algoElGamal, elGamalPublicKeyMaterial).publicParams;
const elGamalPrivateParams = crypto.parsePrivateKeyParams(algoElGamal, elGamalPrivateKeyMaterial).privateParams;
const data = util.strToUint8Array("foobar");
describe('Sign and verify', function () {
it('RSA', async function () {
// FIXME
//Originally we passed public and secret MPI separately, now they are joined. Is this what we want to do long term?
// RSA
return crypto.signature.sign(
1, 2, RSApubMPIs.concat(RSAsecMPIs), data, await crypto.hash.digest(2, data)
1, 2, RSAPublicParams, RSAPrivateParams, data, await crypto.hash.digest(2, data)
).then(async RSAsignedData => {
const RSAsignedDataMPI = new openpgp.MPI();
RSAsignedDataMPI.read(RSAsignedData);
return crypto.signature.verify(
1, 2, [RSAsignedDataMPI], RSApubMPIs, data, await crypto.hash.digest(2, data)
1, 2, [RSAsignedDataMPI], RSAPublicParams, data, await crypto.hash.digest(2, data)
).then(success => {
return expect(success).to.be.true;
});
@@ -252,9 +225,8 @@ module.exports = () => describe('API functional testing', function() {
});
it('DSA', async function () {
// DSA
return crypto.signature.sign(
17, 2, DSApubMPIs.concat(DSAsecMPIs), data, await crypto.hash.digest(2, data)
17, 2, DSAPublicParams, DSAPrivateParams, data, await crypto.hash.digest(2, data)
).then(async DSAsignedData => {
DSAsignedData = util.uint8ArrayToStr(DSAsignedData);
const DSAmsgMPIs = [];
@@ -263,7 +235,7 @@ module.exports = () => describe('API functional testing', function() {
DSAmsgMPIs[0].read(DSAsignedData.substring(0,34));
DSAmsgMPIs[1].read(DSAsignedData.substring(34,68));
return crypto.signature.verify(
17, 2, DSAmsgMPIs, DSApubMPIs, data, await crypto.hash.digest(2, data)
17, 2, DSAmsgMPIs, DSAPublicParams, data, await crypto.hash.digest(2, data)
).then(success => {
return expect(success).to.be.true;
});
@@ -356,9 +328,9 @@ module.exports = () => describe('API functional testing', function() {
it('Asymmetric using RSA with eme_pkcs1 padding', async function () {
const symmKey = await crypto.generateSessionKey('aes256');
return crypto.publicKeyEncrypt(1, RSApubMPIs, symmKey).then(RSAEncryptedData => {
return crypto.publicKeyEncrypt(algoRSA, RSAPublicParams, symmKey).then(RSAEncryptedData => {
return crypto.publicKeyDecrypt(
1, RSApubMPIs.concat(RSAsecMPIs), RSAEncryptedData
algoRSA, RSAPublicParams, RSAPrivateParams, RSAEncryptedData
).then(data => {
expect(data).to.deep.equal(symmKey);
});
@@ -367,9 +339,9 @@ module.exports = () => describe('API functional testing', function() {
it('Asymmetric using Elgamal with eme_pkcs1 padding', async function () {
const symmKey = await crypto.generateSessionKey('aes256');
return crypto.publicKeyEncrypt(16, ElgamalpubMPIs, symmKey).then(ElgamalEncryptedData => {
return crypto.publicKeyEncrypt(algoElGamal, elGamalPublicParams, symmKey).then(ElgamalEncryptedData => {
return crypto.publicKeyDecrypt(
16, ElgamalpubMPIs.concat(ElgamalsecMPIs), ElgamalEncryptedData
algoElGamal, elGamalPublicParams, elGamalPrivateParams, ElgamalEncryptedData
).then(data => {
expect(data).to.deep.equal(symmKey);
});

View File

@@ -22,16 +22,11 @@ module.exports = () => (!native ? describe.skip : describe)('basic RSA cryptogra
it('sign and verify using generated key params', async function() {
const bits = openpgp.util.getWebCryptoAll() ? 2048 : 1024;
const keyParams = await openpgp.crypto.generateParams(openpgp.enums.publicKey.rsaSign, bits);
const { publicParams, privateParams } = await openpgp.crypto.generateParams(openpgp.enums.publicKey.rsaSign, bits);
const message = await openpgp.crypto.random.getRandomBytes(64);
const hash_algo = openpgp.enums.write(openpgp.enums.hash, 'sha256');
const hashed = await openpgp.crypto.hash.digest(hash_algo, message);
const n = keyParams[0].toUint8Array();
const e = keyParams[1].toUint8Array();
const d = keyParams[2].toUint8Array();
const p = keyParams[3].toUint8Array();
const q = keyParams[4].toUint8Array();
const u = keyParams[5].toUint8Array();
const { n, e, d, p, q, u } = { ...publicParams, ...privateParams };
const signature = await openpgp.crypto.publicKey.rsa.sign(hash_algo, message, n, e, d, p, q, u, hashed);
expect(signature).to.exist;
const verify = await openpgp.crypto.publicKey.rsa.verify(hash_algo, message, signature, n, e, hashed);
@@ -40,13 +35,8 @@ module.exports = () => (!native ? describe.skip : describe)('basic RSA cryptogra
it('encrypt and decrypt using generated key params', async function() {
const bits = openpgp.util.getWebCryptoAll() ? 2048 : 1024;
const keyParams = await openpgp.crypto.generateParams(openpgp.enums.publicKey.rsaSign, bits);
const n = keyParams[0].toUint8Array();
const e = keyParams[1].toUint8Array();
const d = keyParams[2].toUint8Array();
const p = keyParams[3].toUint8Array();
const q = keyParams[4].toUint8Array();
const u = keyParams[5].toUint8Array();
const { publicParams, privateParams } = await openpgp.crypto.generateParams(openpgp.enums.publicKey.rsaSign, bits);
const { n, e, d, p, q, u } = { ...publicParams, ...privateParams };
const message = await openpgp.crypto.generateSessionKey('aes256');
const encrypted = await openpgp.crypto.publicKey.rsa.encrypt(message, n, e);
const result = new openpgp.MPI(encrypted);
@@ -59,13 +49,8 @@ module.exports = () => (!native ? describe.skip : describe)('basic RSA cryptogra
this.skip();
}
const bits = 1024;
const keyParams = await openpgp.crypto.generateParams(openpgp.enums.publicKey.rsaSign, bits);
const n = keyParams[0].toUint8Array();
const e = keyParams[1].toUint8Array();
const d = keyParams[2].toUint8Array();
const p = keyParams[3].toUint8Array();
const q = keyParams[4].toUint8Array();
const u = keyParams[5].toUint8Array();
const { publicParams, privateParams } = await openpgp.crypto.generateParams(openpgp.enums.publicKey.rsaSign, bits);
const { n, e, d, p, q, u } = { ...publicParams, ...privateParams };
const message = await openpgp.crypto.generateSessionKey('aes256');
const encryptedBn = await openpgp.crypto.publicKey.rsa.bnEncrypt(message, n, e);
const decrypted1 = await openpgp.crypto.publicKey.rsa.nodeDecrypt(encryptedBn, n, e, d, p, q, u);
@@ -80,13 +65,8 @@ module.exports = () => (!native ? describe.skip : describe)('basic RSA cryptogra
this.skip();
}
const bits = openpgp.util.getWebCrypto() ? 2048 : 1024;
const keyParams = await openpgp.crypto.generateParams(openpgp.enums.publicKey.rsaSign, bits);
const n = keyParams[0].toUint8Array();
const e = keyParams[1].toUint8Array();
const d = keyParams[2].toUint8Array();
const p = keyParams[3].toUint8Array();
const q = keyParams[4].toUint8Array();
const u = keyParams[5].toUint8Array();
const { publicParams, privateParams } = await openpgp.crypto.generateParams(openpgp.enums.publicKey.rsaSign, bits);
const { n, e, d, p, q, u } = { ...publicParams, ...privateParams };
const message = await openpgp.crypto.random.getRandomBytes(64);
const hashName = 'sha256';
const hash_algo = openpgp.enums.write(openpgp.enums.hash, hashName);
@@ -107,13 +87,8 @@ module.exports = () => (!native ? describe.skip : describe)('basic RSA cryptogra
this.skip();
}
const bits = openpgp.util.getWebCrypto() ? 2048 : 1024;
const keyParams = await openpgp.crypto.generateParams(openpgp.enums.publicKey.rsaSign, bits);
const n = keyParams[0].toUint8Array();
const e = keyParams[1].toUint8Array();
const d = keyParams[2].toUint8Array();
const p = keyParams[3].toUint8Array();
const q = keyParams[4].toUint8Array();
const u = keyParams[5].toUint8Array();
const { publicParams, privateParams } = await openpgp.crypto.generateParams(openpgp.enums.publicKey.rsaSign, bits);
const { n, e, d, p, q, u } = { ...publicParams, ...privateParams };
const message = await openpgp.crypto.random.getRandomBytes(64);
const hashName = 'sha256';
const hash_algo = openpgp.enums.write(openpgp.enums.hash, hashName);
@@ -137,13 +112,8 @@ module.exports = () => (!native ? describe.skip : describe)('basic RSA cryptogra
this.skip();
}
const bits = 1024;
const keyParams = await openpgp.crypto.generateParams(openpgp.enums.publicKey.rsaSign, bits);
const n = keyParams[0].toUint8Array();
const e = keyParams[1].toUint8Array();
const d = keyParams[2].toUint8Array();
const p = keyParams[3].toUint8Array();
const q = keyParams[4].toUint8Array();
const u = keyParams[5].toUint8Array();
const { publicParams, privateParams } = await openpgp.crypto.generateParams(openpgp.enums.publicKey.rsaSign, bits);
const { n, e, d, p, q, u } = { ...publicParams, ...privateParams };
const message = await openpgp.crypto.random.getRandomBytes(64);
const hashName = 'sha256';
const hash_algo = openpgp.enums.write(openpgp.enums.hash, hashName);
@@ -158,13 +128,8 @@ module.exports = () => (!native ? describe.skip : describe)('basic RSA cryptogra
this.skip();
}
const bits = openpgp.util.getWebCrypto() ? 2048 : 1024;
const keyParams = await openpgp.crypto.generateParams(openpgp.enums.publicKey.rsaSign, bits);
const n = keyParams[0].toUint8Array();
const e = keyParams[1].toUint8Array();
const d = keyParams[2].toUint8Array();
const p = keyParams[3].toUint8Array();
const q = keyParams[4].toUint8Array();
const u = keyParams[5].toUint8Array();
const { publicParams, privateParams } = await openpgp.crypto.generateParams(openpgp.enums.publicKey.rsaSign, bits);
const { n, e, d, p, q, u } = { ...publicParams, ...privateParams };
const message = await openpgp.crypto.random.getRandomBytes(64);
const hashName = 'sha256';
const hash_algo = openpgp.enums.write(openpgp.enums.hash, hashName);

View File

@@ -93,12 +93,12 @@ module.exports = () => {
it('detect invalid edDSA Q', async function() {
const eddsaKeyPacket = cloneKeyPacket(eddsaKey);
const Q = eddsaKeyPacket.params[1];
Q.data[0]++;
const Q = eddsaKeyPacket.publicParams.Q;
Q[0]++;
await expect(eddsaKeyPacket.validate()).to.be.rejectedWith('Key is invalid');
const infQ = new Uint8Array(Q.data.length);
eddsaKeyPacket.params[1] = new openpgp.MPI(infQ);
const infQ = new Uint8Array(Q.length);
eddsaKeyPacket.publicParams.Q = infQ;
await expect(eddsaKeyPacket.validate()).to.be.rejectedWith('Key is invalid');
});
});
@@ -114,86 +114,78 @@ module.exports = () => {
});
it('EdDSA params are not valid for ECDH', async function() {
const oid = eddsaKey.keyPacket.params[0];
const Q = eddsaKey.keyPacket.params[1];
const seed = eddsaKey.keyPacket.params[2];
const { oid, Q } = eddsaKey.keyPacket.publicParams;
const { seed } = eddsaKey.keyPacket.privateParams;
const ecdhKeyPacket = cloneKeyPacket(ecdhKey);
const ecdhOID = ecdhKeyPacket.params[0];
const ecdhOID = ecdhKeyPacket.publicParams.oid;
ecdhKeyPacket.params[0] = oid;
ecdhKeyPacket.publicParams.oid = oid;
await expect(ecdhKeyPacket.validate()).to.be.rejectedWith('Key is invalid');
ecdhKeyPacket.params[0] = ecdhOID;
ecdhKeyPacket.params[1] = Q;
ecdhKeyPacket.params[3] = seed;
ecdhKeyPacket.publicParams.oid = ecdhOID;
ecdhKeyPacket.publicParams.Q = Q;
ecdhKeyPacket.privateParams.d = seed;
await expect(ecdhKeyPacket.validate()).to.be.rejectedWith('Key is invalid');
});
it('EdDSA params are not valid for EcDSA', async function() {
const oid = eddsaKey.keyPacket.params[0];
const Q = eddsaKey.keyPacket.params[1];
const seed = eddsaKey.keyPacket.params[2];
const { oid, Q } = eddsaKey.keyPacket.publicParams;
const { seed } = eddsaKey.keyPacket.privateParams;
const ecdsaKeyPacket = cloneKeyPacket(ecdsaKey);
const ecdsaOID = ecdsaKeyPacket.params[0];
ecdsaKeyPacket.params[0] = oid;
const ecdsaOID = ecdsaKeyPacket.publicParams.oid;
ecdsaKeyPacket.publicParams.oid = oid;
await expect(ecdsaKeyPacket.validate()).to.be.rejectedWith('Key is invalid');
ecdsaKeyPacket.params[0] = ecdsaOID;
ecdsaKeyPacket.params[1] = Q;
ecdsaKeyPacket.params[2] = seed;
ecdsaKeyPacket.publicParams.oid = ecdsaOID;
ecdsaKeyPacket.publicParams.Q = Q;
ecdsaKeyPacket.privateParams.d = seed;
await expect(ecdsaKeyPacket.validate()).to.be.rejectedWith('Key is invalid');
});
it('ECDH x25519 params are not valid for EcDSA', async function() {
const ecdh25519KeyPacket = ecdhKey.keyPacket;
const oid = ecdh25519KeyPacket.params[0];
const Q = ecdh25519KeyPacket.params[1];
const d = ecdh25519KeyPacket.params[3];
const { oid, Q } = ecdhKey.keyPacket.publicParams;
const { d } = ecdhKey.keyPacket.privateParams;
const ecdsaKeyPacket = cloneKeyPacket(ecdsaKey);
ecdsaKeyPacket.params[0] = oid;
ecdsaKeyPacket.params[1] = Q;
ecdsaKeyPacket.params[2] = d;
ecdsaKeyPacket.publicParams.oid = oid;
ecdsaKeyPacket.publicParams.Q = Q;
ecdsaKeyPacket.privateParams.d = d;
await expect(ecdsaKeyPacket.validate()).to.be.rejectedWith('Key is invalid');
});
it('EcDSA params are not valid for EdDSA', async function() {
const oid = ecdsaKey.keyPacket.params[0];
const Q = ecdsaKey.keyPacket.params[1];
const d = ecdsaKey.keyPacket.params[2];
const { oid, Q } = ecdsaKey.keyPacket.publicParams;
const { d } = ecdsaKey.keyPacket.privateParams;
const eddsaKeyPacket = cloneKeyPacket(eddsaKey);
const eddsaOID = eddsaKeyPacket.params[0];
eddsaKeyPacket.params[0] = oid;
const eddsaOID = eddsaKeyPacket.publicParams.oid;
eddsaKeyPacket.publicParams.oid = oid;
await expect(eddsaKeyPacket.validate()).to.be.rejectedWith('Key is invalid');
eddsaKeyPacket.params[0] = eddsaOID;
eddsaKeyPacket.params[1] = Q;
eddsaKeyPacket.params[2] = d;
eddsaKeyPacket.publicParams.oid = eddsaOID;
eddsaKeyPacket.publicParams.Q = Q;
eddsaKeyPacket.privateParams.seed = d;
await expect(eddsaKeyPacket.validate()).to.be.rejected;
});
it('ECDH x25519 params are not valid for EdDSA', async function() {
const ecdh25519KeyPacket = ecdhKey.keyPacket;
const oid = ecdh25519KeyPacket.params[0];
const Q = ecdh25519KeyPacket.params[1];
const d = ecdh25519KeyPacket.params[3];
const { oid, Q } = ecdhKey.keyPacket.publicParams;
const { d } = ecdhKey.keyPacket.privateParams;
const eddsaKeyPacket = cloneKeyPacket(eddsaKey);
const eddsaOID = eddsaKeyPacket.params[0];
eddsaKeyPacket.params[0] = oid;
const eddsaOID = eddsaKeyPacket.publicParams.oid;
eddsaKeyPacket.publicParams.oid = oid;
await expect(eddsaKeyPacket.validate()).to.be.rejectedWith('Key is invalid');
eddsaKeyPacket.params[0] = eddsaOID;
eddsaKeyPacket.params[1] = Q;
eddsaKeyPacket.params[2] = d;
eddsaKeyPacket.publicParams.oid = eddsaOID;
eddsaKeyPacket.publicParams.Q = Q;
eddsaKeyPacket.privateParams.seed = d;
await expect(eddsaKeyPacket.validate()).to.be.rejectedWith('Key is invalid');
});
});
const curves = ['curve25519', 'p256', 'p384', 'p521', 'secp256k1', 'brainpoolP256r1', 'brainpoolP384r1', 'brainpoolP512r1'];
curves.forEach(curve => {
describe(`ECC ${curve} parameter validation`, () => {
@@ -216,12 +208,12 @@ module.exports = () => {
it('detect invalid EcDSA Q', async function() {
const keyPacket = cloneKeyPacket(ecdsaKey);
const Q = keyPacket.params[1];
Q.data[0]++;
const Q = keyPacket.publicParams.Q;
Q[0]++;
await expect(keyPacket.validate()).to.be.rejectedWith('Key is invalid');
const infQ = new Uint8Array(Q.data.length);
keyPacket.params[1] = new openpgp.MPI(infQ);
const infQ = new Uint8Array(Q.length);
keyPacket.publicParams.Q = infQ;
await expect(keyPacket.validate()).to.be.rejectedWith('Key is invalid');
});
}
@@ -232,12 +224,12 @@ module.exports = () => {
it('detect invalid ECDH Q', async function() {
const keyPacket = cloneKeyPacket(ecdhKey);
const Q = keyPacket.params[1];
Q.data[16]++;
const Q = keyPacket.publicParams.Q;
Q[16]++;
await expect(keyPacket.validate()).to.be.rejectedWith('Key is invalid');
const infQ = new Uint8Array(Q.data.length);
keyPacket.params[1] = new openpgp.MPI(infQ);
const infQ = new Uint8Array(Q.length);
keyPacket.publicParams.Q = infQ;
await expect(keyPacket.validate()).to.be.rejectedWith('Key is invalid');
});
});
@@ -255,15 +247,15 @@ module.exports = () => {
it('detect invalid RSA n', async function() {
const keyPacket = cloneKeyPacket(rsaKey);
const n = keyPacket.params[0];
n.data[0]++;
const n = keyPacket.publicParams.n;
n[0]++;
await expect(keyPacket.validate()).to.be.rejectedWith('Key is invalid');
});
it('detect invalid RSA e', async function() {
const keyPacket = cloneKeyPacket(rsaKey);
const e = keyPacket.params[1];
e.data[0]++;
const e = keyPacket.publicParams.e;
e[0]++;
await expect(keyPacket.validate()).to.be.rejectedWith('Key is invalid');
});
});
@@ -280,28 +272,27 @@ module.exports = () => {
it('detect invalid DSA p', async function() {
const keyPacket = cloneKeyPacket(dsaKey);
const p = keyPacket.params[0];
p.data[0]++;
const p = keyPacket.publicParams.p;
p[0]++;
await expect(keyPacket.validate()).to.be.rejectedWith('Key is invalid');
});
it('detect invalid DSA y', async function() {
const keyPacket = cloneKeyPacket(dsaKey);
const y = keyPacket.params[3];
const y = keyPacket.publicParams.y;
y.data[0]++;
y[0]++;
await expect(keyPacket.validate()).to.be.rejectedWith('Key is invalid');
});
it('detect invalid DSA g', async function() {
const keyPacket = cloneKeyPacket(dsaKey);
const g = keyPacket.params[2];
const g = keyPacket.publicParams.g;
g.data[0]++;
g[0]++;
await expect(keyPacket.validate()).to.be.rejectedWith('Key is invalid');
const gOne = new openpgp.MPI(new Uint8Array([1]));
keyPacket.params[2] = gOne;
keyPacket.publicParams.g = new Uint8Array([1]);
await expect(keyPacket.validate()).to.be.rejectedWith('Key is invalid');
});
});
@@ -318,40 +309,39 @@ module.exports = () => {
it('detect invalid p', async function() {
const keyPacket = cloneKeyPacket(egKey);
const p = keyPacket.params[0];
p.data[0]++;
const p = keyPacket.publicParams.p;
p[0]++;
await expect(keyPacket.validate()).to.be.rejectedWith('Key is invalid');
});
it('detect invalid y', async function() {
const keyPacket = cloneKeyPacket(egKey);
const y = keyPacket.params[2];
y.data[0]++;
const y = keyPacket.publicParams.y;
y[0]++;
await expect(keyPacket.validate()).to.be.rejectedWith('Key is invalid');
});
it('detect invalid g', async function() {
const keyPacket = cloneKeyPacket(egKey);
const g = keyPacket.params[1];
const g = keyPacket.publicParams.g;
g.data[0]++;
g[0]++;
await expect(keyPacket.validate()).to.be.rejectedWith('Key is invalid');
const gOne = new openpgp.MPI(new Uint8Array([1]));
keyPacket.params[1] = gOne;
keyPacket.publicParams.g = new Uint8Array([1]);
await expect(keyPacket.validate()).to.be.rejectedWith('Key is invalid');
});
it('detect g with small order', async function() {
const keyPacket = cloneKeyPacket(egKey);
const p = keyPacket.params[0].toUint8Array();
const g = keyPacket.params[1].toUint8Array();
const p = keyPacket.publicParams.p;
const g = keyPacket.publicParams.g;
const pBN = new BN(p);
const gModP = new BN(g).toRed(new BN.red(pBN));
// g**(p-1)/2 has order 2
const gOrd2 = gModP.redPow(pBN.subn(1).shrn(1));
keyPacket.params[1] = new openpgp.MPI(gOrd2.toArrayLike(Uint8Array, 'be'));
keyPacket.publicParams.g = gOrd2.toArrayLike(Uint8Array, 'be');
await expect(keyPacket.validate()).to.be.rejectedWith('Key is invalid');
});
});