/* aes.c * * The aes/rijndael block cipher. */ /* nettle, low-level cryptographics library * * Copyright (C) 2000, 2001 Rafael R. Sevilla, Niels Möller * * The nettle 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.1 of the License, or (at your * option) any later version. * * The nettle 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 Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with the nettle library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA. */ /* Originally written by Rafael R. Sevilla */ #if HAVE_CONFIG_H # include "config.h" #endif #include #include "aes-internal.h" #include "macros.h" #ifndef AES_DEBUG # define AES_DEBUG 0 #endif #if AES_DEBUG # include static void d4(const char *name, unsigned r, const uint32_t *data) { unsigned j; fprintf(stderr, "aes, %d, %s: ", r, name); for (j = 0; j<4; j++) fprintf(stderr, "%08x, ", data[j]); fprintf(stderr, "\n"); } static void d2(const char *aname, uint32_t a, const char *bname, uint32_t b) { fprintf(stderr, "aes, %s: %08x, %s, %08x\n", aname, a, bname, b); } static void d1(const char *name, uint32_t a) { fprintf(stderr, "aes, %s: %08x\n", name, a); } # define D4(x) d4 x # define D2(x) d2 x # define D1(x) d2 x #else # define D4(x) # define D2(x) # define D1(x) #endif /* Get the byte with index 0, 1, 2 and 3 */ #define B0(x) ((x) & 0xff) #define B1(x) (((x) >> 8) & 0xff) #define B2(x) (((x) >> 16) & 0xff) #define B3(x) (((x) >> 24) & 0xff) #define IDX0(j) (j) #define IDX1(j) (T->idx[0][j]) #define IDX2(j) (T->idx[1][j]) #define IDX3(j) (T->idx[2][j]) /* NOTE: IDX2 can be done as j ^ 2, but that doesn't seem to make much * of a difference. */ #define SWAP(a, b) \ do { uint32_t *t_swap = (a); (a) = (b); (b) = t_swap; } while(0) void _aes_crypt(const struct aes_ctx *ctx, const struct aes_table *T, unsigned length, uint8_t *dst, const uint8_t *src) { FOR_BLOCKS(length, dst, src, AES_BLOCK_SIZE) { /* Use double buffering, reading one half of the buffer writing * to the other, and then swapping the role of the two * halves. */ uint32_t buffer[8]; uint32_t *wtxt; /* working ciphertext */ uint32_t *tmp; unsigned i; unsigned round; wtxt = buffer; tmp = buffer + 4; /* Get clear text, using little-endian byte order. * Also XOR with the first subkey. */ for (i = 0; i<4; i++) wtxt[i] = LE_READ_UINT32(src + 4*i) ^ ctx->keys[i]; for (round = 1; round < ctx->nrounds; round++) { unsigned j; D4(("wtxt", round, wtxt)); D4(("key", round, &ctx->keys[4*round])); /* What's the best way to order this loop? Ideally, * we'd want to keep both t and wtxt in registers. */ for (j=0; j<4; j++) { /* FIXME: Figure out how the indexing should really be * done. With the current idx arrays, it looks like the * code shifts the rows in the wrong direction. But it * passes the testsuite. Perhaps the tables are rotated * in the wrong direction, but I don't think so. */ uint32_t t; #if AES_SMALL t = T->table[0][ B0(wtxt[IDX0(j)]) ] ^ ROTRBYTE( T->table[0][ B1(wtxt[IDX1(j)]) ]^ ROTRBYTE( T->table[0][ B2(wtxt[IDX2(j)]) ] ^ ROTRBYTE(T->table[0][ B3(wtxt[IDX3(j)]) ]))); #else /* !AES_SMALL */ t = ( T->table[0][ B0(wtxt[IDX0(j)]) ] ^ T->table[1][ B1(wtxt[IDX1(j)]) ] ^ T->table[2][ B2(wtxt[IDX2(j)]) ] ^ T->table[3][ B3(wtxt[IDX3(j)]) ]); #endif /* !AES_SMALL */ D1(("t", t)); tmp[j] = t ^ ctx->keys[4*round + j]; } SWAP(tmp, wtxt); #if 0 D4(("t", round, t)); for (j = 0; j<4; j++) wtxt[j] = t[j] ^ ctx->keys[4*round + j]; #endif } /* Final round */ { uint32_t out; unsigned j; for (j = 0; j<4; j++) { /* FIXME: Figure out how the indexing should really be done. * It looks like this code shifts the rows in the wrong * direction, but it passes the testsuite. */ out = ( (uint32_t) T->sbox[ B0(wtxt[IDX0(j)]) ] | ((uint32_t) T->sbox[ B1(wtxt[IDX1(j)]) ] << 8) | ((uint32_t) T->sbox[ B2(wtxt[IDX2(j)]) ] << 16) | ((uint32_t) T->sbox[ B3(wtxt[IDX3(j)]) ] << 24)); D2(("t", out, "key", ctx->keys[4*round + j])); out ^= ctx->keys[4*round + j]; LE_WRITE_UINT32(dst + 4*j, out); } } } }