Fix ElGamal param range and PKCS1 decoding (#1169)
* Fix ElGamal sampling range * Stricter PKCS1 decoding
This commit is contained in:
parent
d5373ef361
commit
38ec5314d4
|
@ -133,8 +133,10 @@ export default {
|
||||||
const c2 = data_params[1].toBN();
|
const c2 = data_params[1].toBN();
|
||||||
const p = key_params[0].toBN();
|
const p = key_params[0].toBN();
|
||||||
const x = key_params[3].toBN();
|
const x = key_params[3].toBN();
|
||||||
const result = new type_mpi(await publicKey.elgamal.decrypt(c1, c2, p, x));
|
const result = new type_mpi(await publicKey.elgamal.decrypt(c1, c2, p, x)); // MPI and BN.js discard any leading zeros
|
||||||
return pkcs1.eme.decode(result.toString());
|
return pkcs1.eme.decode(
|
||||||
|
util.Uint8Array_to_str(result.toUint8Array('be', p.byteLength())) // re-introduce leading zeros
|
||||||
|
);
|
||||||
}
|
}
|
||||||
case enums.publicKey.ecdh: {
|
case enums.publicKey.ecdh: {
|
||||||
const oid = key_params[0];
|
const oid = key_params[0];
|
||||||
|
|
|
@ -106,10 +106,6 @@ eme.encode = async function(M, k) {
|
||||||
* @returns {String} message, an octet string
|
* @returns {String} message, an octet string
|
||||||
*/
|
*/
|
||||||
eme.decode = function(EM) {
|
eme.decode = function(EM) {
|
||||||
// leading zeros truncated by bn.js
|
|
||||||
if (EM.charCodeAt(0) !== 0) {
|
|
||||||
EM = String.fromCharCode(0) + EM;
|
|
||||||
}
|
|
||||||
const firstOct = EM.charCodeAt(0);
|
const firstOct = EM.charCodeAt(0);
|
||||||
const secondOct = EM.charCodeAt(1);
|
const secondOct = EM.charCodeAt(1);
|
||||||
let i = 2;
|
let i = 2;
|
||||||
|
|
|
@ -25,8 +25,6 @@
|
||||||
import BN from 'bn.js';
|
import BN from 'bn.js';
|
||||||
import random from '../random';
|
import random from '../random';
|
||||||
|
|
||||||
const zero = new BN(0);
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
/**
|
/**
|
||||||
* ElGamal Encryption function
|
* ElGamal Encryption function
|
||||||
|
@ -42,8 +40,9 @@ export default {
|
||||||
const mred = m.toRed(redp);
|
const mred = m.toRed(redp);
|
||||||
const gred = g.toRed(redp);
|
const gred = g.toRed(redp);
|
||||||
const yred = y.toRed(redp);
|
const yred = y.toRed(redp);
|
||||||
// See Section 11.5 here: https://crypto.stanford.edu/~dabo/cryptobook/BonehShoup_0_4.pdf
|
// OpenPGP uses a "special" version of ElGamal where g is generator of the full group Z/pZ*
|
||||||
const k = await random.getRandomBN(zero, p); // returns in [0, p-1]
|
// hence g has order p-1, and to avoid that k = 0 mod p-1, we need to pick k in [1, p-2]
|
||||||
|
const k = await random.getRandomBN(new BN(1), p.subn(1));
|
||||||
return {
|
return {
|
||||||
c1: gred.redPow(k).fromRed(),
|
c1: gred.redPow(k).fromRed(),
|
||||||
c2: yred.redPow(k).redMul(mred).fromRed()
|
c2: yred.redPow(k).redMul(mred).fromRed()
|
||||||
|
|
|
@ -501,7 +501,11 @@ export default {
|
||||||
});
|
});
|
||||||
key = { key: pem, padding: nodeCrypto.constants.RSA_PKCS1_PADDING };
|
key = { key: pem, padding: nodeCrypto.constants.RSA_PKCS1_PADDING };
|
||||||
}
|
}
|
||||||
return util.Uint8Array_to_str(nodeCrypto.privateDecrypt(key, data));
|
try {
|
||||||
|
return util.Uint8Array_to_str(nodeCrypto.privateDecrypt(key, data));
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error('Decryption error');
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
bnDecrypt: async function(data, n, e, d, p, q, u) {
|
bnDecrypt: async function(data, n, e, d, p, q, u) {
|
||||||
|
@ -540,7 +544,8 @@ export default {
|
||||||
result = result.redMul(unblinder);
|
result = result.redMul(unblinder);
|
||||||
}
|
}
|
||||||
|
|
||||||
return pkcs1.eme.decode((new type_mpi(result)).toString());
|
result = new type_mpi(result).toUint8Array('be', n.byteLength()); // preserve leading zeros
|
||||||
|
return pkcs1.eme.decode(util.Uint8Array_to_str(result));
|
||||||
},
|
},
|
||||||
|
|
||||||
prime: prime
|
prime: prime
|
||||||
|
|
|
@ -374,6 +374,69 @@ EQr2Mx42THr260IFYp5E/rIA
|
||||||
=oA0b
|
=oA0b
|
||||||
-----END PGP PRIVATE KEY BLOCK-----`;
|
-----END PGP PRIVATE KEY BLOCK-----`;
|
||||||
|
|
||||||
|
const rsaPrivateKeyPKCS1 = `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||||
|
|
||||||
|
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
|
||||||
|
=dSNv
|
||||||
|
-----END PGP PRIVATE KEY BLOCK-----
|
||||||
|
`;
|
||||||
|
|
||||||
|
|
||||||
function withCompression(tests) {
|
function withCompression(tests) {
|
||||||
const compressionTypes = Object.keys(openpgp.enums.compression).map(k => openpgp.enums.compression[k]);
|
const compressionTypes = Object.keys(openpgp.enums.compression).map(k => openpgp.enums.compression[k]);
|
||||||
|
|
||||||
|
@ -2464,6 +2527,52 @@ describe('OpenPGP.js public api tests', function() {
|
||||||
await expect(openpgp.decrypt(decOpt)).to.be.rejectedWith(/Session key decryption failed/);
|
await expect(openpgp.decrypt(decOpt)).to.be.rejectedWith(/Session key decryption failed/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('RSA decryption with PKCS1 padding of wrong length should fail', async function() {
|
||||||
|
const key = (await openpgp.key.readArmored(rsaPrivateKeyPKCS1)).keys[0];
|
||||||
|
// the paddings of these messages are prefixed by 0x02 and 0x000002 instead of 0x0002
|
||||||
|
// the code should discriminate between these cases by checking the length of the padded plaintext
|
||||||
|
const padding02 = `-----BEGIN PGP MESSAGE-----
|
||||||
|
Version: OpenPGP.js VERSION
|
||||||
|
Comment: https://openpgpjs.org
|
||||||
|
|
||||||
|
wcBMAxbpoSTRSSl3AQf/fepDhqeam4Ecy8GUFChc47U3hbkdgINobI9TORAf
|
||||||
|
eGFZVcyTQKVIt7fB8bwQwjxRmU98xCjF7VkLhPQJkzKlkT9cIDBKswU+d3fw
|
||||||
|
lHAVYo77yUkFkVLXrQTZj/OjsA12V7lfRagO375XB3EpJUHVPvYQFFr3aSlo
|
||||||
|
FbsCrpZoS6FXxRYVjGpIeMjam3a7qDavQpKhjOQ+Sfm0tk2JZkQwpFom6x7c
|
||||||
|
9TEn3YSo6+I0ztjiuTBZDyYr8zocHW8imFzZRlcNuuuukesyFzFgHx46eVpO
|
||||||
|
6PVjmiN50agZvsV9rgPyyH84nb3zYJ63shnrQWubTOVH4daGbe8uHi+ZM3UU
|
||||||
|
J9I8AcH94nE77JUtCm7s1kOlo0EIshZsAqJwGveDGdAuabfViVwVxG4I24M6
|
||||||
|
8sqJYJd9FpNjSbYlrLT0R9zy
|
||||||
|
=+n/4
|
||||||
|
-----END PGP MESSAGE-----`;
|
||||||
|
const padding000002 = `-----BEGIN PGP MESSAGE-----
|
||||||
|
Version: OpenPGP.js VERSION
|
||||||
|
Comment: https://openpgpjs.org
|
||||||
|
|
||||||
|
wcBMAxbpoSTRSSl3AQf/fepDhqeam4Ecy8GUFChc47U3hbkdgINobI9TORAf
|
||||||
|
eGFZVcyTQKVIt7fB8bwQwjxRmU98xCjF7VkLhPQJkzKlkT9cIDBKswU+d3fw
|
||||||
|
lHAVYo77yUkFkVLXrQTZj/OjsA12V7lfRagO375XB3EpJUHVPvYQFFr3aSlo
|
||||||
|
FbsCrpZoS6FXxRYVjGpIeMjam3a7qDavQpKhjOQ+Sfm0tk2JZkQwpFom6x7c
|
||||||
|
9TEn3YSo6+I0ztjiuTBZDyYr8zocHW8imFzZRlcNuuuukesyFzFgHx46eVpO
|
||||||
|
6PVjmiN50agZvsV9rgPyyH84nb3zYJ63shnrQWubTOVH4daGbe8uHi+ZM3UU
|
||||||
|
J9I8AcH94nE77JUtCm7s1kOlo0EIshZsAqJwGveDGdAuabfViVwVxG4I24M6
|
||||||
|
8sqJYJd9FpNjSbYlrLT0R9zy
|
||||||
|
=+n/4
|
||||||
|
-----END PGP MESSAGE-----`;
|
||||||
|
|
||||||
|
const decOpt02 = {
|
||||||
|
message: await openpgp.message.readArmored(padding02),
|
||||||
|
privateKeys: key
|
||||||
|
};
|
||||||
|
await expect(openpgp.decrypt(decOpt02)).to.be.rejectedWith(/Decryption error/);
|
||||||
|
|
||||||
|
const decOpt000002 = {
|
||||||
|
message: await openpgp.message.readArmored(padding000002),
|
||||||
|
privateKeys: key
|
||||||
|
};
|
||||||
|
await expect(openpgp.decrypt(decOpt000002)).to.be.rejectedWith(/Decryption error/);
|
||||||
|
});
|
||||||
|
|
||||||
it('should decrypt with two passwords message which GPG fails on', async function() {
|
it('should decrypt with two passwords message which GPG fails on', async function() {
|
||||||
const decOpt = {
|
const decOpt = {
|
||||||
message: await openpgp.message.readArmored(twoPasswordGPGFail),
|
message: await openpgp.message.readArmored(twoPasswordGPGFail),
|
||||||
|
|
Loading…
Reference in New Issue
Block a user