Cleanup and unit test gcm.js
This commit is contained in:
parent
49faca83c5
commit
8aa15b66a9
|
@ -23,12 +23,14 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import util from '../util.js';
|
import util from '../util.js';
|
||||||
|
import config from '../config';
|
||||||
import asmCrypto from 'asmcrypto-lite';
|
import asmCrypto from 'asmcrypto-lite';
|
||||||
const webCrypto = util.getWebCrypto();
|
const webCrypto = util.getWebCrypto();
|
||||||
const nodeCrypto = util.getNodeCrypto();
|
const nodeCrypto = util.getNodeCrypto();
|
||||||
const Buffer = util.getNodeBuffer();
|
const Buffer = util.getNodeBuffer();
|
||||||
|
|
||||||
export const ivLength = 12;
|
export const ivLength = 12;
|
||||||
|
const ALGO = 'AES-GCM';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encrypt plaintext input.
|
* Encrypt plaintext input.
|
||||||
|
@ -40,26 +42,18 @@ export const ivLength = 12;
|
||||||
*/
|
*/
|
||||||
export function encrypt(cipher, plaintext, key, iv) {
|
export function encrypt(cipher, plaintext, key, iv) {
|
||||||
if (cipher.substr(0,3) !== 'aes') {
|
if (cipher.substr(0,3) !== 'aes') {
|
||||||
return Promise.reject(new Error('Invalid cipher for GCM mode'));
|
return Promise.reject(new Error('GCM mode supports only AES cipher'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (webCrypto) { // native WebCrypto api
|
const keySize = cipher.substr(3,3);
|
||||||
const keyOptions = {
|
if (webCrypto && config.useNative && keySize !== '192') { // WebCrypto (no 192 bit support) see: https://www.chromium.org/blink/webcrypto#TOC-AES-support
|
||||||
name: 'AES-GCM'
|
return webCrypto.importKey('raw', key, { name: ALGO }, false, ['encrypt'])
|
||||||
},
|
.then(keyObj => webCrypto.encrypt({ name: ALGO, iv }, keyObj, plaintext))
|
||||||
encryptOptions = {
|
.then(ciphertext => new Uint8Array(ciphertext));
|
||||||
name: 'AES-GCM',
|
|
||||||
iv: iv
|
|
||||||
};
|
|
||||||
return webCrypto.importKey('raw', key, keyOptions, false, ['encrypt']).then(keyObj => {
|
|
||||||
return webCrypto.encrypt(encryptOptions, keyObj, plaintext);
|
|
||||||
}).then(ciphertext => {
|
|
||||||
return new Uint8Array(ciphertext);
|
|
||||||
});
|
|
||||||
|
|
||||||
} else if(nodeCrypto) { // native node crypto library
|
} else if (nodeCrypto && config.useNative) { // Node crypto library
|
||||||
let cipherObj = new nodeCrypto.createCipheriv('aes-' + cipher.substr(3,3) + '-gcm', new Buffer(key), new Buffer(iv));
|
const en = new nodeCrypto.createCipheriv('aes-' + keySize + '-gcm', new Buffer(key), new Buffer(iv));
|
||||||
let encrypted = Buffer.concat([cipherObj.update(new Buffer(plaintext)), cipherObj.final()]);
|
const encrypted = Buffer.concat([en.update(new Buffer(plaintext)), en.final()]);
|
||||||
return Promise.resolve(new Uint8Array(encrypted));
|
return Promise.resolve(new Uint8Array(encrypted));
|
||||||
|
|
||||||
} else { // asm.js fallback
|
} else { // asm.js fallback
|
||||||
|
@ -77,26 +71,18 @@ export function encrypt(cipher, plaintext, key, iv) {
|
||||||
*/
|
*/
|
||||||
export function decrypt(cipher, ciphertext, key, iv) {
|
export function decrypt(cipher, ciphertext, key, iv) {
|
||||||
if (cipher.substr(0,3) !== 'aes') {
|
if (cipher.substr(0,3) !== 'aes') {
|
||||||
return Promise.reject(new Error('Invalid cipher for GCM mode'));
|
return Promise.reject(new Error('GCM mode supports only AES cipher'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (webCrypto) { // native WebCrypto api
|
const keySize = cipher.substr(3,3);
|
||||||
const keyOptions = {
|
if (webCrypto && config.useNative && keySize !== '192') { // WebCrypto (no 192 bit support) see: https://www.chromium.org/blink/webcrypto#TOC-AES-support
|
||||||
name: 'AES-GCM'
|
return webCrypto.importKey('raw', key, { name: ALGO }, false, ['decrypt'])
|
||||||
},
|
.then(keyObj => webCrypto.decrypt({ name: ALGO, iv }, keyObj, ciphertext))
|
||||||
decryptOptions = {
|
.then(plaintext => new Uint8Array(plaintext));
|
||||||
name: 'AES-GCM',
|
|
||||||
iv: iv
|
|
||||||
};
|
|
||||||
return webCrypto.importKey('raw', key, keyOptions, false, ['decrypt']).then(keyObj => {
|
|
||||||
return webCrypto.decrypt(decryptOptions, keyObj, ciphertext);
|
|
||||||
}).then(plaintext => {
|
|
||||||
return new Uint8Array(plaintext);
|
|
||||||
});
|
|
||||||
|
|
||||||
} else if(nodeCrypto) { // native node crypto library
|
} else if (nodeCrypto && config.useNative) { // Node crypto library
|
||||||
let decipherObj = new nodeCrypto.createDecipheriv('aes-' + cipher.substr(3,3) + '-gcm', new Buffer(key), new Buffer(iv));
|
let de = new nodeCrypto.createDecipheriv('aes-' + keySize + '-gcm', new Buffer(key), new Buffer(iv));
|
||||||
let decrypted = Buffer.concat([decipherObj.update(new Buffer(ciphertext)), decipherObj.final()]);
|
let decrypted = Buffer.concat([de.update(new Buffer(ciphertext)), de.final()]);
|
||||||
return Promise.resolve(new Uint8Array(decrypted));
|
return Promise.resolve(new Uint8Array(decrypted));
|
||||||
|
|
||||||
} else { // asm.js fallback
|
} else { // asm.js fallback
|
||||||
|
|
|
@ -80,7 +80,7 @@ describe('API functional testing', function() {
|
||||||
0x51,0xe0,0x22,0xf0,0xff,0xa7,0x42,0xd4,0xde,0x0b,0x47,0x8f,0x2b,
|
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,
|
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])];
|
0xe7,0xd6,0x76,0xea,0x0e,0x1a,0x90,0x30,0xf5,0x98,0x01,0xc5,0x73])];
|
||||||
|
|
||||||
var DSApubMPIstrs = [
|
var DSApubMPIstrs = [
|
||||||
new Uint8Array([0x08,0x00,0xa8,0x85,0x5c,0x28,0x05,0x94,0x03,0xbe,0x07,0x6c,0x13,0x3e,0x65,
|
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,
|
0xfb,0xb5,0xe1,0x99,0x7c,0xfa,0x84,0xe3,0xac,0x47,0xa5,0xc4,0x46,0xd8,0x5f,
|
||||||
|
@ -143,7 +143,7 @@ describe('API functional testing', function() {
|
||||||
new Uint8Array([0x01,0x00,0x9b,0x58,0xa8,0xf4,0x04,0xb1,0xd5,0x14,0x09,0xe1,0xe1,0xa1,0x8a,
|
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,
|
0x0b,0xa3,0xc3,0xa3,0x66,0xaa,0x27,0x99,0x50,0x1c,0x4d,0xba,0x24,0xee,0xdf,
|
||||||
0xdf,0xb8,0x8e,0x8e])];
|
0xdf,0xb8,0x8e,0x8e])];
|
||||||
|
|
||||||
var ElgamalpubMPIstrs = [
|
var ElgamalpubMPIstrs = [
|
||||||
new Uint8Array([0x08,0x00,0xea,0xcc,0xbe,0xe2,0xe4,0x5a,0x51,0x18,0x93,0xa1,0x12,0x2f,0x00,
|
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,
|
0x99,0x42,0xd8,0x5c,0x1c,0x2f,0xb6,0x3c,0xd9,0x94,0x61,0xb4,0x55,0x8d,0x4e,
|
||||||
|
@ -200,13 +200,13 @@ describe('API functional testing', function() {
|
||||||
RSAsecMPIs[i] = new openpgp.MPI();
|
RSAsecMPIs[i] = new openpgp.MPI();
|
||||||
RSAsecMPIs[i].read(RSAsecMPIstrs[i]);
|
RSAsecMPIs[i].read(RSAsecMPIstrs[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
var DSAsecMPIs = [];
|
var DSAsecMPIs = [];
|
||||||
for (i = 0; i < 1; i++) {
|
for (i = 0; i < 1; i++) {
|
||||||
DSAsecMPIs[i] = new openpgp.MPI();
|
DSAsecMPIs[i] = new openpgp.MPI();
|
||||||
DSAsecMPIs[i].read(DSAsecMPIstrs[i]);
|
DSAsecMPIs[i].read(DSAsecMPIstrs[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
var DSApubMPIs = [];
|
var DSApubMPIs = [];
|
||||||
for (i = 0; i < 4; i++) {
|
for (i = 0; i < 4; i++) {
|
||||||
DSApubMPIs[i] = new openpgp.MPI();
|
DSApubMPIs[i] = new openpgp.MPI();
|
||||||
|
@ -217,7 +217,7 @@ describe('API functional testing', function() {
|
||||||
ElgamalsecMPIs[i] = new openpgp.MPI();
|
ElgamalsecMPIs[i] = new openpgp.MPI();
|
||||||
ElgamalsecMPIs[i].read(ElgamalsecMPIstrs[i]);
|
ElgamalsecMPIs[i].read(ElgamalsecMPIstrs[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
var ElgamalpubMPIs = [];
|
var ElgamalpubMPIs = [];
|
||||||
for (i = 0; i < 3; i++) {
|
for (i = 0; i < 3; i++) {
|
||||||
ElgamalpubMPIs[i] = new openpgp.MPI();
|
ElgamalpubMPIs[i] = new openpgp.MPI();
|
||||||
|
@ -287,6 +287,25 @@ describe('API functional testing', function() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function testAESGCM(plaintext) {
|
||||||
|
symmAlgos.forEach(function(algo) {
|
||||||
|
if(algo.substr(0,3) === 'aes') {
|
||||||
|
it(algo, function(done) {
|
||||||
|
var key = openpgp.crypto.generateSessionKey(algo);
|
||||||
|
var iv = openpgp.crypto.random.getRandomValues(new Uint8Array(openpgp.crypto.gcm.ivLength));
|
||||||
|
|
||||||
|
openpgp.crypto.gcm.encrypt(algo, util.str2Uint8Array(plaintext), key, iv).then(function(ciphertext) {
|
||||||
|
return openpgp.crypto.gcm.decrypt(algo, ciphertext, key, iv);
|
||||||
|
}).then(function(decrypted) {
|
||||||
|
var decryptedStr = util.Uint8Array2str(decrypted);
|
||||||
|
expect(decryptedStr).to.equal(plaintext);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
it("Symmetric with OpenPGP CFB resync", function () {
|
it("Symmetric with OpenPGP CFB resync", function () {
|
||||||
testCFB("hello", true);
|
testCFB("hello", true);
|
||||||
testCFB("1234567", true);
|
testCFB("1234567", true);
|
||||||
|
@ -301,11 +320,37 @@ describe('API functional testing', function() {
|
||||||
testCFB("12345678901234567890123456789012345678901234567890", false);
|
testCFB("12345678901234567890123456789012345678901234567890", false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("asmCrypto AES without OpenPGP CFB resync", function () {
|
it.skip("asmCrypto AES without OpenPGP CFB resync", function () {
|
||||||
testCFB("hello");
|
testAESCFB("hello");
|
||||||
testCFB("1234567");
|
testAESCFB("1234567");
|
||||||
testCFB("foobarfoobar1234567890");
|
testAESCFB("foobarfoobar1234567890");
|
||||||
testCFB("12345678901234567890123456789012345678901234567890");
|
testAESCFB("12345678901234567890123456789012345678901234567890");
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Symmetric AES-GCM (native)', function() {
|
||||||
|
var useNativeVal;
|
||||||
|
beforeEach(function() {
|
||||||
|
useNativeVal = openpgp.config.useNative;
|
||||||
|
openpgp.config.useNative = true;
|
||||||
|
});
|
||||||
|
afterEach(function() {
|
||||||
|
openpgp.config.useNative = useNativeVal;
|
||||||
|
});
|
||||||
|
|
||||||
|
testAESGCM("12345678901234567890123456789012345678901234567890");
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Symmetric AES-GCM (asm.js fallback)', function() {
|
||||||
|
var useNativeVal;
|
||||||
|
beforeEach(function() {
|
||||||
|
useNativeVal = openpgp.config.useNative;
|
||||||
|
openpgp.config.useNative = false;
|
||||||
|
});
|
||||||
|
afterEach(function() {
|
||||||
|
openpgp.config.useNative = useNativeVal;
|
||||||
|
});
|
||||||
|
|
||||||
|
testAESGCM("12345678901234567890123456789012345678901234567890");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Asymmetric using RSA with eme_pkcs1 padding', function (done) {
|
it('Asymmetric using RSA with eme_pkcs1 padding', function (done) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user