/* LibTomCrypt, modular cryptographic library -- Tom St Denis * * LibTomCrypt is a library that provides various cryptographic * algorithms in a highly modular and flexible manner. * * The library is free for all purposes without any express * guarantee it works. * * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org */ /* OCB Implementation by Tom St Denis */ #include "mycrypt.h" #ifdef OCB_MODE static const struct { int len; unsigned char poly_div[MAXBLOCKSIZE], poly_mul[MAXBLOCKSIZE]; } polys[] = { { 8, { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D }, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B } }, { 16, { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43 }, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87 } } }; int ocb_init(ocb_state *ocb, int cipher, const unsigned char *key, unsigned long keylen, const unsigned char *nonce) { int poly, x, y, m, err; _ARGCHK(ocb != NULL); _ARGCHK(key != NULL); _ARGCHK(nonce != NULL); /* valid cipher? */ if ((err = cipher_is_valid(cipher)) != CRYPT_OK) { return err; } /* determine which polys to use */ ocb->block_len = cipher_descriptor[cipher].block_length; for (poly = 0; poly < (int)(sizeof(polys)/sizeof(polys[0])); poly++) { if (polys[poly].len == ocb->block_len) { break; } } if (polys[poly].len != ocb->block_len) { return CRYPT_INVALID_ARG; } /* schedule the key */ if ((err = cipher_descriptor[cipher].setup(key, keylen, 0, &ocb->key)) != CRYPT_OK) { return err; } /* find L = E[0] */ zeromem(ocb->L, ocb->block_len); cipher_descriptor[cipher].ecb_encrypt(ocb->L, ocb->L, &ocb->key); /* find R = E[N xor L] */ for (x = 0; x < ocb->block_len; x++) { ocb->R[x] = ocb->L[x] ^ nonce[x]; } cipher_descriptor[cipher].ecb_encrypt(ocb->R, ocb->R, &ocb->key); /* find Ls[i] = L << i for i == 0..31 */ memcpy(ocb->Ls[0], ocb->L, ocb->block_len); for (x = 1; x < 32; x++) { m = ocb->Ls[x-1][0] >> 7; for (y = 0; y < ocb->block_len-1; y++) { ocb->Ls[x][y] = ((ocb->Ls[x-1][y] << 1) | (ocb->Ls[x-1][y+1] >> 7)) & 255; } ocb->Ls[x][ocb->block_len-1] = (ocb->Ls[x-1][ocb->block_len-1] << 1) & 255; if (m == 1) { for (y = 0; y < ocb->block_len; y++) { ocb->Ls[x][y] ^= polys[poly].poly_mul[y]; } } } /* find Lr = L / x */ m = ocb->L[ocb->block_len-1] & 1; /* shift right */ for (x = ocb->block_len - 1; x > 0; x--) { ocb->Lr[x] = ((ocb->L[x] >> 1) | (ocb->L[x-1] << 7)) & 255; } ocb->Lr[0] = ocb->L[0] >> 1; if (m == 1) { for (x = 0; x < ocb->block_len; x++) { ocb->Lr[x] ^= polys[poly].poly_div[x]; } } /* set Li, checksum */ zeromem(ocb->Li, ocb->block_len); zeromem(ocb->checksum, ocb->block_len); /* set other params */ ocb->block_index = 1; ocb->cipher = cipher; return CRYPT_OK; } #endif