/* rijndael - An implementation of the Rijndael cipher. * Copyright (C) 2000, 2001 Rafael R. Sevilla * * Currently maintained by brian d foy, * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "rijndael.h" #include #include #include #if 0 static void print_block(UINT8 *block) { int i; for (i=0; i> 8) | (((x) & 0xff) << 24)) #define ROTRBYTE(x) (((x) << 8) | (((x) >> 24) & 0xff)) #define SUBBYTE(x, box) (((box)[((x) & 0xff)]) | \ ((box)[(((x) >> 8) & 0xff)] << 8) | \ ((box)[(((x) >> 16) & 0xff)] << 16) | \ ((box)[(((x) >> 24) & 0xff)] << 24)) static UINT8 xtime(UINT8 a) { UINT8 b; b = (a & 0x80) ? 0x1b : 0; a<<=1; a^=b; return(a); } static UINT8 mul(UINT8 a, UINT8 b) { if (a && b) return Alogtable[(Logtable[a] + Logtable[b])%255]; else return 0; } static void inv_mix_column(UINT32 *a, UINT32 *b) { UINT8 c[4][4]; int i, j; for(j = 0; j < 4; j++) { for(i = 0; i < 4; i++) { c[j][i] = mul(0xe, (a[j] >> i*8) & 0xff) ^ mul(0xb, (a[j] >> ((i+1)%4)*8) & 0xff) ^ mul(0xd, (a[j] >> ((i+2)%4)*8) & 0xff) ^ mul(0x9, (a[j] >> ((i+3)%4)*8) & 0xff); } } for(i = 0; i < 4; i++) { b[i] = 0; for(j = 0; j < 4; j++) b[i] |= c[i][j] << (j*8); } } void rijndael_setup(RIJNDAEL_context *ctx, size_t keysize, const UINT8 *key) { int nk, nr, i, lastkey; UINT32 temp, rcon; /* Truncate keysizes to the valid key sizes provided by Rijndael */ if (keysize >= 32) { nk = 8; nr = 14; } else if (keysize >= 24) { nk = 6; nr = 12; } else { /* must be 16 or more */ nk = 4; nr = 10; } lastkey = (RIJNDAEL_BLOCKSIZE/4) * (nr + 1); ctx->nrounds = nr; rcon = 1; for (i=0; ikeys[i] = key[i*4] + (key[i*4+1]<<8) + (key[i*4+2]<<16) + (key[i*4+3]<<24); } for (i=nk; ikeys[i-1]; if (i % nk == 0) { temp = SUBBYTE(ROTBYTE(temp), sbox) ^ rcon; rcon = (UINT32)xtime((UINT8)rcon&0xff); } else if (nk > 6 && (i%nk) == 4) { temp = SUBBYTE(temp, sbox); } ctx->keys[i] = ctx->keys[i-nk] ^ temp; } /* Generate the inverse keys */ for (i=0; i<4; i++) { ctx->ikeys[i] = ctx->keys[i]; ctx->ikeys[lastkey-4 + i] = ctx->keys[lastkey-4 + i]; } for (i=4; ikeys[i]), &(ctx->ikeys[i])); } /* Key addition that also packs every byte in the key to a word rep. */ static void key_addition_8to32(const UINT8 *txt, UINT32 *keys, UINT32 *out) { const UINT8 *ptr; int i, j; UINT32 val; ptr = txt; for (i=0; i<4; i++) { val = 0; for (j=0; j<4; j++) val |= (*ptr++ << 8*j); out[i] = keys[i]^val; } } static void key_addition32(const UINT32 *txt, UINT32 *keys, UINT32 *out) { int i; for (i=0; i<4; i++) out[i] = keys[i] ^ txt[i]; } static void key_addition32to8(const UINT32 *txt, UINT32 *keys, UINT8 *out) { UINT8 *ptr; int i, j; UINT32 val; ptr = out; for (i=0; i<4; i++) { val = txt[i] ^ keys[i]; for (j=0; j<4; j++) *ptr++ = (val >> 8*j) & 0xff; } } static int idx[4][4] = { { 0, 1, 2, 3 }, { 1, 2, 3, 0 }, { 2, 3, 0, 1 }, { 3, 0, 1, 2 } }; void rijndael_encrypt(RIJNDAEL_context *ctx, const UINT8 *plaintext, UINT8 *ciphertext) { int r, j; UINT32 wtxt[4], t[4]; /* working ciphertext */ UINT32 e; key_addition_8to32(plaintext, &(ctx->keys[0]), wtxt); for (r=1; rnrounds; r++) { for (j=0; j<4; j++) { t[j] = dtbl[wtxt[j] & 0xff] ^ ROTRBYTE(dtbl[(wtxt[idx[1][j]] >> 8) & 0xff]^ ROTRBYTE(dtbl[(wtxt[idx[2][j]] >> 16) & 0xff] ^ ROTRBYTE(dtbl[(wtxt[idx[3][j]] >> 24) & 0xff]))); } key_addition32(t, &(ctx->keys[r*4]), wtxt); } /* last round is special: there is no mixcolumn, so we can't use the big tables. */ for (j=0; j<4; j++) { e = wtxt[j] & 0xff; e |= (wtxt[idx[1][j]]) & (0xff << 8 ); e |= (wtxt[idx[2][j]]) & (0xff << 16); e |= (wtxt[idx[3][j]]) & (0xffU << 24); t[j] = e; } for (j=0; j<4; j++) t[j] = SUBBYTE(t[j], sbox); key_addition32to8(t, &(ctx->keys[4*ctx->nrounds]), ciphertext); } static int iidx[4][4] = { { 0, 1, 2, 3 }, { 3, 0, 1, 2 }, { 2, 3, 0, 1 }, { 1, 2, 3, 0 } }; void rijndael_decrypt(RIJNDAEL_context *ctx, const UINT8 *ciphertext, UINT8 *plaintext) { int r, j; UINT32 wtxt[4], t[4]; /* working ciphertext */ UINT32 e; key_addition_8to32(ciphertext, &(ctx->ikeys[4*ctx->nrounds]), wtxt); for (r=ctx->nrounds-1; r> 0; r--) { for (j=0; j<4; j++) { t[j] = itbl[wtxt[j] & 0xff] ^ ROTRBYTE(itbl[(wtxt[iidx[1][j]] >> 8) & 0xff]^ ROTRBYTE(itbl[(wtxt[iidx[2][j]] >> 16) & 0xff] ^ ROTRBYTE(itbl[(wtxt[iidx[3][j]] >> 24) & 0xff]))); } key_addition32(t, &(ctx->ikeys[r*4]), wtxt); } /* last round is special: there is no mixcolumn, so we can't use the big tables. */ for (j=0; j<4; j++) { e = wtxt[j] & 0xff; e |= (wtxt[iidx[1][j]]) & (0xff << 8); e |= (wtxt[iidx[2][j]]) & (0xff << 16); e |= (wtxt[iidx[3][j]]) & (0xffU << 24); t[j] = e; } for (j=0; j<4; j++) t[j] = SUBBYTE(t[j], isbox); key_addition32to8(t, &(ctx->ikeys[0]), plaintext); } void block_encrypt(RIJNDAEL_context *ctx, UINT8 *input, int inputlen, UINT8 *output, UINT8 *iv) { int i, j, nblocks, carry_flg; UINT8 block[RIJNDAEL_BLOCKSIZE], block2[RIJNDAEL_BLOCKSIZE], oldptxt; nblocks = inputlen / RIJNDAEL_BLOCKSIZE; switch (ctx->mode) { case MODE_ECB: /* electronic code book */ for (i = 0; i=0; j--) { if (carry_flg) { block[j]++; carry_flg = block[j] != 0 ? 0 : 1; } else break; } } break; default: break; } } void block_decrypt(RIJNDAEL_context *ctx, UINT8 *input, int inputlen, UINT8 *output, UINT8 *iv) { int i, j, nblocks, carry_flg; UINT8 block[RIJNDAEL_BLOCKSIZE], block2[RIJNDAEL_BLOCKSIZE]; nblocks = inputlen / RIJNDAEL_BLOCKSIZE; switch (ctx->mode) { case MODE_ECB: for (i = 0; i=0; j--) { if (carry_flg) { block[j]++; carry_flg = block[j] != 0 ? 0 : 1; } else break; } } break; default: break; } }