/*
// AEZ v5 reference code. AEZ info: http://www.cs.ucdavis.edu/~rogaway/aez
//
// ** This version is slow and susceptible to side-channel attacks. **
// ** Do not use for any purpose other than to understand AEZ. **
//
// Written by Ted Krovetz (ted@krovetz.net). Last modified 21 March 2017.
//
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
//
// In jurisdictions that recognize copyright laws, the author or authors
// of this software dedicate any and all copyright interest in the
// software to the public domain. We make this dedication for the benefit
// of the public at large and to the detriment of our heirs and
// successors. We intend this dedication to be an overt act of
// relinquishment in perpetuity of all present and future rights to this
// software under copyright law.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
// For more information, please refer to
*/
#include
#include
/* BLAKE2b384 is used in Extract(). We use Saarinen's reference version */
/* http://github.com/mjosaarinen/blake2_mjosref (accessed 02SEP2015) */
#include "blake2b.h"
/* We us Rijmen, Bosselaers and Barreto's AES reference code, with */
/* rijndael-alg-fst.h modified to define INTERMEDIATE_VALUE_KAT. This gives */
/* access to AES4 and AES10, and allows the forcing of MixColumns in the */
/* final round. It also defines "u32", used for internal AES keys. */
#include "rijndael-alg-fst.h"
#include "crypto_aead.h"
typedef unsigned char byte;
/* ------------------------------------------------------------------------- */
static void write32_big_endian(unsigned x, void *ptr) {
byte *p = (byte *)ptr;
p[0] = (byte)(x>>24); p[1] = (byte)(x>>16);
p[2] = (byte)(x>> 8); p[3] = (byte)(x>> 0);
}
/* ------------------------------------------------------------------------- */
/* Adjust our constructed round keys to be compatible with rijndael-alg-fst */
static void correct_key(u32 *p, unsigned nbytes) {
unsigned i;
for (i=0; i> 7);
p[15] = (p[15] << 1) ^ ((tmp >> 7)?135:0);
}
/* ------------------------------------------------------------------------- */
static void mult_block(unsigned x, byte *src, byte *dst) {
byte t[16], r[16];
memcpy(t,src,16); memset(r,0,16);
while (x != 0) {
if (x&1) xor_bytes(r,t,16,r);
double_block(t);
x>>=1;
}
memcpy(dst,r,16);
}
/* ------------------------------------------------------------------------- */
static void Extract(byte *K, unsigned kbytes, byte extracted_key[3*16]) {
if (kbytes==48) memcpy(extracted_key, K, 48);
else blake2b(extracted_key, 48, NULL, 0, K, kbytes);
}
/* ------------------------------------------------------------------------- */
static void E(byte *K, unsigned kbytes, int j, unsigned i,
byte src[16], byte dst[16]) {
byte extracted_key[3*16], buf[16], delta[16], I[16], J[16], L[16];
Extract(K, kbytes, extracted_key);
memcpy(I,extracted_key,16);
memcpy(J,extracted_key+16,16);
memcpy(L,extracted_key+32,16);
/* Encipher */
if (j == -1) {
u32 aes_key[4*11];
memset(aes_key,0,16); /* 0 */
memcpy((byte*)aes_key+ 16, extracted_key, 48); /* I J L */
correct_key(aes_key+4,3*16);
memcpy((byte*)aes_key+ 64, (byte*)aes_key+16, 48); /* I J L */
memcpy((byte*)aes_key+112, (byte*)aes_key+16, 48); /* I J L */
memcpy((byte*)aes_key+160, (byte*)aes_key+16, 16); /* I */
mult_block(i,L,delta); xor_bytes(delta,src,16,buf);
rijndaelEncryptRound(aes_key, 99, buf, 10); /*incl final MixColumns*/
} else {
u32 aes4_key[4*5];
memset(aes4_key,0,16);
memcpy((byte*)aes4_key+16, J, 16);
memcpy((byte*)aes4_key+32, I, 16);
memcpy((byte*)aes4_key+48, L, 16);
memset((byte*)aes4_key+64,0,16);
correct_key(aes4_key+4,3*16);
mult_block(j,J,delta);
mult_block(i%8,L,buf); xor_bytes(delta, buf, 16, delta);
for (i=(i+7)/8; i>0; i--) mult_block(2,I,I);
xor_bytes(delta, I, 16, delta);
xor_bytes(delta, src, 16, buf);
rijndaelEncryptRound(aes4_key, 99, buf, 4);
}
memcpy(dst, buf, 16);
}
/* ------------------------------------------------------------------------- */
static void AEZhash(byte *K, unsigned kbytes, byte *N, unsigned nbytes,
byte *A[], unsigned abytes[], unsigned veclen, unsigned tau, byte *result) {
byte buf[16], sum[16], *p;
unsigned i, k, bytes, empty;
/* Initialize sum with hash of tau */
memset(buf,0,12); write32_big_endian(tau, buf+12);
E(K,kbytes,3,1,buf,sum);
/* Hash nonce, accumulate into sum */
empty = (nbytes==0);
for (i=1; nbytes>=16; i++, nbytes-=16, N+=16) {
E(K,kbytes,4,i,N,buf); xor_bytes(sum, buf, 16, sum);
}
if (nbytes || empty) {
memset(buf,0,16); memcpy(buf,N,nbytes); buf[nbytes]=0x80;
E(K,kbytes,4,0,buf,buf);
xor_bytes(sum, buf, 16, sum);
}
/* Hash each vector element, accumulate into sum */
for (k=0; k=16; i++, bytes-=16, p+=16) {
E(K,kbytes,5+k,i,p,buf); xor_bytes(sum, buf, 16, sum);
}
if (bytes || empty) {
memset(buf,0,16); memcpy(buf,p,bytes); buf[bytes]=0x80;
E(K,kbytes,5+k,0,buf,buf);
xor_bytes(sum, buf, 16, sum);
}
}
memcpy(result,sum,16);
}
/* ------------------------------------------------------------------------- */
static void AEZprf(byte *K, unsigned kbytes, byte delta[16],
unsigned bytes, byte *result) {
byte buf[16], ctr[16];
memset(ctr,0,16);
for ( ; bytes >= 16; bytes-=16, result+=16) {
unsigned i=15;
xor_bytes(delta, ctr, 16, buf);
E(K,kbytes,-1,3,buf,result);
do { ctr[i]++; i--; } while (ctr[i+1]==0); /* ctr+=1 */
}
if (bytes) {
xor_bytes(delta, ctr, 16, buf);
E(K,kbytes,-1,3,buf,buf);
memcpy(result, buf, bytes);
}
}
/* ------------------------------------------------------------------------- */
/* Set d=0 for EncipherAEZcore and d=1 for DecipherAEZcore */
static void AEZcore(byte *K, unsigned kbytes, byte delta[16],
byte *in, unsigned inbytes, unsigned d, byte *out) {
byte tmp[16], X[16], Y[16], S[16];
byte *in_orig = in, *out_orig = out;
unsigned i, inbytes_orig = inbytes;
memset(X,0,16); memset(Y,0,16);
/* Pass 1 over in[0:-32], store intermediate values in out[0:-32] */
for (i=1; inbytes >= 64; i++, inbytes-=32, in+=32, out+=32) {
E(K, kbytes, 1, i, in+16, tmp); xor_bytes(in, tmp, 16, out);
E(K, kbytes, 0, 0, out, tmp); xor_bytes(in+16, tmp, 16, out+16);
xor_bytes(out+16, X, 16, X);
}
/* Finish X calculation */
inbytes -= 32; /* inbytes now has fragment length 0..31 */
if (inbytes >= 16) {
E(K, kbytes, 0, 4, in, tmp); xor_bytes(X, tmp, 16, X);
inbytes -= 16; in += 16; out += 16;
memset(tmp,0,16); memcpy(tmp,in,inbytes); tmp[inbytes] = 0x80;
E(K, kbytes, 0, 5, tmp, tmp); xor_bytes(X, tmp, 16, X);
} else if (inbytes > 0) {
memset(tmp,0,16); memcpy(tmp,in,inbytes); tmp[inbytes] = 0x80;
E(K, kbytes, 0, 4, tmp, tmp); xor_bytes(X, tmp, 16, X);
}
in += inbytes; out += inbytes;
/* Calculate S */
E(K, kbytes, 0, 1+d, in+16, tmp);
xor_bytes(X, in, 16, out);
xor_bytes(delta, out, 16, out);
xor_bytes(tmp, out, 16, out);
E(K, kbytes, -1, 1+d, out, tmp);
xor_bytes(in+16, tmp, 16, out+16);
xor_bytes(out, out+16, 16, S);
/* Pass 2 over intermediate values in out[32..]. Final values written */
inbytes = inbytes_orig; out = out_orig; in = in_orig;
for (i=1; inbytes >= 64; i++, inbytes-=32, in+=32, out+=32) {
E(K, kbytes, 2, i, S, tmp);
xor_bytes(out, tmp, 16, out); xor_bytes(out+16, tmp, 16, out+16);
xor_bytes(out, Y, 16, Y);
E(K, kbytes, 0, 0, out+16, tmp); xor_bytes(out, tmp, 16, out);
E(K, kbytes, 1, i, out, tmp); xor_bytes(out+16, tmp, 16, out+16);
memcpy(tmp, out, 16); memcpy(out, out+16, 16); memcpy(out+16, tmp, 16);
}
/* Finish Y calculation and finish encryption of fragment bytes */
inbytes -= 32; /* inbytes now has fragment length 0..31 */
if (inbytes >= 16) {
E(K, kbytes, -1, 4, S, tmp); xor_bytes(in, tmp, 16, out);
E(K, kbytes, 0, 4, out, tmp); xor_bytes(Y, tmp, 16, Y);
inbytes -= 16; in += 16; out += 16;
E(K, kbytes, -1, 5, S, tmp); xor_bytes(in, tmp, inbytes, tmp);
memcpy(out,tmp,inbytes);
memset(tmp+inbytes,0,16-inbytes); tmp[inbytes] = 0x80;
E(K, kbytes, 0, 5, tmp, tmp); xor_bytes(Y, tmp, 16, Y);
} else if (inbytes > 0) {
E(K, kbytes, -1, 4, S, tmp); xor_bytes(in, tmp, inbytes, tmp);
memcpy(out,tmp,inbytes);
memset(tmp+inbytes,0,16-inbytes); tmp[inbytes] = 0x80;
E(K, kbytes, 0, 4, tmp, tmp); xor_bytes(Y, tmp, 16, Y);
}
in += inbytes; out += inbytes;
/* Finish encryption of last two blocks */
E(K, kbytes, -1, 2-d, out+16, tmp);
xor_bytes(out, tmp, 16, out);
E(K, kbytes, 0, 2-d, out, tmp);
xor_bytes(tmp, out+16, 16, out+16);
xor_bytes(delta, out+16, 16, out+16);
xor_bytes(Y, out+16, 16, out+16);
memcpy(tmp, out, 16); memcpy(out, out+16, 16); memcpy(out+16, tmp, 16);
}
/* ------------------------------------------------------------------------- */
/* Set d=0 for EncipherAEZtiny and d=1 for DecipherAEZtiny */
static void AEZtiny(byte *K, unsigned kbytes, byte delta[16],
byte *in, unsigned inbytes, unsigned d, byte *out) {
unsigned rounds,i=7,j,k;
int step;
byte mask=0x00, pad=0x80, L[16], R[16], buf[32];
if (inbytes==1) rounds=24;
else if (inbytes==2) rounds=16;
else if (inbytes<16) rounds=10;
else { i=6; rounds=8; }
/* Split (inbytes*8)/2 bits into L and R. Beware: May end in nibble. */
memcpy(L, in, (inbytes+1)/2);
memcpy(R, in+inbytes/2, (inbytes+1)/2);
if (inbytes&1) { /* Must shift R left by half a byte */
for (k=0; k> 4));
R[inbytes/2] = (byte)(R[inbytes/2] << 4);
pad = 0x08; mask = 0xf0;
}
if (d) {
if (inbytes < 16) {
memset(buf,0,16); memcpy(buf,in,inbytes); buf[0] |= 0x80;
xor_bytes(delta, buf, 16, buf);
E(K, kbytes,0,3,buf,buf);
L[0] ^= (buf[0] & 0x80);
}
j = rounds-1; step = -1;
} else {
j = 0; step = 1;
}
for (k=0; kinbytes/2; k--)
buf[k] = (byte)((buf[k] >> 4) | (buf[k-1] << 4));
buf[inbytes/2] = (byte)((L[0] >> 4) | (R[inbytes/2] & 0xf0));
}
memcpy(out,buf,inbytes);
if ((inbytes < 16) && !d) {
memset(buf+inbytes,0,16-inbytes); buf[0] |= 0x80;
xor_bytes(delta, buf, 16, buf);
E(K, kbytes,0,3,buf,buf);
out[0] ^= (buf[0] & 0x80);
}
}
/* ------------------------------------------------------------------------- */
static void Encipher(byte *K, unsigned kbytes, byte delta[16],
byte *in, unsigned inbytes, byte *out) {
if (inbytes == 0) return;
if (inbytes < 32) AEZtiny(K, kbytes, delta, in, inbytes, 0, out);
else AEZcore(K, kbytes, delta, in, inbytes, 0, out);
}
/* ------------------------------------------------------------------------- */
static void Decipher(byte *K, unsigned kbytes, byte delta[16],
byte *in, unsigned inbytes, byte *out) {
if (inbytes == 0) return;
if (inbytes < 32) AEZtiny(K, kbytes, delta, in, inbytes, 1, out);
else AEZcore(K, kbytes, delta, in, inbytes, 1, out);
}
/* ------------------------------------------------------------------------- */
int Decrypt(byte *K, unsigned kbytes,
byte *N, unsigned nbytes,
byte *AD[], unsigned adbytes[],
unsigned veclen, unsigned abytes,
byte *C, unsigned cbytes, byte *M) {
byte delta[16], *X, sum=0;
unsigned i;
if (cbytes < abytes) return -1;
AEZhash(K, kbytes, N, nbytes, AD, adbytes, veclen, abytes*8, delta);
X = (byte *)malloc(cbytes);
if (cbytes==abytes) {
AEZprf(K, kbytes, delta, abytes, X);
for (i=0; i