Native CMAC
This commit is contained in:
parent
6f2abdc2cf
commit
51d7860622
|
@ -1,21 +1,80 @@
|
||||||
/**
|
/**
|
||||||
|
* @fileoverview This module implements AES-CMAC on top of
|
||||||
|
* native AES-CBC using either the WebCrypto API or Node.js' crypto API.
|
||||||
* @requires asmcrypto.js
|
* @requires asmcrypto.js
|
||||||
|
* @requires util
|
||||||
|
* @module crypto/cmac
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { AES_CMAC } from 'asmcrypto.js/src/aes/cmac/cmac';
|
import { AES_CBC } from 'asmcrypto.js/src/aes/cbc/exports';
|
||||||
|
import util from '../util';
|
||||||
|
|
||||||
export default class CMAC extends AES_CMAC {
|
const webCrypto = util.getWebCryptoAll();
|
||||||
constructor(key) {
|
const nodeCrypto = util.getNodeCrypto();
|
||||||
super(key);
|
const Buffer = util.getNodeBuffer();
|
||||||
this._k = this.k.slice();
|
|
||||||
|
|
||||||
|
const blockLength = 16;
|
||||||
|
|
||||||
|
|
||||||
|
function set_xor_r(S, T) {
|
||||||
|
const offset = S.length - blockLength;
|
||||||
|
for (let i = 0; i < blockLength; i++) {
|
||||||
|
S[i + offset] ^= T[i];
|
||||||
|
}
|
||||||
|
return S;
|
||||||
}
|
}
|
||||||
|
|
||||||
mac(data) {
|
function mul2(data) {
|
||||||
if (this.result) {
|
const t = data[0] & 0x80;
|
||||||
this.bufferLength = 0;
|
for (let i = 0; i < 15; i++) {
|
||||||
this.k.set(this._k, 0);
|
data[i] = (data[i] << 1) ^ ((data[i + 1] & 0x80) ? 1 : 0);
|
||||||
this.cbc.AES_reset(undefined, new Uint8Array(16), false);
|
|
||||||
}
|
}
|
||||||
return this.process(data).finish().result;
|
data[15] = (data[15] << 1) ^ (t ? 0x87 : 0);
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const zeros_16 = new Uint8Array(16);
|
||||||
|
|
||||||
|
export default async function CMAC(key) {
|
||||||
|
const cbc = await CBC(key);
|
||||||
|
const padding = mul2(await cbc(zeros_16));
|
||||||
|
const padding2 = mul2(padding.slice());
|
||||||
|
|
||||||
|
return async function(data) {
|
||||||
|
return (await cbc(pad(data, padding, padding2))).subarray(-blockLength);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function pad(data, padding, padding2) {
|
||||||
|
if (data.length % blockLength === 0) {
|
||||||
|
return set_xor_r(data, padding);
|
||||||
|
}
|
||||||
|
const padded = new Uint8Array(data.length + (blockLength - data.length % blockLength));
|
||||||
|
padded.set(data);
|
||||||
|
padded[data.length] = 0b10000000;
|
||||||
|
return set_xor_r(padded, padding2);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function CBC(key) {
|
||||||
|
if (util.getWebCryptoAll() && key.length !== 24) { // WebCrypto (no 192 bit support) see: https://www.chromium.org/blink/webcrypto#TOC-AES-support
|
||||||
|
key = await webCrypto.importKey('raw', key, { name: 'AES-CBC', length: key.length * 8 }, false, ['encrypt']);
|
||||||
|
return async function(pt) {
|
||||||
|
const ct = await webCrypto.encrypt({ name: 'AES-CBC', iv: zeros_16, length: blockLength * 8 }, key, pt);
|
||||||
|
return new Uint8Array(ct).subarray(0, ct.byteLength - blockLength);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (util.getNodeCrypto()) { // Node crypto library
|
||||||
|
key = new Buffer(key);
|
||||||
|
return async function(pt) {
|
||||||
|
pt = new Buffer(pt);
|
||||||
|
const en = new nodeCrypto.createCipheriv('aes-' + (key.length * 8) + '-cbc', key, zeros_16);
|
||||||
|
const ct = en.update(pt);
|
||||||
|
return new Uint8Array(ct);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// asm.js fallback
|
||||||
|
return async function(pt) {
|
||||||
|
return AES_CBC.encrypt(pt, key, false, zeros_16);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,63 +41,57 @@ const zero = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
|
||||||
const one = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
|
const one = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
|
||||||
const two = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]);
|
const two = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]);
|
||||||
|
|
||||||
class OMAC extends CMAC {
|
async function OMAC(key) {
|
||||||
mac(t, message) {
|
const cmac = await CMAC(key);
|
||||||
return super.mac(concat(t, message));
|
return function(t, message) {
|
||||||
}
|
return cmac(concat(t, message));
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class CTR {
|
async function CTR(key) {
|
||||||
constructor(key) {
|
|
||||||
if (util.getWebCryptoAll() && key.length !== 24) { // WebCrypto (no 192 bit support) see: https://www.chromium.org/blink/webcrypto#TOC-AES-support
|
if (util.getWebCryptoAll() && key.length !== 24) { // WebCrypto (no 192 bit support) see: https://www.chromium.org/blink/webcrypto#TOC-AES-support
|
||||||
this.key = webCrypto.importKey('raw', key, { name: 'AES-CTR', length: key.length * 8 }, false, ['encrypt']);
|
key = await webCrypto.importKey('raw', key, { name: 'AES-CTR', length: key.length * 8 }, false, ['encrypt']);
|
||||||
this.ctr = this.webCtr;
|
return async function(pt, iv) {
|
||||||
} else if (util.getNodeCrypto()) { // Node crypto library
|
const ct = await webCrypto.encrypt({ name: 'AES-CTR', counter: iv, length: blockLength * 8 }, key, pt);
|
||||||
this.key = new Buffer(key);
|
return new Uint8Array(ct);
|
||||||
this.ctr = this.nodeCtr;
|
};
|
||||||
} else {
|
|
||||||
// asm.js fallback
|
|
||||||
this.key = key;
|
|
||||||
}
|
}
|
||||||
}
|
if (util.getNodeCrypto()) { // Node crypto library
|
||||||
|
key = new Buffer(key);
|
||||||
webCtr(pt, iv) {
|
return async function(pt, iv) {
|
||||||
return this.key
|
|
||||||
.then(keyObj => webCrypto.encrypt({ name: 'AES-CTR', counter: iv, length: blockLength * 8 }, keyObj, pt))
|
|
||||||
.then(ct => new Uint8Array(ct));
|
|
||||||
}
|
|
||||||
|
|
||||||
nodeCtr(pt, iv) {
|
|
||||||
pt = new Buffer(pt);
|
pt = new Buffer(pt);
|
||||||
iv = new Buffer(iv);
|
iv = new Buffer(iv);
|
||||||
const en = new nodeCrypto.createCipheriv('aes-' + (this.key.length * 8) + '-ctr', this.key, iv);
|
const en = new nodeCrypto.createCipheriv('aes-' + (key.length * 8) + '-ctr', key, iv);
|
||||||
const ct = Buffer.concat([en.update(pt), en.final()]);
|
const ct = Buffer.concat([en.update(pt), en.final()]);
|
||||||
return Promise.resolve(new Uint8Array(ct));
|
return new Uint8Array(ct);
|
||||||
}
|
};
|
||||||
|
|
||||||
ctr(pt, iv) {
|
|
||||||
return Promise.resolve(AES_CTR.encrypt(pt, this.key, iv));
|
|
||||||
}
|
}
|
||||||
|
// asm.js fallback
|
||||||
|
return async function(pt, iv) {
|
||||||
|
return AES_CTR.encrypt(pt, key, iv);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class EAX {
|
|
||||||
/**
|
/**
|
||||||
* Class to en/decrypt using EAX mode.
|
* Class to en/decrypt using EAX mode.
|
||||||
* @param {String} cipher The symmetric cipher algorithm to use e.g. 'aes128'
|
* @param {String} cipher The symmetric cipher algorithm to use e.g. 'aes128'
|
||||||
* @param {Uint8Array} key The encryption key
|
* @param {Uint8Array} key The encryption key
|
||||||
*/
|
*/
|
||||||
constructor(cipher, key) {
|
async function EAX(cipher, key) {
|
||||||
if (cipher.substr(0, 3) !== 'aes') {
|
if (cipher.substr(0, 3) !== 'aes') {
|
||||||
throw new Error('EAX mode supports only AES cipher');
|
throw new Error('EAX mode supports only AES cipher');
|
||||||
}
|
}
|
||||||
|
|
||||||
const omac = new OMAC(key);
|
const [
|
||||||
this.omac = omac.mac.bind(omac);
|
omac,
|
||||||
const ctr = new CTR(key);
|
ctr
|
||||||
this.ctr = ctr.ctr.bind(ctr);
|
] = await Promise.all([
|
||||||
}
|
OMAC(key),
|
||||||
|
CTR(key)
|
||||||
|
]);
|
||||||
|
|
||||||
|
return {
|
||||||
/**
|
/**
|
||||||
* Encrypt plaintext input.
|
* Encrypt plaintext input.
|
||||||
* @param {Uint8Array} plaintext The cleartext input to be encrypted
|
* @param {Uint8Array} plaintext The cleartext input to be encrypted
|
||||||
|
@ -105,14 +99,19 @@ class EAX {
|
||||||
* @param {Uint8Array} adata Associated data to sign
|
* @param {Uint8Array} adata Associated data to sign
|
||||||
* @returns {Promise<Uint8Array>} The ciphertext output
|
* @returns {Promise<Uint8Array>} The ciphertext output
|
||||||
*/
|
*/
|
||||||
async encrypt(plaintext, nonce, adata) {
|
encrypt: async function(plaintext, nonce, adata) {
|
||||||
const _nonce = this.omac(zero, nonce);
|
const [
|
||||||
const _adata = this.omac(one, adata);
|
_nonce,
|
||||||
const ciphered = await this.ctr(plaintext, _nonce);
|
_adata
|
||||||
const _ciphered = this.omac(two, ciphered);
|
] = await Promise.all([
|
||||||
|
omac(zero, nonce),
|
||||||
|
omac(one, adata)
|
||||||
|
]);
|
||||||
|
const ciphered = await ctr(plaintext, _nonce);
|
||||||
|
const _ciphered = await omac(two, ciphered);
|
||||||
const tag = xor3(_nonce, _ciphered, _adata); // Assumes that omac(*).length === tagLength.
|
const tag = xor3(_nonce, _ciphered, _adata); // Assumes that omac(*).length === tagLength.
|
||||||
return concat(ciphered, tag);
|
return concat(ciphered, tag);
|
||||||
}
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decrypt ciphertext input.
|
* Decrypt ciphertext input.
|
||||||
|
@ -121,18 +120,25 @@ class EAX {
|
||||||
* @param {Uint8Array} adata Associated data to verify
|
* @param {Uint8Array} adata Associated data to verify
|
||||||
* @returns {Promise<Uint8Array>} The plaintext output
|
* @returns {Promise<Uint8Array>} The plaintext output
|
||||||
*/
|
*/
|
||||||
async decrypt(ciphertext, nonce, adata) {
|
decrypt: async function(ciphertext, nonce, adata) {
|
||||||
if (ciphertext.length < tagLength) throw new Error('Invalid EAX ciphertext');
|
if (ciphertext.length < tagLength) throw new Error('Invalid EAX ciphertext');
|
||||||
const ciphered = ciphertext.subarray(0, ciphertext.length - tagLength);
|
const ciphered = ciphertext.subarray(0, ciphertext.length - tagLength);
|
||||||
const tag = ciphertext.subarray(ciphertext.length - tagLength);
|
const tag = ciphertext.subarray(ciphertext.length - tagLength);
|
||||||
const _nonce = this.omac(zero, nonce);
|
const [
|
||||||
const _adata = this.omac(one, adata);
|
_nonce,
|
||||||
const _ciphered = this.omac(two, ciphered);
|
_adata,
|
||||||
|
_ciphered
|
||||||
|
] = await Promise.all([
|
||||||
|
omac(zero, nonce),
|
||||||
|
omac(one, adata),
|
||||||
|
omac(two, ciphered)
|
||||||
|
]);
|
||||||
const _tag = xor3(_nonce, _ciphered, _adata); // Assumes that omac(*).length === tagLength.
|
const _tag = xor3(_nonce, _ciphered, _adata); // Assumes that omac(*).length === tagLength.
|
||||||
if (!util.equalsUint8Array(tag, _tag)) throw new Error('Authentication tag mismatch in EAX ciphertext');
|
if (!util.equalsUint8Array(tag, _tag)) throw new Error('Authentication tag mismatch in EAX ciphertext');
|
||||||
const plaintext = await this.ctr(ciphered, _nonce);
|
const plaintext = await ctr(ciphered, _nonce);
|
||||||
return plaintext;
|
return plaintext;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -79,18 +79,19 @@ function double(S) {
|
||||||
const zeros_16 = zeros(16);
|
const zeros_16 = zeros(16);
|
||||||
const one = new Uint8Array([1]);
|
const one = new Uint8Array([1]);
|
||||||
|
|
||||||
class OCB {
|
|
||||||
/**
|
/**
|
||||||
* Class to en/decrypt using OCB mode.
|
* Class to en/decrypt using OCB mode.
|
||||||
* @param {String} cipher The symmetric cipher algorithm to use e.g. 'aes128'
|
* @param {String} cipher The symmetric cipher algorithm to use e.g. 'aes128'
|
||||||
* @param {Uint8Array} key The encryption key
|
* @param {Uint8Array} key The encryption key
|
||||||
*/
|
*/
|
||||||
constructor(cipher, key) {
|
async function OCB(cipher, key) {
|
||||||
this.max_ntz = 0;
|
|
||||||
this.constructKeyVariables(cipher, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
constructKeyVariables(cipher, key) {
|
let max_ntz = 0;
|
||||||
|
let kv;
|
||||||
|
|
||||||
|
constructKeyVariables(cipher, key);
|
||||||
|
|
||||||
|
function constructKeyVariables(cipher, key) {
|
||||||
const aes = new ciphers[cipher](key);
|
const aes = new ciphers[cipher](key);
|
||||||
const encipher = aes.encrypt.bind(aes);
|
const encipher = aes.encrypt.bind(aes);
|
||||||
const decipher = aes.decrypt.bind(aes);
|
const decipher = aes.decrypt.bind(aes);
|
||||||
|
@ -104,25 +105,25 @@ class OCB {
|
||||||
L.x = L_x;
|
L.x = L_x;
|
||||||
L.$ = L_$;
|
L.$ = L_$;
|
||||||
|
|
||||||
this.kv = { encipher, decipher, L };
|
kv = { encipher, decipher, L };
|
||||||
}
|
}
|
||||||
|
|
||||||
extendKeyVariables(text, adata) {
|
function extendKeyVariables(text, adata) {
|
||||||
const { L } = this.kv;
|
const { L } = kv;
|
||||||
const max_ntz = util.nbits(Math.max(text.length, adata.length) >> 4) - 1;
|
const new_max_ntz = util.nbits(Math.max(text.length, adata.length) >> 4) - 1;
|
||||||
for (let i = this.max_ntz + 1; i <= max_ntz; i++) {
|
for (let i = max_ntz + 1; i <= new_max_ntz; i++) {
|
||||||
L[i] = double(L[i - 1]);
|
L[i] = double(L[i - 1]);
|
||||||
}
|
}
|
||||||
this.max_ntz = max_ntz;
|
max_ntz = new_max_ntz;
|
||||||
}
|
}
|
||||||
|
|
||||||
hash(adata) {
|
function hash(adata) {
|
||||||
if (!adata.length) {
|
if (!adata.length) {
|
||||||
// Fast path
|
// Fast path
|
||||||
return zeros_16;
|
return zeros_16;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { encipher, L } = this.kv;
|
const { encipher, L } = kv;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Consider A as a sequence of 128-bit blocks
|
// Consider A as a sequence of 128-bit blocks
|
||||||
|
@ -155,6 +156,7 @@ class OCB {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return {
|
||||||
/**
|
/**
|
||||||
* Encrypt plaintext input.
|
* Encrypt plaintext input.
|
||||||
* @param {Uint8Array} plaintext The cleartext input to be encrypted
|
* @param {Uint8Array} plaintext The cleartext input to be encrypted
|
||||||
|
@ -162,7 +164,7 @@ class OCB {
|
||||||
* @param {Uint8Array} adata Associated data to sign
|
* @param {Uint8Array} adata Associated data to sign
|
||||||
* @returns {Promise<Uint8Array>} The ciphertext output
|
* @returns {Promise<Uint8Array>} The ciphertext output
|
||||||
*/
|
*/
|
||||||
async encrypt(plaintext, nonce, adata) {
|
encrypt: async function(plaintext, nonce, adata) {
|
||||||
//
|
//
|
||||||
// Consider P as a sequence of 128-bit blocks
|
// Consider P as a sequence of 128-bit blocks
|
||||||
//
|
//
|
||||||
|
@ -171,8 +173,8 @@ class OCB {
|
||||||
//
|
//
|
||||||
// Key-dependent variables
|
// Key-dependent variables
|
||||||
//
|
//
|
||||||
this.extendKeyVariables(plaintext, adata);
|
extendKeyVariables(plaintext, adata);
|
||||||
const { encipher, L } = this.kv;
|
const { encipher, L } = kv;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Nonce-dependent and per-encryption variables
|
// Nonce-dependent and per-encryption variables
|
||||||
|
@ -218,14 +220,14 @@ class OCB {
|
||||||
set_xor(checksum, xorInput);
|
set_xor(checksum, xorInput);
|
||||||
pos += plaintext.length;
|
pos += plaintext.length;
|
||||||
}
|
}
|
||||||
const Tag = set_xor(encipher(set_xor(set_xor(checksum, offset), L.$)), this.hash(adata));
|
const Tag = set_xor(encipher(set_xor(set_xor(checksum, offset), L.$)), hash(adata));
|
||||||
|
|
||||||
//
|
//
|
||||||
// Assemble ciphertext
|
// Assemble ciphertext
|
||||||
//
|
//
|
||||||
C.set(Tag, pos);
|
C.set(Tag, pos);
|
||||||
return C;
|
return C;
|
||||||
}
|
},
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -235,7 +237,7 @@ class OCB {
|
||||||
* @param {Uint8Array} adata Associated data to verify
|
* @param {Uint8Array} adata Associated data to verify
|
||||||
* @returns {Promise<Uint8Array>} The plaintext output
|
* @returns {Promise<Uint8Array>} The plaintext output
|
||||||
*/
|
*/
|
||||||
async decrypt(ciphertext, nonce, adata) {
|
decrypt: async function(ciphertext, nonce, adata) {
|
||||||
//
|
//
|
||||||
// Consider C as a sequence of 128-bit blocks
|
// Consider C as a sequence of 128-bit blocks
|
||||||
//
|
//
|
||||||
|
@ -246,8 +248,8 @@ class OCB {
|
||||||
//
|
//
|
||||||
// Key-dependent variables
|
// Key-dependent variables
|
||||||
//
|
//
|
||||||
this.extendKeyVariables(ciphertext, adata);
|
extendKeyVariables(ciphertext, adata);
|
||||||
const { encipher, decipher, L } = this.kv;
|
const { encipher, decipher, L } = kv;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Nonce-dependent and per-encryption variables
|
// Nonce-dependent and per-encryption variables
|
||||||
|
@ -293,7 +295,7 @@ class OCB {
|
||||||
set_xor(checksum, xorInput);
|
set_xor(checksum, xorInput);
|
||||||
pos += ciphertext.length;
|
pos += ciphertext.length;
|
||||||
}
|
}
|
||||||
const Tag = set_xor(encipher(set_xor(set_xor(checksum, offset), L.$)), this.hash(adata));
|
const Tag = set_xor(encipher(set_xor(set_xor(checksum, offset), L.$)), hash(adata));
|
||||||
|
|
||||||
//
|
//
|
||||||
// Check for validity and assemble plaintext
|
// Check for validity and assemble plaintext
|
||||||
|
@ -303,6 +305,7 @@ class OCB {
|
||||||
}
|
}
|
||||||
return P;
|
return P;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -211,7 +211,8 @@ SecretKey.prototype.encrypt = async function (passphrase) {
|
||||||
arr = [new Uint8Array([253, optionalFields.length])];
|
arr = [new Uint8Array([253, optionalFields.length])];
|
||||||
arr.push(optionalFields);
|
arr.push(optionalFields);
|
||||||
const mode = crypto[aead];
|
const mode = crypto[aead];
|
||||||
const encrypted = await new mode(symmetric, key).encrypt(cleartext, iv.subarray(0, mode.ivLength), new Uint8Array());
|
const modeInstance = await mode(symmetric, key);
|
||||||
|
const encrypted = await modeInstance.encrypt(cleartext, iv.subarray(0, mode.ivLength), new Uint8Array());
|
||||||
arr.push(util.writeNumber(encrypted.length, 4));
|
arr.push(util.writeNumber(encrypted.length, 4));
|
||||||
arr.push(encrypted);
|
arr.push(encrypted);
|
||||||
} else {
|
} else {
|
||||||
|
@ -305,7 +306,8 @@ SecretKey.prototype.decrypt = async function (passphrase) {
|
||||||
if (aead) {
|
if (aead) {
|
||||||
const mode = crypto[aead];
|
const mode = crypto[aead];
|
||||||
try {
|
try {
|
||||||
cleartext = await new mode(symmetric, key).decrypt(ciphertext, iv.subarray(0, mode.ivLength), new Uint8Array());
|
const modeInstance = await mode(symmetric, key);
|
||||||
|
cleartext = await modeInstance.decrypt(ciphertext, iv.subarray(0, mode.ivLength), new Uint8Array());
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
if (err.message.startsWith('Authentication tag mismatch')) {
|
if (err.message.startsWith('Authentication tag mismatch')) {
|
||||||
throw new Error('Incorrect key passphrase: ' + err.message);
|
throw new Error('Incorrect key passphrase: ' + err.message);
|
||||||
|
|
|
@ -107,7 +107,7 @@ SymEncryptedAEADProtected.prototype.decrypt = async function (sessionKeyAlgorith
|
||||||
adataArray.set([0xC0 | this.tag, this.version, this.cipherAlgo, this.aeadAlgo, this.chunkSizeByte], 0);
|
adataArray.set([0xC0 | this.tag, this.version, this.cipherAlgo, this.aeadAlgo, this.chunkSizeByte], 0);
|
||||||
adataView.setInt32(13 + 4, data.length - mode.blockLength); // Should be setInt64(13, ...)
|
adataView.setInt32(13 + 4, data.length - mode.blockLength); // Should be setInt64(13, ...)
|
||||||
const decryptedPromises = [];
|
const decryptedPromises = [];
|
||||||
const modeInstance = new mode(cipher, key);
|
const modeInstance = await mode(cipher, key);
|
||||||
for (let chunkIndex = 0; chunkIndex === 0 || data.length;) {
|
for (let chunkIndex = 0; chunkIndex === 0 || data.length;) {
|
||||||
decryptedPromises.push(
|
decryptedPromises.push(
|
||||||
modeInstance.decrypt(data.subarray(0, chunkSize), mode.getNonce(this.iv, chunkIndexArray), adataArray)
|
modeInstance.decrypt(data.subarray(0, chunkSize), mode.getNonce(this.iv, chunkIndexArray), adataArray)
|
||||||
|
@ -149,7 +149,7 @@ SymEncryptedAEADProtected.prototype.encrypt = async function (sessionKeyAlgorith
|
||||||
adataArray.set([0xC0 | this.tag, this.version, this.cipherAlgo, this.aeadAlgo, this.chunkSizeByte], 0);
|
adataArray.set([0xC0 | this.tag, this.version, this.cipherAlgo, this.aeadAlgo, this.chunkSizeByte], 0);
|
||||||
adataView.setInt32(13 + 4, data.length); // Should be setInt64(13, ...)
|
adataView.setInt32(13 + 4, data.length); // Should be setInt64(13, ...)
|
||||||
const encryptedPromises = [];
|
const encryptedPromises = [];
|
||||||
const modeInstance = new mode(sessionKeyAlgorithm, key);
|
const modeInstance = await mode(sessionKeyAlgorithm, key);
|
||||||
for (let chunkIndex = 0; chunkIndex === 0 || data.length;) {
|
for (let chunkIndex = 0; chunkIndex === 0 || data.length;) {
|
||||||
encryptedPromises.push(
|
encryptedPromises.push(
|
||||||
modeInstance.encrypt(data.subarray(0, chunkSize), mode.getNonce(this.iv, chunkIndexArray), adataArray)
|
modeInstance.encrypt(data.subarray(0, chunkSize), mode.getNonce(this.iv, chunkIndexArray), adataArray)
|
||||||
|
|
|
@ -142,7 +142,8 @@ SymEncryptedSessionKey.prototype.decrypt = async function(passphrase) {
|
||||||
if (this.version === 5) {
|
if (this.version === 5) {
|
||||||
const mode = crypto[this.aeadAlgorithm];
|
const mode = crypto[this.aeadAlgorithm];
|
||||||
const adata = new Uint8Array([0xC0 | this.tag, this.version, enums.write(enums.symmetric, this.sessionKeyEncryptionAlgorithm), enums.write(enums.aead, this.aeadAlgorithm)]);
|
const adata = new Uint8Array([0xC0 | this.tag, this.version, enums.write(enums.symmetric, this.sessionKeyEncryptionAlgorithm), enums.write(enums.aead, this.aeadAlgorithm)]);
|
||||||
this.sessionKey = await new mode(algo, key).decrypt(this.encrypted, this.iv, adata);
|
const modeInstance = await mode(algo, key);
|
||||||
|
this.sessionKey = await modeInstance.decrypt(this.encrypted, this.iv, adata);
|
||||||
} else if (this.encrypted !== null) {
|
} else if (this.encrypted !== null) {
|
||||||
const decrypted = crypto.cfb.normalDecrypt(algo, key, this.encrypted, null);
|
const decrypted = crypto.cfb.normalDecrypt(algo, key, this.encrypted, null);
|
||||||
|
|
||||||
|
@ -182,7 +183,8 @@ SymEncryptedSessionKey.prototype.encrypt = async function(passphrase) {
|
||||||
const mode = crypto[this.aeadAlgorithm];
|
const mode = crypto[this.aeadAlgorithm];
|
||||||
this.iv = await crypto.random.getRandomBytes(mode.ivLength); // generate new random IV
|
this.iv = await crypto.random.getRandomBytes(mode.ivLength); // generate new random IV
|
||||||
const adata = new Uint8Array([0xC0 | this.tag, this.version, enums.write(enums.symmetric, this.sessionKeyEncryptionAlgorithm), enums.write(enums.aead, this.aeadAlgorithm)]);
|
const adata = new Uint8Array([0xC0 | this.tag, this.version, enums.write(enums.symmetric, this.sessionKeyEncryptionAlgorithm), enums.write(enums.aead, this.aeadAlgorithm)]);
|
||||||
this.encrypted = await new mode(algo, key).encrypt(this.sessionKey, this.iv, adata);
|
const modeInstance = await mode(algo, key);
|
||||||
|
this.encrypted = await modeInstance.encrypt(this.sessionKey, this.iv, adata);
|
||||||
} else {
|
} else {
|
||||||
const algo_enum = new Uint8Array([enums.write(enums.symmetric, this.sessionKeyAlgorithm)]);
|
const algo_enum = new Uint8Array([enums.write(enums.symmetric, this.sessionKeyAlgorithm)]);
|
||||||
const private_key = util.concatUint8Array([algo_enum, this.sessionKey]);
|
const private_key = util.concatUint8Array([algo_enum, this.sessionKey]);
|
||||||
|
|
|
@ -94,7 +94,7 @@ function testAESEAX() {
|
||||||
headerBytes = openpgp.util.hex_to_Uint8Array(vec.header),
|
headerBytes = openpgp.util.hex_to_Uint8Array(vec.header),
|
||||||
ctBytes = openpgp.util.hex_to_Uint8Array(vec.ct);
|
ctBytes = openpgp.util.hex_to_Uint8Array(vec.ct);
|
||||||
|
|
||||||
const eax = new openpgp.crypto.eax(cipher, keyBytes);
|
const eax = await openpgp.crypto.eax(cipher, keyBytes);
|
||||||
|
|
||||||
// encryption test
|
// encryption test
|
||||||
let ct = await eax.encrypt(msgBytes, nonceBytes, headerBytes);
|
let ct = await eax.encrypt(msgBytes, nonceBytes, headerBytes);
|
||||||
|
|
|
@ -122,7 +122,7 @@ describe('Symmetric AES-OCB', function() {
|
||||||
headerBytes = openpgp.util.hex_to_Uint8Array(vec.A),
|
headerBytes = openpgp.util.hex_to_Uint8Array(vec.A),
|
||||||
ctBytes = openpgp.util.hex_to_Uint8Array(vec.C);
|
ctBytes = openpgp.util.hex_to_Uint8Array(vec.C);
|
||||||
|
|
||||||
const ocb = new openpgp.crypto.ocb(cipher, keyBytes);
|
const ocb = await openpgp.crypto.ocb(cipher, keyBytes);
|
||||||
|
|
||||||
// encryption test
|
// encryption test
|
||||||
let ct = await ocb.encrypt(msgBytes, nonceBytes, headerBytes);
|
let ct = await ocb.encrypt(msgBytes, nonceBytes, headerBytes);
|
||||||
|
@ -162,7 +162,7 @@ describe('Symmetric AES-OCB', function() {
|
||||||
const K = new Uint8Array(KEYLEN / 8);
|
const K = new Uint8Array(KEYLEN / 8);
|
||||||
K[K.length - 1] = TAGLEN;
|
K[K.length - 1] = TAGLEN;
|
||||||
|
|
||||||
const ocb = new openpgp.crypto.ocb('aes' + KEYLEN, K);
|
const ocb = await openpgp.crypto.ocb('aes' + KEYLEN, K);
|
||||||
|
|
||||||
const C = [];
|
const C = [];
|
||||||
let N;
|
let N;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user