Skip to content
Snippets Groups Projects
Forked from Nettle / nettle
3530 commits behind the upstream repository.
aes.c-hacked 4.78 KiB
/* aes.c
 *
 * The aes/rijndael block cipher.
 */

/* nettle, low-level cryptographics library
 *
 * Copyright (C) 2000, 2001 Rafael R. Sevilla, Niels Mller
 *  
 * 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 <dido@pacific.net.ph> */

#if HAVE_CONFIG_H
# include "config.h"
#endif

#include <assert.h>

#include "aes-internal.h"

#include "macros.h"

#ifndef AES_DEBUG
# define AES_DEBUG 0
#endif

#if AES_DEBUG
# include <stdio.h>

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);
	  }
      }
    }
}