Constant-time double() in OCB

This commit is contained in:
Daniel Huigens 2018-04-18 15:42:16 +02:00
parent 69762f95de
commit d5a7cb3037
3 changed files with 19 additions and 47 deletions

View File

@ -46,24 +46,6 @@ function rightXorMut(data, padding) {
return data;
}
/**
* 2L = L<<1 if the first bit of L is 0 and 2L = (L<<1) xor (0^120 ||
* 10000111) otherwise, where L<<1 means the left shift of L by one
* position (the first bit vanishing and a zero entering into the last
* bit). The value of 4L is simply 2(2L). We warn that to avoid side-
* channel attacks one must implement the doubling operation in a
* constant-time manner.
* @param {Uint8Array} data
*/
function mul2(data) {
const t = data[0] & 0x80;
for (let i = 0; i < 15; i++) {
data[i] = (data[i] << 1) ^ ((data[i + 1] & 0x80) ? 1 : 0);
}
data[15] = (data[15] << 1) ^ (t ? 0x87 : 0);
return data;
}
function pad(data, padding, padding2) {
// if |M| in {n, 2n, 3n, ...}
if (data.length % blockLength === 0) {
@ -83,8 +65,8 @@ export default async function CMAC(key) {
const cbc = await CBC(key);
// L ← E_K(0^n); B ← 2L; P ← 4L
const padding = mul2(await cbc(zeroBlock));
const padding2 = mul2(padding.slice());
const padding = util.double(await cbc(zeroBlock));
const padding2 = util.double(padding);
return async function(data) {
// return CBC_K(pad(M; B, P))

View File

@ -55,16 +55,6 @@ function xor(S, T) {
return xorMut(S.slice(), T);
}
function double(S) {
const double = S.slice();
util.shiftLeft(double, 1);
if (S[0] & 0b10000000) {
double[15] ^= 0b10000111;
}
return double;
}
const zeroBlock = new Uint8Array(blockLength);
const one = new Uint8Array([1]);
@ -86,9 +76,9 @@ async function OCB(cipher, key) {
const decipher = aes.decrypt.bind(aes);
const mask_x = encipher(zeroBlock);
const mask_$ = double(mask_x);
const mask_$ = util.double(mask_x);
const mask = [];
mask[0] = double(mask_$);
mask[0] = util.double(mask_$);
mask.x = mask_x;
@ -101,7 +91,7 @@ async function OCB(cipher, key) {
const { mask } = kv;
const newMaxNtz = util.nbits(Math.max(text.length, adata.length) >> 4) - 1;
for (let i = maxNtz + 1; i <= newMaxNtz; i++) {
mask[i] = double(mask[i - 1]);
mask[i] = util.double(mask[i - 1]);
}
maxNtz = newMaxNtz;
}

View File

@ -444,22 +444,22 @@ export default {
},
/**
* Shift a Uint8Array to the left by n bits
* @param {Uint8Array} array The array to shift
* @param {Integer} bits Amount of bits to shift (MUST be smaller
* than 8)
* @returns {String} Resulting array.
* If S[1] == 0, then double(S) == (S[2..128] || 0);
* otherwise, double(S) == (S[2..128] || 0) xor
* (zeros(120) || 10000111).
*
* Both OCB and EAX (through CMAC) require this function to be constant-time.
*
* @param {Uint8Array} data
*/
shiftLeft: function (array, bits) {
if (bits) {
for (let i = 0; i < array.length; i++) {
array[i] <<= bits;
if (i + 1 < array.length) {
array[i] |= array[i + 1] >> (8 - bits);
}
}
double: function(data) {
const double = new Uint8Array(data.length);
const last = data.length - 1;
for (let i = 0; i < last; i++) {
double[i] = (data[i] << 1) ^ (data[i + 1] >> 7);
}
return array;
double[last] = (data[last] << 1) ^ ((data[0] >> 7) * 0x87);
return double;
},
/**