1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
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 aesAlgoNames = Object.keys(openpgp.enums.symmetric).filter(
algoName => algoName.substr(0,3) === 'aes'
);
aesAlgoNames.forEach(function(algoName) {
it(algoName, async function() {
const nodeCrypto = util.getNodeCrypto();
const webCrypto = util.getWebCrypto();
if (!nodeCrypto && !webCrypto) {
this.skip(); // eslint-disable-line no-invalid-this
}
const algo = openpgp.enums.write(openpgp.enums.symmetric, algoName);
const key = await crypto.generateSessionKey(algo);
const iv = await crypto.random.getRandomBytes(crypto.mode.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.mode.gcm(algo, key);
const ciphertext = await modeInstance.encrypt(util.stringToUint8Array(plaintext), iv);
enableNative();
nativeDecrypt || disableNative();
modeInstance = await crypto.mode.gcm(algo, key);
const decrypted = await modeInstance.decrypt(util.stringToUint8Array(util.uint8ArrayToString(ciphertext)), iv);
enableNative();
const decryptedStr = util.uint8ArrayToString(decrypted);
expect(decryptedStr).to.equal(plaintext);
if (algo !== openpgp.enums.symmetric.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);
});
});
|