Skip to content

Commit

Permalink
FEATURE: Use AES-GCM instead of AES-CBC.
Browse files Browse the repository at this point in the history
  • Loading branch information
udan11 committed Dec 5, 2018
1 parent 4243ed6 commit 1347023
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 13 deletions.
26 changes: 13 additions & 13 deletions assets/javascripts/lib/keys.js.es6
Expand Up @@ -75,9 +75,9 @@ export function importPublicKey(publicKey) {
* @return Promise<String>
*/
export function exportPrivateKey(privateKey, key) {
const iv = window.crypto.getRandomValues(new Uint8Array(16));
const iv = window.crypto.getRandomValues(new Uint8Array(12));
return window.crypto.subtle
.wrapKey("jwk", privateKey, key, { name: "AES-CBC", iv })
.wrapKey("jwk", privateKey, key, { name: "AES-GCM", iv })
.then(buffer => bufferToBase64(iv) + bufferToBase64(buffer));
}

Expand All @@ -91,13 +91,13 @@ export function exportPrivateKey(privateKey, key) {
* @return Promise<CryptoKey>
*/
export function importPrivateKey(privateKey, key, extractable) {
const iv = base64ToBuffer(privateKey.substring(0, 24));
const wrapped = base64ToBuffer(privateKey.substring(24));
const iv = base64ToBuffer(privateKey.substring(0, 16));
const wrapped = base64ToBuffer(privateKey.substring(16));
return window.crypto.subtle.unwrapKey(
"jwk",
wrapped,
key,
{ name: "AES-CBC", iv },
{ name: "AES-GCM", iv },
{ name: "RSA-OAEP", hash: { name: "SHA-256" } },
isSafari || extractable,
["decrypt", "unwrapKey"]
Expand Down Expand Up @@ -174,7 +174,7 @@ export function generatePassphraseKey(passphrase, salt) {
hash: "SHA-256"
},
key,
{ name: "AES-CBC", length: 256 },
{ name: "AES-GCM", length: 256 },
false,
["wrapKey", "unwrapKey"]
)
Expand All @@ -193,7 +193,7 @@ export function generatePassphraseKey(passphrase, salt) {
*/
export function generateKey() {
return window.crypto.subtle.generateKey(
{ name: "AES-CBC", length: 256 },
{ name: "AES-GCM", length: 256 },
true,
["encrypt", "decrypt"]
);
Expand Down Expand Up @@ -230,7 +230,7 @@ export function importKey(key, privateKey) {
base64ToBuffer(key),
privateKey,
{ name: "RSA-OAEP", hash: { name: "SHA-256" } },
{ name: "AES-CBC", length: 256 },
{ name: "AES-GCM", length: 256 },
true,
["encrypt", "decrypt"]
);
Expand All @@ -245,11 +245,11 @@ export function importKey(key, privateKey) {
* @return Promise<String>
*/
export function encrypt(key, plaintext) {
const iv = window.crypto.getRandomValues(new Uint8Array(16));
const iv = window.crypto.getRandomValues(new Uint8Array(12));
const buffer = stringToBuffer(plaintext);

return window.crypto.subtle
.encrypt({ name: "AES-CBC", iv: iv }, key, buffer)
.encrypt({ name: "AES-GCM", iv: iv, tagLength: 128 }, key, buffer)
.then(encrypted => bufferToBase64(iv) + bufferToBase64(encrypted));
}

Expand All @@ -262,10 +262,10 @@ export function encrypt(key, plaintext) {
* @return Promise<String>
*/
export function decrypt(key, ciphertext) {
const iv = base64ToBuffer(ciphertext.substring(0, 24));
const encrypted = base64ToBuffer(ciphertext.substring(24));
const iv = base64ToBuffer(ciphertext.substring(0, 16));
const encrypted = base64ToBuffer(ciphertext.substring(16));

return window.crypto.subtle
.decrypt({ name: "AES-CBC", iv: iv }, key, encrypted)
.decrypt({ name: "AES-GCM", iv: iv, tagLength: 128 }, key, encrypted)
.then(buffer => bufferToString(buffer));
}
14 changes: 14 additions & 0 deletions test/javascripts/lib/keys-test.js.es6
Expand Up @@ -69,6 +69,20 @@ test("encrypt & decrypt", async assert => {
const key = await generateKey();
const plaintext = "this is a message";
const ciphertext = await encrypt(key, plaintext);

/*
* Length of ciphertext is computed as sum:
* - input length (UTF-16, input size = output size for AES-GCM)
* - tag length is 128-bits
* - IV has 12 bytes
*
* Base64 is used for encoding, so every 3 bytes become 4 bytes.
*/
let length =
4 * Math.ceil((plaintext.length * 2 + 128 / 8) / 3) + // base64(tag + ciphertext).length
4 * Math.ceil(12 / 3); // base64(iv).length
assert.equal(ciphertext.length, length);

const plaintext2 = await decrypt(key, ciphertext);
assert.equal(plaintext, plaintext2);
});

0 comments on commit 1347023

Please sign in to comment.