/**
* eme-ref.c
*
* @version 1.0 (May 2003)
*
* Reference ANSI C code for EME-AES encryption
*
* @author Shai Halevi <shaih@watson.ibm.com>
*
* entry points:
* void sectorEME(unsigned char outSector[512],
* const unsigned char K[], // 16, 24, or 32 bytes
* int keyBits, // number of bits in K[]
* const unsigned char T[16], // the "tweak"
* const unsigned char inSector[512],
* int dir // 1 for enc, 0 for dec
* );
*
* This code is hereby placed in the public domain.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* Note: The code below assumes an interface to AES core encryption and
* decryption routines, such as provided by the OpenSSL Toolkit
* (http://www.openssl.org/), developed by the OpenSSL Project.
*
* This interface can be described by the following declarations
* (which were derived from <openssl/aes.h>):
*
* typedef struct {
* unsigned long rd_key[4 * 15];
* int rounds;
* } AES_KEY;
*
* #define AES_ENCRYPT 1
* #define AES_DECRYPT 0
*
* int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
* AES_KEY *key);
* int AES_set_decrypt_key(const unsigned char *userKey, const int bits,
* AES_KEY *key);
* void AES_encrypt(const unsigned char *in, unsigned char *out,
* const AES_KEY *key);
* void AES_decrypt(const unsigned char *in, unsigned char *out,
* const AES_KEY *key);
*/
#include <openssl/aes.h>
/* local functions */
/* Encrypt or decrypt one block with AES and the given key */
static void aesBlock(unsigned char out[16], const unsigned char key[],
int keyBits, const unsigned char in[16], int dir);
/* Set out = in1 xor in2 */
static void xorBlocks(unsigned char out[16],
const unsigned char in1[16],
const unsigned char in2[16]);
/* Set out = 2 * in, multiplication in GF(2^{128}) */
static void multByTwo(unsigned char out[16], const unsigned char in[16]);
void sectorEME(unsigned char C[512], const unsigned char K[], int keyBits,
const unsigned char T[16], const unsigned char P[512], int dir)
{
int j;
unsigned char L[16], M[16], MP[16], MC[16];
unsigned char temp[512]; /* a temporary array, just in case P and C */
/* point to the same memory location */
unsigned char zero[16] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
aesBlock(zero, K, keyBits, zero, AES_ENCRYPT); /* L = 2*AES-enc(K; 0) */
multByTwo(L, zero);
for (j=0; j<32; j++) {
xorBlocks(&temp[j*16], &P[j*16], L); /* PPj = 2**(j-1)*L xor Pj */
aesBlock(&temp[j*16],
K, keyBits, &temp[j*16], dir); /* PPPj = AES-enc(K; PPj) */
multByTwo(L, L);
}
xorBlocks(MP, temp, T); /* MP = (xorSum PPPj) xor T */
for (j=1; j<32; j++)
xorBlocks(MP, MP, &temp[j*16]);
aesBlock(MC, K, keyBits, MP, dir); /* MC = AES-enc(K; MP) */
xorBlocks(M, MP, MC); /* M = MP xor MC */
for (j=1; j<32; j++) {
multByTwo(M, M);
xorBlocks(&temp[j*16],&temp[j*16],M); /* CCCj = 2**(j-1)*M xor PPPj */
}
xorBlocks(temp, MC, T); /* CCC1 = (xorSum CCCj) xor T xor MC */
for (j=1; j<32; j++)
xorBlocks(temp, temp, &temp[j*16]);
multByTwo(L, zero); /* reset L = 2*AES-enc(K; 0) */
for (j=0; j<32; j++) {
aesBlock(&temp[j*16],
K, keyBits, &temp[j*16], dir); /* CCj = AES-enc(K; CCCj) */
xorBlocks(&C[j*16], &temp[j*16], L); /* Cj = 2**(j-1)*L xor CCj */
multByTwo(L, L);
}
}
static void multByTwo(unsigned char output[16], const unsigned char input[16])
{
int j;
unsigned char temp[16]; /* a temporary array, just in case input and */
/* output point to the same memory location */
temp[0] = 2 * input[0];
if (input[15] >= 128) temp[0] ^= 135;
for (j=1; j<16; j++) {
temp[j] = 2 * input[j];
if (input[j-1] >= 128) temp[j] += 1;
}
for (j=0; j<16; j++) output[j] = temp[j];
}
static void xorBlocks(unsigned char out[16],
const unsigned char in1[16], const unsigned char in2[16])
{
int j; for (j=0; j<16; j++) out[j] = in1[j] ^ in2[j];
}
static void aesBlock(unsigned char out[16], const unsigned char key[],
int keyBits, const unsigned char in[16], int dir)
{
extern void exit(int status);
int retCode;
AES_KEY aesKey;
if (dir==AES_ENCRYPT)
retCode = AES_set_encrypt_key(key, keyBits, &aesKey);
else
retCode = AES_set_decrypt_key(key, keyBits, &aesKey);
if (retCode!=0) exit(retCode); /* Not very gracefull, but still... */
if (dir==AES_ENCRYPT) AES_encrypt(in, out, &aesKey);
else AES_decrypt(in, out, &aesKey);
}
/**
* testEME.c - generating test-vectors for the EME-AES construction
*
* @version 1.0 (May 2003)
* @author Shai Halevi <shaih@watson.ibm.com>
*
* We use the following procedure to generate the test vectors:
*
* Encryption:
* Set buffer = [0, 0, ..., 0] (a 512-byte array)
* Set T = K = [0, 0, ..., 0] (16-byte blocks)
* buffer = EME-encrypt_K^T(buffer)
* printf buffer
*
* K = buffer[0..15] (a 16-byte block)
* For i=1 to 10 do
* T = buffer[16..31] (a 16-byte block)
* For j=1 to 100 do
* buffer = EME-encrypt_K^T(buffer)
* end-for
* Print buffer
* end-for
*
* Decryption:
* Set buffer = [0, 0, ..., 0] (a 512-byte array)
* Set T = K = [0, 0, ..., 0] (16-byte blocks)
* buffer = EME-decrypt_K^T(buffer)
* printf buffer
*
* K = buffer[0..15] (a 16-byte block)
* For i=1 to 10 do
* T = buffer[16..31] (a 16-byte block)
* For j=1 to 100 do
* buffer = EME-decrypt_K^T(buffer)
* end-for
* Print buffer
* end-for
*
* This code is hereby placed in the public domain.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/aes.h>
extern void
sectorEME(unsigned char C[512], const unsigned char K[], int keyLen,
const unsigned char T[16], const unsigned char P[512], int dir);
static void emeTestDirection(int dir);
static void blocksPrint (FILE *fp, unsigned char *blocks,
int blockBits, int nBlocks, const char *tag);
int main()
{
printf("Test vectors for EME-AES, with 128-bit keys and 32 blocks\n");
emeTestDirection(AES_ENCRYPT);
emeTestDirection(AES_DECRYPT);
return 0;
}
static void emeTestDirection(int dir)
{
int i, j;
unsigned char keyMaterial[16];
unsigned char tweak[16];
unsigned char buf[512];
char *dirName = (dir==AES_ENCRYPT)? "enc" : "dec";
printf("\nTesting %sryption:\n", dirName);
memset(buf, '\0', sizeof(buf));
memset(tweak, '\0', sizeof(tweak));
memset(keyMaterial, '\0', sizeof(keyMaterial));
blocksPrint(stdout, keyMaterial, 128, 1, " key");
blocksPrint(stdout, buf, 128, 32, " buffer");
blocksPrint(stdout, tweak, 128, 1, " tweak");
sectorEME(buf, keyMaterial, 128, tweak, buf, dir);
printf("after one application of EME-AES-%s\n\n", dirName);
blocksPrint(stdout, buf, 128, 32, " buffer");
printf("==============================================================\n\n");
memcpy(keyMaterial, buf, 16);
blocksPrint(stdout, keyMaterial, 128, 1, " key");
for(i=0; i<10; i++) {
memcpy(tweak, buf+16, 16);
blocksPrint(stdout, buf, 128, 32, " buffer");
blocksPrint(stdout, tweak, 128, 1, " tweak");
for(j=0; j<100; j++) {
sectorEME(buf, keyMaterial, 128, tweak, buf, dir);
}
printf("after 100 applications of EME-AES-%s\n\n", dirName);
}
blocksPrint(stdout, buf, 128, 32, " buffer");
printf("****************************************************************\n");
printf("****************************************************************\n");
}
/**********************************************************************/
/**********************************************************************/
static void blocksPrint (FILE *fp, unsigned char *blocks,
int blockBits, int nBlocks, const char *tag)
{
int i, j;
fprintf (fp, "%s=", tag);
for (j=0; j<nBlocks; j++) {
for (i = 0; i < blockBits/8; i++) {
fprintf (fp, "%02X ", blocks[i]);
}
fprintf (fp, "\n ");
blocks += blockBits/8;
}
fprintf (fp, "\n");
fflush (fp);
} /* blocksPrint */
/**********************************************************************/