Constant-time double() in OCB
This commit is contained in:
parent
69762f95de
commit
d5a7cb3037
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
28
src/util.js
28
src/util.js
|
@ -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;
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue
Block a user