mirror of
https://github.com/openpgpjs/openpgpjs.git
synced 2026-03-18 14:19:15 +00:00
Add config parameter to top-level functions (#1241)
Refactor functions to take the configuration as a parameter.
This allows setting a config option for a single function call, whereas
setting `openpgp.config` could lead to concurrency-related issues when
multiple async function calls are made at the same time.
`openpgp.config` is used as default for unset config values in top-level
functions.
`openpgp.config` is used as default config object in low-level functions
(i.e., when calling a low-level function, it may be required to pass
`{ ...openpgp.config, modifiedConfig: modifiedValue }`).
Also,
- remove `config.rsaBlinding`: blinding is now always applied to RSA decryption
- remove `config.debug`: debugging mode can be enabled by setting
`process.env.NODE_ENV = 'development'`
- remove `config.useNative`: native crypto is always used when available
This commit is contained in:
@@ -242,33 +242,11 @@ module.exports = () => describe('API functional testing', function() {
|
||||
await Promise.all(symmAlgos.map(async function(algo) {
|
||||
const symmKey = await crypto.generateSessionKey(algo);
|
||||
const IV = new Uint8Array(crypto.cipher[algo].blockSize);
|
||||
const symmencData = await crypto.cfb.encrypt(algo, symmKey, util.strToUint8Array(plaintext), IV);
|
||||
const symmencData = await crypto.cfb.encrypt(algo, symmKey, util.strToUint8Array(plaintext), IV, openpgp.config);
|
||||
const text = util.uint8ArrayToStr(await crypto.cfb.decrypt(algo, symmKey, symmencData, new Uint8Array(crypto.cipher[algo].blockSize)));
|
||||
expect(text).to.equal(plaintext);
|
||||
}));
|
||||
}
|
||||
|
||||
function testAESGCM(plaintext, nativeDecrypt) {
|
||||
symmAlgos.forEach(function(algo) {
|
||||
if (algo.substr(0,3) === 'aes') {
|
||||
it(algo, async function() {
|
||||
const key = await crypto.generateSessionKey(algo);
|
||||
const iv = await crypto.random.getRandomBytes(crypto.gcm.ivLength);
|
||||
let modeInstance = await crypto.gcm(algo, key);
|
||||
|
||||
const ciphertext = await modeInstance.encrypt(util.strToUint8Array(plaintext), iv);
|
||||
|
||||
openpgp.config.useNative = nativeDecrypt;
|
||||
modeInstance = await crypto.gcm(algo, key);
|
||||
|
||||
const decrypted = await modeInstance.decrypt(util.strToUint8Array(util.uint8ArrayToStr(ciphertext)), iv);
|
||||
const decryptedStr = util.uint8ArrayToStr(decrypted);
|
||||
expect(decryptedStr).to.equal(plaintext);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
it("Symmetric with OpenPGP CFB", async function () {
|
||||
await testCFB("hello");
|
||||
await testCFB("1234567");
|
||||
@@ -276,45 +254,6 @@ module.exports = () => describe('API functional testing', function() {
|
||||
await testCFB("12345678901234567890123456789012345678901234567890");
|
||||
});
|
||||
|
||||
describe('Symmetric AES-GCM (native)', function() {
|
||||
let useNativeVal;
|
||||
beforeEach(function() {
|
||||
useNativeVal = openpgp.config.useNative;
|
||||
openpgp.config.useNative = true;
|
||||
});
|
||||
afterEach(function() {
|
||||
openpgp.config.useNative = useNativeVal;
|
||||
});
|
||||
|
||||
testAESGCM("12345678901234567890123456789012345678901234567890", true);
|
||||
});
|
||||
|
||||
describe('Symmetric AES-GCM (asm.js fallback)', function() {
|
||||
let useNativeVal;
|
||||
beforeEach(function() {
|
||||
useNativeVal = openpgp.config.useNative;
|
||||
openpgp.config.useNative = false;
|
||||
});
|
||||
afterEach(function() {
|
||||
openpgp.config.useNative = useNativeVal;
|
||||
});
|
||||
|
||||
testAESGCM("12345678901234567890123456789012345678901234567890", false);
|
||||
});
|
||||
|
||||
describe('Symmetric AES-GCM (native encrypt, asm.js decrypt)', function() {
|
||||
let useNativeVal;
|
||||
beforeEach(function() {
|
||||
useNativeVal = openpgp.config.useNative;
|
||||
openpgp.config.useNative = true;
|
||||
});
|
||||
afterEach(function() {
|
||||
openpgp.config.useNative = useNativeVal;
|
||||
});
|
||||
|
||||
testAESGCM("12345678901234567890123456789012345678901234567890", false);
|
||||
});
|
||||
|
||||
it('Asymmetric using RSA with eme_pkcs1 padding', async function () {
|
||||
const symmKey = await crypto.generateSessionKey('aes256');
|
||||
return crypto.publicKeyEncrypt(algoRSA, RSAPublicParams, symmKey).then(RSAEncryptedData => {
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
// Adapted from https://github.com/artjomb/cryptojs-extension/blob/8c61d159/test/eax.js
|
||||
|
||||
const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../..');
|
||||
const EAX = require('../../src/crypto/eax');
|
||||
const util = require('../../src/util');
|
||||
|
||||
const sandbox = require('sinon/lib/sinon/sandbox');
|
||||
const chai = require('chai');
|
||||
chai.use(require('chai-as-promised'));
|
||||
|
||||
@@ -125,30 +125,45 @@ function testAESEAX() {
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = () => {
|
||||
module.exports = () => describe('Symmetric AES-EAX', function() {
|
||||
let sinonSandbox;
|
||||
let getWebCryptoStub;
|
||||
let getNodeCryptoStub;
|
||||
|
||||
const disableNative = () => {
|
||||
enableNative();
|
||||
// stubbed functions return undefined
|
||||
getWebCryptoStub = sinonSandbox.stub(util, "getWebCrypto");
|
||||
getNodeCryptoStub = sinonSandbox.stub(util, "getNodeCrypto");
|
||||
};
|
||||
const enableNative = () => {
|
||||
getWebCryptoStub && getWebCryptoStub.restore();
|
||||
getNodeCryptoStub && getNodeCryptoStub.restore();
|
||||
};
|
||||
|
||||
describe('Symmetric AES-EAX (native)', function() {
|
||||
let useNativeVal;
|
||||
beforeEach(function() {
|
||||
useNativeVal = openpgp.config.useNative;
|
||||
openpgp.config.useNative = true;
|
||||
beforeEach(function () {
|
||||
sinonSandbox = sandbox.create();
|
||||
enableNative();
|
||||
});
|
||||
afterEach(function() {
|
||||
openpgp.config.useNative = useNativeVal;
|
||||
|
||||
afterEach(function () {
|
||||
sinonSandbox.restore();
|
||||
});
|
||||
|
||||
testAESEAX();
|
||||
});
|
||||
|
||||
describe('Symmetric AES-EAX (asm.js fallback)', function() {
|
||||
let useNativeVal;
|
||||
beforeEach(function() {
|
||||
useNativeVal = openpgp.config.useNative;
|
||||
openpgp.config.useNative = false;
|
||||
beforeEach(function () {
|
||||
sinonSandbox = sandbox.create();
|
||||
disableNative();
|
||||
});
|
||||
afterEach(function() {
|
||||
openpgp.config.useNative = useNativeVal;
|
||||
|
||||
afterEach(function () {
|
||||
sinonSandbox.restore();
|
||||
});
|
||||
|
||||
testAESEAX();
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
@@ -4,6 +4,7 @@ const KDFParams = require('../../src/type/kdf_params');
|
||||
const elliptic_curves = require('../../src/crypto/public_key/elliptic');
|
||||
const util = require('../../src/util');
|
||||
|
||||
const sandbox = require('sinon/lib/sinon/sandbox');
|
||||
const chai = require('chai');
|
||||
const elliptic_data = require('./elliptic_data');
|
||||
|
||||
@@ -133,133 +134,111 @@ module.exports = () => describe('ECDH key exchange @lightweight', function () {
|
||||
]);
|
||||
|
||||
describe('ECDHE key generation', function () {
|
||||
const ecdh = elliptic_curves.ecdh;
|
||||
|
||||
it('Invalid curve', async function () {
|
||||
if (!openpgp.config.useIndutnyElliptic && !util.getNodeCrypto()) {
|
||||
this.skip();
|
||||
}
|
||||
const { key: publicKey } = await openpgp.generateKey({ curve: "secp256k1", userIds: [{ name: 'Test' }] });
|
||||
publicKey.subKeys[0].keyPacket.publicParams.Q = Q1;
|
||||
publicKey.subKeys[0].keyPacket.fingerprint = fingerprint1;
|
||||
await expect(
|
||||
openpgp.encrypt({ publicKeys: [publicKey], message: openpgp.Message.fromText('test') })
|
||||
const curve = new elliptic_curves.Curve('secp256k1');
|
||||
const oid = new OID(curve.oid);
|
||||
const kdfParams = new KDFParams({ hash: curve.hash, cipher: curve.cipher });
|
||||
const data = util.strToUint8Array('test');
|
||||
expect(
|
||||
ecdh.encrypt(oid, kdfParams, data, Q1, fingerprint1)
|
||||
).to.be.rejectedWith(Error, /Public key is not valid for specified curve|Failed to translate Buffer to a EC_POINT|Unknown point format/);
|
||||
});
|
||||
it('Invalid public part of ephemeral key and private key', async function () {
|
||||
const { key: publicKey } = await openpgp.generateKey({ curve: "curve25519", userIds: [{ name: 'Test' }] });
|
||||
publicKey.subKeys[0].keyPacket.publicParams.Q = Q1;
|
||||
publicKey.subKeys[0].keyPacket.fingerprint = fingerprint1;
|
||||
const { key: privateKey } = await openpgp.generateKey({ curve: "curve25519", userIds: [{ name: 'Test' }] });
|
||||
privateKey.subKeys[0].keyPacket.publicParams.Q = Q2;
|
||||
privateKey.subKeys[0].keyPacket.privateParams.d = d2;
|
||||
privateKey.subKeys[0].keyPacket.fingerprint = fingerprint1;
|
||||
const armoredMessage = await openpgp.encrypt({ publicKeys: [publicKey], message: openpgp.Message.fromText('test') });
|
||||
it('Different keys', async function () {
|
||||
const curve = new elliptic_curves.Curve('curve25519');
|
||||
const oid = new OID(curve.oid);
|
||||
const kdfParams = new KDFParams({ hash: curve.hash, cipher: curve.cipher });
|
||||
const data = util.strToUint8Array('test');
|
||||
const { publicKey: V, wrappedKey: C } = await ecdh.encrypt(oid, kdfParams, data, Q1, fingerprint1);
|
||||
await expect(
|
||||
openpgp.decrypt({ privateKeys: [privateKey], message: await openpgp.readMessage({ armoredMessage }) })
|
||||
).to.be.rejectedWith('Error decrypting message: Key Data Integrity failed');
|
||||
ecdh.decrypt(oid, kdfParams, V, C, Q2, d2, fingerprint1)
|
||||
).to.be.rejectedWith(/Key Data Integrity failed/);
|
||||
});
|
||||
it('Invalid fingerprint', async function () {
|
||||
const { key: publicKey } = await openpgp.generateKey({ curve: "curve25519", userIds: [{ name: 'Test' }] });
|
||||
publicKey.subKeys[0].keyPacket.publicParams.Q = Q1;
|
||||
publicKey.subKeys[0].keyPacket.fingerprint = fingerprint1;
|
||||
const { key: privateKey } = await openpgp.generateKey({ curve: "curve25519", userIds: [{ name: 'Test' }] });
|
||||
privateKey.subKeys[0].keyPacket.publicParams.Q = Q2;
|
||||
privateKey.subKeys[0].keyPacket.privateParams.d = d2;
|
||||
privateKey.subKeys[0].keyPacket.fingerprint = fingerprint2;
|
||||
const armoredMessage = await openpgp.encrypt({ publicKeys: [publicKey], message: openpgp.Message.fromText('test') });
|
||||
const curve = new elliptic_curves.Curve('curve25519');
|
||||
const oid = new OID(curve.oid);
|
||||
const kdfParams = new KDFParams({ hash: curve.hash, cipher: curve.cipher });
|
||||
const data = util.strToUint8Array('test');
|
||||
const { publicKey: V, wrappedKey: C } = await ecdh.encrypt(oid, kdfParams, data, Q2, fingerprint1);
|
||||
await expect(
|
||||
openpgp.decrypt({ privateKeys: [privateKey], message: await openpgp.readMessage({ armoredMessage }) })
|
||||
).to.be.rejectedWith('Error decrypting message: Session key decryption failed');
|
||||
});
|
||||
it('Different keys', async function () {
|
||||
const { key: publicKey } = await openpgp.generateKey({ curve: "curve25519", userIds: [{ name: 'Test' }] });
|
||||
publicKey.subKeys[0].keyPacket.publicParams.Q = Q2;
|
||||
publicKey.subKeys[0].keyPacket.fingerprint = fingerprint1;
|
||||
const { key: privateKey } = await openpgp.generateKey({ curve: "curve25519", userIds: [{ name: 'Test' }] });
|
||||
privateKey.subKeys[0].keyPacket.publicParams.Q = Q1;
|
||||
privateKey.subKeys[0].keyPacket.privateParams.d = d1;
|
||||
privateKey.subKeys[0].keyPacket.fingerprint = fingerprint1;
|
||||
const armoredMessage = await openpgp.encrypt({ publicKeys: [publicKey], message: openpgp.Message.fromText('test') });
|
||||
await expect(
|
||||
openpgp.decrypt({ privateKeys: [privateKey], message: await openpgp.readMessage({ armoredMessage }) })
|
||||
).to.be.rejectedWith('Error decrypting message: Key Data Integrity failed');
|
||||
ecdh.decrypt(oid, kdfParams, V, C, Q2, d2, fingerprint2)
|
||||
).to.be.rejectedWith(/Key Data Integrity failed/);
|
||||
});
|
||||
it('Successful exchange curve25519', async function () {
|
||||
const { key: publicKey } = await openpgp.generateKey({ curve: "curve25519", userIds: [{ name: 'Test' }] });
|
||||
publicKey.subKeys[0].keyPacket.publicParams.Q = Q1;
|
||||
publicKey.subKeys[0].keyPacket.fingerprint = fingerprint1;
|
||||
const { key: privateKey } = await openpgp.generateKey({ curve: "curve25519", userIds: [{ name: 'Test' }] });
|
||||
privateKey.subKeys[0].keyPacket.publicParams.Q = Q1;
|
||||
privateKey.subKeys[0].keyPacket.privateParams.d = d1;
|
||||
privateKey.subKeys[0].keyPacket.fingerprint = fingerprint1;
|
||||
const armoredMessage = await openpgp.encrypt({ publicKeys: [publicKey], message: openpgp.Message.fromText('test') });
|
||||
expect((
|
||||
await openpgp.decrypt({ privateKeys: [privateKey], message: await openpgp.readMessage({ armoredMessage }) })
|
||||
).data).to.equal('test');
|
||||
});
|
||||
it('Successful exchange NIST P256', async function () {
|
||||
const { key: publicKey } = await openpgp.generateKey({ curve: "p256", userIds: [{ name: 'Test' }] });
|
||||
publicKey.subKeys[0].keyPacket.publicParams.Q = key_data.p256.pub;
|
||||
publicKey.subKeys[0].keyPacket.fingerprint = fingerprint1;
|
||||
const { key: privateKey } = await openpgp.generateKey({ curve: "p256", userIds: [{ name: 'Test' }] });
|
||||
privateKey.subKeys[0].keyPacket.publicParams.Q = key_data.p256.pub;
|
||||
privateKey.subKeys[0].keyPacket.privateParams.d = key_data.p256.priv;
|
||||
privateKey.subKeys[0].keyPacket.fingerprint = fingerprint1;
|
||||
const armoredMessage = await openpgp.encrypt({ publicKeys: [publicKey], message: openpgp.Message.fromText('test') });
|
||||
expect((
|
||||
await openpgp.decrypt({ privateKeys: [privateKey], message: await openpgp.readMessage({ armoredMessage }) })
|
||||
).data).to.equal('test');
|
||||
});
|
||||
it('Successful exchange NIST P384', async function () {
|
||||
const { key: publicKey } = await openpgp.generateKey({ curve: "p384", userIds: [{ name: 'Test' }] });
|
||||
publicKey.subKeys[0].keyPacket.publicParams.Q = key_data.p384.pub;
|
||||
publicKey.subKeys[0].keyPacket.fingerprint = fingerprint1;
|
||||
const { key: privateKey } = await openpgp.generateKey({ curve: "p384", userIds: [{ name: 'Test' }] });
|
||||
privateKey.subKeys[0].keyPacket.publicParams.Q = key_data.p384.pub;
|
||||
privateKey.subKeys[0].keyPacket.privateParams.d = key_data.p384.priv;
|
||||
privateKey.subKeys[0].keyPacket.fingerprint = fingerprint1;
|
||||
const armoredMessage = await openpgp.encrypt({ publicKeys: [publicKey], message: openpgp.Message.fromText('test') });
|
||||
expect((
|
||||
await openpgp.decrypt({ privateKeys: [privateKey], message: await openpgp.readMessage({ armoredMessage }) })
|
||||
).data).to.equal('test');
|
||||
});
|
||||
it('Successful exchange NIST P521', async function () {
|
||||
const { key: publicKey } = await openpgp.generateKey({ curve: "p521", userIds: [{ name: 'Test' }] });
|
||||
publicKey.subKeys[0].keyPacket.publicParams.Q = key_data.p521.pub;
|
||||
publicKey.subKeys[0].keyPacket.fingerprint = fingerprint1;
|
||||
const { key: privateKey } = await openpgp.generateKey({ curve: "p521", userIds: [{ name: 'Test' }] });
|
||||
privateKey.subKeys[0].keyPacket.publicParams.Q = key_data.p521.pub;
|
||||
privateKey.subKeys[0].keyPacket.privateParams.d = key_data.p521.priv;
|
||||
privateKey.subKeys[0].keyPacket.fingerprint = fingerprint1;
|
||||
const armoredMessage = await openpgp.encrypt({ publicKeys: [publicKey], message: openpgp.Message.fromText('test') });
|
||||
expect((
|
||||
await openpgp.decrypt({ privateKeys: [privateKey], message: await openpgp.readMessage({ armoredMessage }) })
|
||||
).data).to.equal('test');
|
||||
const curve = new elliptic_curves.Curve('curve25519');
|
||||
const oid = new OID(curve.oid);
|
||||
const kdfParams = new KDFParams({ hash: curve.hash, cipher: curve.cipher });
|
||||
const data = util.strToUint8Array('test');
|
||||
const { publicKey: V, wrappedKey: C } = await ecdh.encrypt(oid, kdfParams, data, Q1, fingerprint1);
|
||||
expect(await ecdh.decrypt(oid, kdfParams, V, C, Q1, d1, fingerprint1)).to.deep.equal(data);
|
||||
});
|
||||
|
||||
it('Comparing decrypting with useNative = true and false', async function () {
|
||||
const names = ["p256", "p384", "p521"];
|
||||
return Promise.all(names.map(async function (name) {
|
||||
const { key: publicKey } = await openpgp.generateKey({ curve: name, userIds: [{ name: 'Test' }] });
|
||||
publicKey.subKeys[0].keyPacket.publicParams.Q = key_data[name].pub;
|
||||
publicKey.subKeys[0].keyPacket.fingerprint = fingerprint1;
|
||||
const { key: privateKey } = await openpgp.generateKey({ curve: name, userIds: [{ name: 'Test' }] });
|
||||
privateKey.subKeys[0].keyPacket.publicParams.Q = key_data[name].pub;
|
||||
privateKey.subKeys[0].keyPacket.privateParams.d = key_data[name].priv;
|
||||
privateKey.subKeys[0].keyPacket.fingerprint = fingerprint1;
|
||||
const armoredMessage = await openpgp.encrypt({ publicKeys: [publicKey], message: openpgp.Message.fromText('test') });
|
||||
expect((
|
||||
await openpgp.decrypt({ privateKeys: [privateKey], message: await openpgp.readMessage({ armoredMessage }) })
|
||||
).data).to.equal('test');
|
||||
const useNative = openpgp.config.useNative;
|
||||
openpgp.config.useNative = !useNative;
|
||||
try {
|
||||
expect((
|
||||
await openpgp.decrypt({ privateKeys: [privateKey], message: await openpgp.readMessage({ armoredMessage }) })
|
||||
).data).to.equal('test');
|
||||
} finally {
|
||||
openpgp.config.useNative = useNative;
|
||||
}
|
||||
}));
|
||||
['p256', 'p384', 'p521'].forEach(curveName => {
|
||||
it(`NIST ${curveName} - Successful exchange`, async function () {
|
||||
const curve = new elliptic_curves.Curve(curveName);
|
||||
const oid = new OID(curve.oid);
|
||||
const kdfParams = new KDFParams({ hash: curve.hash, cipher: curve.cipher });
|
||||
const data = util.strToUint8Array('test');
|
||||
const Q = key_data[curveName].pub;
|
||||
const d = key_data[curveName].priv;
|
||||
const { publicKey: V, wrappedKey: C } = await ecdh.encrypt(oid, kdfParams, data, Q, fingerprint1);
|
||||
expect(await ecdh.decrypt(oid, kdfParams, V, C, Q, d, fingerprint1)).to.deep.equal(data);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Comparing decrypting with and without native crypto', () => {
|
||||
let sinonSandbox;
|
||||
let getWebCryptoStub;
|
||||
let getNodeCryptoStub;
|
||||
|
||||
beforeEach(function () {
|
||||
sinonSandbox = sandbox.create();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
sinonSandbox.restore();
|
||||
});
|
||||
|
||||
const disableNative = () => {
|
||||
enableNative();
|
||||
// stubbed functions return undefined
|
||||
getWebCryptoStub = sinonSandbox.stub(util, "getWebCrypto");
|
||||
getNodeCryptoStub = sinonSandbox.stub(util, "getNodeCrypto");
|
||||
};
|
||||
const enableNative = () => {
|
||||
getWebCryptoStub && getWebCryptoStub.restore();
|
||||
getNodeCryptoStub && getNodeCryptoStub.restore();
|
||||
};
|
||||
|
||||
['p256', 'p384', 'p521'].forEach(curveName => {
|
||||
it(`NIST ${curveName}`, async function () {
|
||||
const nodeCrypto = util.getNodeCrypto();
|
||||
const webCrypto = util.getWebCrypto();
|
||||
if (!nodeCrypto && !webCrypto) {
|
||||
this.skip();
|
||||
}
|
||||
|
||||
const curve = new elliptic_curves.Curve(curveName);
|
||||
const oid = new OID(curve.oid);
|
||||
const kdfParams = new KDFParams({ hash: curve.hash, cipher: curve.cipher });
|
||||
const data = util.strToUint8Array('test');
|
||||
const Q = key_data[curveName].pub;
|
||||
const d = key_data[curveName].priv;
|
||||
const { publicKey: V, wrappedKey: C } = await ecdh.encrypt(oid, kdfParams, data, Q, fingerprint1);
|
||||
|
||||
const nativeDecryptSpy = webCrypto ? sinonSandbox.spy(webCrypto, 'deriveBits') : sinonSandbox.spy(nodeCrypto, 'createECDH');
|
||||
expect(await ecdh.decrypt(oid, kdfParams, V, C, Q, d, fingerprint1)).to.deep.equal(data);
|
||||
disableNative();
|
||||
expect(await ecdh.decrypt(oid, kdfParams, V, C, Q, d, fingerprint1)).to.deep.equal(data);
|
||||
if (curveName !== 'p521') { // safari does not implement p521 in webcrypto
|
||||
expect(nativeDecryptSpy.calledOnce).to.be.true;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,6 +4,7 @@ const hashMod = require('../../src/crypto/hash');
|
||||
const config = require('../../src/config');
|
||||
const util = require('../../src/util');
|
||||
|
||||
const sandbox = require('sinon/lib/sinon/sandbox');
|
||||
const chai = require('chai');
|
||||
|
||||
const elliptic_data = require('./elliptic_data');
|
||||
@@ -99,6 +100,29 @@ module.exports = () => describe('Elliptic Curve Cryptography @lightweight', func
|
||||
});
|
||||
});
|
||||
describe('ECDSA signature', function () {
|
||||
let sinonSandbox;
|
||||
let getWebCryptoStub;
|
||||
let getNodeCryptoStub;
|
||||
|
||||
beforeEach(function () {
|
||||
sinonSandbox = sandbox.create();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
sinonSandbox.restore();
|
||||
});
|
||||
|
||||
const disableNative = () => {
|
||||
enableNative();
|
||||
// stubbed functions return undefined
|
||||
getWebCryptoStub = sinonSandbox.stub(util, "getWebCrypto");
|
||||
getNodeCryptoStub = sinonSandbox.stub(util, "getNodeCrypto");
|
||||
};
|
||||
const enableNative = () => {
|
||||
getWebCryptoStub && getWebCryptoStub.restore();
|
||||
getNodeCryptoStub && getNodeCryptoStub.restore();
|
||||
};
|
||||
|
||||
const verify_signature = async function (oid, hash, r, s, message, pub) {
|
||||
if (util.isString(message)) {
|
||||
message = util.strToUint8Array(message);
|
||||
@@ -151,7 +175,7 @@ module.exports = () => describe('Elliptic Curve Cryptography @lightweight', func
|
||||
});
|
||||
it('Invalid public key', async function () {
|
||||
if (!config.useIndutnyElliptic && !util.getNodeCrypto()) {
|
||||
this.skip();
|
||||
this.skip(); // webcrypto does not implement secp256k1
|
||||
}
|
||||
if (util.getNodeCrypto()) {
|
||||
await expect(verify_signature(
|
||||
@@ -162,20 +186,13 @@ module.exports = () => describe('Elliptic Curve Cryptography @lightweight', func
|
||||
)).to.eventually.be.false;
|
||||
}
|
||||
if (config.useIndutnyElliptic) {
|
||||
const useNative = config.useNative;
|
||||
config.useNative = false;
|
||||
try {
|
||||
await Promise.all([
|
||||
expect(verify_signature(
|
||||
'secp256k1', 8, [], [], [], []
|
||||
)).to.be.rejectedWith(Error, /Unknown point format/),
|
||||
expect(verify_signature(
|
||||
'secp256k1', 8, [], [], [], secp256k1_invalid_point_format
|
||||
)).to.be.rejectedWith(Error, /Unknown point format/)
|
||||
]);
|
||||
} finally {
|
||||
config.useNative = useNative;
|
||||
}
|
||||
disableNative();
|
||||
await expect(verify_signature(
|
||||
'secp256k1', 8, [], [], [], []
|
||||
)).to.be.rejectedWith(Error, /Unknown point format/);
|
||||
await expect(verify_signature(
|
||||
'secp256k1', 8, [], [], [], secp256k1_invalid_point_format
|
||||
)).to.be.rejectedWith(Error, /Unknown point format/);
|
||||
}
|
||||
});
|
||||
it('Invalid point', async function () {
|
||||
@@ -188,15 +205,10 @@ module.exports = () => describe('Elliptic Curve Cryptography @lightweight', func
|
||||
)).to.eventually.be.false;
|
||||
}
|
||||
if (config.useIndutnyElliptic) {
|
||||
const useNative = config.useNative;
|
||||
config.useNative = false;
|
||||
try {
|
||||
await expect(verify_signature(
|
||||
'secp256k1', 8, [], [], [], secp256k1_invalid_point
|
||||
)).to.be.rejectedWith(Error, /Invalid elliptic public key/);
|
||||
} finally {
|
||||
config.useNative = useNative;
|
||||
}
|
||||
disableNative();
|
||||
await expect(verify_signature(
|
||||
'secp256k1', 8, [], [], [], secp256k1_invalid_point
|
||||
)).to.be.rejectedWith(Error, /Invalid elliptic public key/);
|
||||
}
|
||||
});
|
||||
it('Invalid signature', function (done) {
|
||||
|
||||
86
test/crypto/gcm.js
Normal file
86
test/crypto/gcm.js
Normal file
@@ -0,0 +1,86 @@
|
||||
const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../..');
|
||||
const crypto = require('../../src/crypto');
|
||||
const util = require('../../src/util');
|
||||
|
||||
const sandbox = require('sinon/lib/sinon/sandbox');
|
||||
const chai = require('chai');
|
||||
chai.use(require('chai-as-promised'));
|
||||
|
||||
const expect = chai.expect;
|
||||
|
||||
module.exports = () => describe('Symmetric AES-GCM (experimental)', function() {
|
||||
let sinonSandbox;
|
||||
let getWebCryptoStub;
|
||||
let getNodeCryptoStub;
|
||||
|
||||
beforeEach(function () {
|
||||
sinonSandbox = sandbox.create();
|
||||
enableNative();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
sinonSandbox.restore();
|
||||
});
|
||||
|
||||
const disableNative = () => {
|
||||
enableNative();
|
||||
// stubbed functions return undefined
|
||||
getWebCryptoStub = sinonSandbox.stub(util, "getWebCrypto");
|
||||
getNodeCryptoStub = sinonSandbox.stub(util, "getNodeCrypto");
|
||||
};
|
||||
const enableNative = () => {
|
||||
getWebCryptoStub && getWebCryptoStub.restore();
|
||||
getNodeCryptoStub && getNodeCryptoStub.restore();
|
||||
};
|
||||
|
||||
function testAESGCM(plaintext, nativeEncrypt, nativeDecrypt) {
|
||||
const aesAlgos = Object.keys(openpgp.enums.symmetric).filter(
|
||||
algo => algo.substr(0,3) === 'aes'
|
||||
);
|
||||
aesAlgos.forEach(function(algo) {
|
||||
it(algo, async function() {
|
||||
const nodeCrypto = util.getNodeCrypto();
|
||||
const webCrypto = util.getWebCrypto();
|
||||
if (!nodeCrypto && !webCrypto) {
|
||||
this.skip(); // eslint-disable-line no-invalid-this
|
||||
}
|
||||
const key = await crypto.generateSessionKey(algo);
|
||||
const iv = await crypto.random.getRandomBytes(crypto.gcm.ivLength);
|
||||
|
||||
const nativeEncryptSpy = webCrypto ? sinonSandbox.spy(webCrypto, 'encrypt') : sinonSandbox.spy(nodeCrypto, 'createCipheriv');
|
||||
const nativeDecryptSpy = webCrypto ? sinonSandbox.spy(webCrypto, 'decrypt') : sinonSandbox.spy(nodeCrypto, 'createDecipheriv');
|
||||
|
||||
nativeEncrypt || disableNative();
|
||||
let modeInstance = await crypto.gcm(algo, key);
|
||||
const ciphertext = await modeInstance.encrypt(util.strToUint8Array(plaintext), iv);
|
||||
enableNative();
|
||||
|
||||
nativeDecrypt || disableNative();
|
||||
modeInstance = await crypto.gcm(algo, key);
|
||||
const decrypted = await modeInstance.decrypt(util.strToUint8Array(util.uint8ArrayToStr(ciphertext)), iv);
|
||||
enableNative();
|
||||
|
||||
const decryptedStr = util.uint8ArrayToStr(decrypted);
|
||||
expect(decryptedStr).to.equal(plaintext);
|
||||
|
||||
if (algo !== 'aes192') { // not implemented by webcrypto
|
||||
// sanity check: native crypto was indeed on/off
|
||||
expect(nativeEncryptSpy.called).to.equal(nativeEncrypt);
|
||||
expect(nativeDecryptSpy.called).to.equal(nativeDecrypt);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
describe('Symmetric AES-GCM (native)', function() {
|
||||
testAESGCM("12345678901234567890123456789012345678901234567890", true, true);
|
||||
});
|
||||
|
||||
describe('Symmetric AES-GCM (asm.js fallback)', function() {
|
||||
testAESGCM("12345678901234567890123456789012345678901234567890", false, false);
|
||||
});
|
||||
|
||||
describe('Symmetric AES-GCM (native encrypt, asm.js decrypt)', function() {
|
||||
testAESGCM("12345678901234567890123456789012345678901234567890", true, false);
|
||||
});
|
||||
});
|
||||
@@ -7,6 +7,7 @@ module.exports = () => describe('Crypto', function () {
|
||||
require('./ecdh.js')();
|
||||
require('./pkcs5.js')();
|
||||
require('./aes_kw.js')();
|
||||
require('./gcm.js')();
|
||||
require('./eax.js')();
|
||||
require('./ocb.js')();
|
||||
require('./rsa.js')();
|
||||
|
||||
@@ -3,6 +3,7 @@ const crypto = require('../../src/crypto');
|
||||
const random = require('../../src/crypto/random');
|
||||
const util = require('../../src/util');
|
||||
|
||||
const sandbox = require('sinon/lib/sinon/sandbox');
|
||||
const chai = require('chai');
|
||||
|
||||
chai.use(require('chai-as-promised'));
|
||||
@@ -13,6 +14,30 @@ const expect = chai.expect;
|
||||
/* eslint-disable no-invalid-this */
|
||||
const native = util.getWebCrypto() || util.getNodeCrypto();
|
||||
module.exports = () => (!native ? describe.skip : describe)('basic RSA cryptography with native crypto', function () {
|
||||
let sinonSandbox;
|
||||
let getWebCryptoStub;
|
||||
let getNodeCryptoStub;
|
||||
|
||||
beforeEach(function () {
|
||||
sinonSandbox = sandbox.create();
|
||||
enableNative();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
sinonSandbox.restore();
|
||||
});
|
||||
|
||||
const disableNative = () => {
|
||||
enableNative();
|
||||
// stubbed functions return undefined
|
||||
getWebCryptoStub = sinonSandbox.stub(util, "getWebCrypto");
|
||||
getNodeCryptoStub = sinonSandbox.stub(util, "getNodeCrypto");
|
||||
};
|
||||
const enableNative = () => {
|
||||
getWebCryptoStub && getWebCryptoStub.restore();
|
||||
getNodeCryptoStub && getNodeCryptoStub.restore();
|
||||
};
|
||||
|
||||
it('generate rsa key', async function() {
|
||||
const bits = 1024;
|
||||
const keyObject = await crypto.publicKey.rsa.generate(bits, 65537);
|
||||
@@ -49,29 +74,24 @@ module.exports = () => (!native ? describe.skip : describe)('basic RSA cryptogra
|
||||
|
||||
it('decrypt nodeCrypto by bnCrypto and vice versa', async function() {
|
||||
if (!util.getNodeCrypto()) {
|
||||
this.skip();
|
||||
this.skip(); // webcrypto does not implement RSA PKCS#1 v.15 decryption
|
||||
}
|
||||
const bits = 1024;
|
||||
const { publicParams, privateParams } = await crypto.generateParams(openpgp.enums.publicKey.rsaSign, bits);
|
||||
const { n, e, d, p, q, u } = { ...publicParams, ...privateParams };
|
||||
const message = await crypto.generateSessionKey('aes256');
|
||||
const useNative = openpgp.config.useNative;
|
||||
try {
|
||||
openpgp.config.useNative = false;
|
||||
const encryptedBn = await crypto.publicKey.rsa.encrypt(message, n, e);
|
||||
openpgp.config.useNative = true;
|
||||
const decrypted1 = await crypto.publicKey.rsa.decrypt(encryptedBn, n, e, d, p, q, u);
|
||||
expect(decrypted1).to.deep.equal(message);
|
||||
const encryptedNode = await crypto.publicKey.rsa.encrypt(message, n, e);
|
||||
openpgp.config.useNative = false;
|
||||
const decrypted2 = await crypto.publicKey.rsa.decrypt(encryptedNode, n, e, d, p, q, u);
|
||||
expect(decrypted2).to.deep.equal(message);
|
||||
} finally {
|
||||
openpgp.config.useNative = useNative;
|
||||
}
|
||||
disableNative();
|
||||
const encryptedBn = await crypto.publicKey.rsa.encrypt(message, n, e);
|
||||
enableNative();
|
||||
const decrypted1 = await crypto.publicKey.rsa.decrypt(encryptedBn, n, e, d, p, q, u);
|
||||
expect(decrypted1).to.deep.equal(message);
|
||||
const encryptedNode = await crypto.publicKey.rsa.encrypt(message, n, e);
|
||||
disableNative();
|
||||
const decrypted2 = await crypto.publicKey.rsa.decrypt(encryptedNode, n, e, d, p, q, u);
|
||||
expect(decrypted2).to.deep.equal(message);
|
||||
});
|
||||
|
||||
it('compare native crypto and bn math sign', async function() {
|
||||
it('compare native crypto and bnSign', async function() {
|
||||
const bits = 1024;
|
||||
const { publicParams, privateParams } = await crypto.generateParams(openpgp.enums.publicKey.rsaSign, bits);
|
||||
const { n, e, d, p, q, u } = { ...publicParams, ...privateParams };
|
||||
@@ -79,25 +99,14 @@ module.exports = () => (!native ? describe.skip : describe)('basic RSA cryptogra
|
||||
const hashName = 'sha256';
|
||||
const hash_algo = openpgp.enums.write(openpgp.enums.hash, hashName);
|
||||
const hashed = await crypto.hash.digest(hash_algo, message);
|
||||
const useNative = openpgp.config.useNative;
|
||||
try {
|
||||
openpgp.config.useNative = true;
|
||||
let signatureWeb;
|
||||
try {
|
||||
signatureWeb = await crypto.publicKey.rsa.sign(hash_algo, message, n, e, d, p, q, u, hashed);
|
||||
} catch (error) {
|
||||
util.printDebugError('web crypto error');
|
||||
this.skip();
|
||||
}
|
||||
openpgp.config.useNative = false;
|
||||
const signatureBN = await crypto.publicKey.rsa.sign(hash_algo, message, n, e, d, p, q, u, hashed);
|
||||
expect(util.uint8ArrayToHex(signatureWeb)).to.be.equal(util.uint8ArrayToHex(signatureBN));
|
||||
} finally {
|
||||
openpgp.config.useNative = useNative;
|
||||
}
|
||||
enableNative();
|
||||
const signatureNative = await crypto.publicKey.rsa.sign(hash_algo, message, n, e, d, p, q, u, hashed);
|
||||
disableNative();
|
||||
const signatureBN = await crypto.publicKey.rsa.sign(hash_algo, message, n, e, d, p, q, u, hashed);
|
||||
expect(util.uint8ArrayToHex(signatureNative)).to.be.equal(util.uint8ArrayToHex(signatureBN));
|
||||
});
|
||||
|
||||
it('compare native crypto and bn math verify', async function() {
|
||||
it('compare native crypto and bnVerify', async function() {
|
||||
const bits = 1024;
|
||||
const { publicParams, privateParams } = await crypto.generateParams(openpgp.enums.publicKey.rsaSign, bits);
|
||||
const { n, e, d, p, q, u } = { ...publicParams, ...privateParams };
|
||||
@@ -105,24 +114,12 @@ module.exports = () => (!native ? describe.skip : describe)('basic RSA cryptogra
|
||||
const hashName = 'sha256';
|
||||
const hash_algo = openpgp.enums.write(openpgp.enums.hash, hashName);
|
||||
const hashed = await crypto.hash.digest(hash_algo, message);
|
||||
let verifyWeb;
|
||||
let signature;
|
||||
const useNative = openpgp.config.useNative;
|
||||
try {
|
||||
openpgp.config.useNative = true;
|
||||
try {
|
||||
signature = await crypto.publicKey.rsa.sign(hash_algo, message, n, e, d, p, q, u, hashed);
|
||||
verifyWeb = await crypto.publicKey.rsa.verify(hash_algo, message, signature, n, e);
|
||||
} catch (error) {
|
||||
util.printDebugError('web crypto error');
|
||||
this.skip();
|
||||
}
|
||||
openpgp.config.useNative = false;
|
||||
const verifyBN = await crypto.publicKey.rsa.verify(hash_algo, message, signature, n, e, hashed);
|
||||
expect(verifyWeb).to.be.true;
|
||||
expect(verifyBN).to.be.true;
|
||||
} finally {
|
||||
openpgp.config.useNative = useNative;
|
||||
}
|
||||
enableNative();
|
||||
const signatureNative = await crypto.publicKey.rsa.sign(hash_algo, message, n, e, d, p, q, u, hashed);
|
||||
const verifyNative = await crypto.publicKey.rsa.verify(hash_algo, message, signatureNative, n, e);
|
||||
disableNative();
|
||||
const verifyBN = await crypto.publicKey.rsa.verify(hash_algo, message, signatureNative, n, e, hashed);
|
||||
expect(verifyNative).to.be.true;
|
||||
expect(verifyBN).to.be.true;
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user