/* $Id: aes.C,v 1.5 2001/06/03 08:16:54 ericp Exp $ */ /* * * Copyright (C) 2001 David Mazieres (dm@uun.org) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2, or (at * your option) any later version. * * This program 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 * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA * */ /* * This is a modified version of an implementation covered by the * following copyright: * * Copyright in this implementation is held by Dr B R Gladman but I * hereby give permission for its free direct or derivative use subject * to acknowledgment of its origin and compliance with any conditions * that the originators of the algorithm place on its exploitation. * * Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999 */ #include "aes.h" static void gen_tabs (); /* Circular rotate of 32 bit values */ #define rotr(x,n) (((x) >> ((int)(n))) | ((x) << (32 - (int)(n)))) #define rotl(x,n) (((x) << ((int)(n))) | ((x) >> (32 - (int)(n)))) /* Invert byte order in a 32 bit variable */ #ifdef WORDS_BIGENDIAN #define io_swap(x) ((rotl(x, 8) & 0x00ff00ff) | (rotr(x, 8) & 0xff00ff00)) #else /* !WORDS_BIGENDIAN */ #define io_swap(x) (x) #endif /* !WORDS_BIGENDIAN */ /* Extract byte from a 32 bit quantity (little endian notation) */ #define byte(x,n) ((u_int8_t)((x) >> (8 * n))) #define LARGE_TABLES u_int8_t pow_tab[256]; u_int8_t log_tab[256]; u_int8_t sbx_tab[256]; u_int8_t isb_tab[256]; u_int32_t rco_tab[10]; u_int32_t ft_tab[4][256]; u_int32_t it_tab[4][256]; #ifdef LARGE_TABLES u_int32_t fl_tab[4][256]; u_int32_t il_tab[4][256]; #endif /* LARGE_TABLES */ static bool tab_gen; #define ff_mult(a,b) (a && b ? pow_tab[(log_tab[a] + log_tab[b]) % 255] : 0) #define f_rn(bo, bi, n, k) \ bo[n] = ft_tab[0][byte(bi[n],0)] ^ \ ft_tab[1][byte(bi[(n + 1) & 3],1)] ^ \ ft_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ ft_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n) #define i_rn(bo, bi, n, k) \ bo[n] = it_tab[0][byte(bi[n],0)] ^ \ it_tab[1][byte(bi[(n + 3) & 3],1)] ^ \ it_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ it_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n) #ifdef LARGE_TABLES #define ls_box(x) \ ( fl_tab[0][byte(x, 0)] ^ \ fl_tab[1][byte(x, 1)] ^ \ fl_tab[2][byte(x, 2)] ^ \ fl_tab[3][byte(x, 3)] ) #define f_rl(bo, bi, n, k) \ bo[n] = fl_tab[0][byte(bi[n],0)] ^ \ fl_tab[1][byte(bi[(n + 1) & 3],1)] ^ \ fl_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ fl_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n) #define i_rl(bo, bi, n, k) \ bo[n] = il_tab[0][byte(bi[n],0)] ^ \ il_tab[1][byte(bi[(n + 3) & 3],1)] ^ \ il_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ il_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n) #else /* !LARGE_TABLES */ #define ls_box(x) \ ((u_int32_t)sbx_tab[byte(x, 0)] << 0) ^ \ ((u_int32_t)sbx_tab[byte(x, 1)] << 8) ^ \ ((u_int32_t)sbx_tab[byte(x, 2)] << 16) ^ \ ((u_int32_t)sbx_tab[byte(x, 3)] << 24) #define f_rl(bo, bi, n, k) \ bo[n] = (u_int32_t)sbx_tab[byte(bi[n],0)] ^ \ rotl(((u_int32_t)sbx_tab[byte(bi[(n + 1) & 3],1)]), 8) ^ \ rotl(((u_int32_t)sbx_tab[byte(bi[(n + 2) & 3],2)]), 16) ^ \ rotl(((u_int32_t)sbx_tab[byte(bi[(n + 3) & 3],3)]), 24) ^ *(k + n) #define i_rl(bo, bi, n, k) \ bo[n] = (u_int32_t)isb_tab[byte(bi[n],0)] ^ \ rotl(((u_int32_t)isb_tab[byte(bi[(n + 3) & 3],1)]), 8) ^ \ rotl(((u_int32_t)isb_tab[byte(bi[(n + 2) & 3],2)]), 16) ^ \ rotl(((u_int32_t)isb_tab[byte(bi[(n + 1) & 3],3)]), 24) ^ *(k + n) #endif /* !LARGE_TABLES */ inline u_int32_t getleword (const u_char *k) { return k[0] | k[1]<<8 | k[2]<<16 | k[3]<<24; } inline void putleword (u_char *k, u_int32_t val) { k[0] = val; k[1] = val >> 8; k[2] = val >> 16; k[3] = val >> 24; } static void gen_tabs (void) { u_int32_t i, t; u_int8_t p, q; /* log and power tables for GF(2**8) finite field with 0x11b as * modular polynomial - the simplest prmitive root is 0x11, used * here to generate the tables */ for (i = 0, p = 1; i < 256; ++i) { pow_tab[i] = (u_int8_t) p; log_tab[p] = (u_int8_t) i; p = p ^ (p << 1) ^ (p & 0x80 ? 0x01b : 0); } log_tab[1] = 0; p = 1; for (i = 0; i < 10; ++i) { rco_tab[i] = p; p = (p << 1) ^ (p & 0x80 ? 0x1b : 0); } /* note that the affine byte transformation matrix in aes * specification is in big endian format with bit 0 as the most * significant bit. In the remainder of the specification the bits * are numbered from the least significant end of a byte. */ for (i = 0; i < 256; ++i) { p = (i ? pow_tab[255 - log_tab[i]] : 0); q = p; q = (q >> 7) | (q << 1); p ^= q; q = (q >> 7) | (q << 1); p ^= q; q = (q >> 7) | (q << 1); p ^= q; q = (q >> 7) | (q << 1); p ^= q ^ 0x63; sbx_tab[i] = (u_int8_t) p; isb_tab[p] = (u_int8_t) i; } for (i = 0; i < 256; ++i) { p = sbx_tab[i]; #ifdef LARGE_TABLES t = p; fl_tab[0][i] = t; fl_tab[1][i] = rotl (t, 8); fl_tab[2][i] = rotl (t, 16); fl_tab[3][i] = rotl (t, 24); #endif /* LARGE_TABLES */ t = ((u_int32_t) ff_mult (2, p)) | ((u_int32_t) p << 8) | ((u_int32_t) p << 16) | ((u_int32_t) ff_mult (3, p) << 24); ft_tab[0][i] = t; ft_tab[1][i] = rotl (t, 8); ft_tab[2][i] = rotl (t, 16); ft_tab[3][i] = rotl (t, 24); p = isb_tab[i]; #ifdef LARGE_TABLES t = p; il_tab[0][i] = t; il_tab[1][i] = rotl (t, 8); il_tab[2][i] = rotl (t, 16); il_tab[3][i] = rotl (t, 24); #endif /* LARGE_TABLES */ t = ((u_int32_t) ff_mult (14, p)) | ((u_int32_t) ff_mult (9, p) << 8) | ((u_int32_t) ff_mult (13, p) << 16) | ((u_int32_t) ff_mult (11, p) << 24); it_tab[0][i] = t; it_tab[1][i] = rotl (t, 8); it_tab[2][i] = rotl (t, 16); it_tab[3][i] = rotl (t, 24); } tab_gen = true; } #define star_x(x) (((x) & 0x7f7f7f7f) << 1) ^ ((((x) & 0x80808080) >> 7) * 0x1b) #define imix_col(y,x) \ { \ u = star_x(x); \ v = star_x(u); \ w = star_x(v); \ t = w ^ (x); \ (y) = u ^ v ^ w; \ (y) ^= rotr(u ^ t, 8) ^ rotr(v ^ t, 16) ^ rotr(t,24); \ } /* initialise the key schedule from the user supplied key */ #define loop4(i) \ { t = ls_box(rotr(t, 8)) ^ rco_tab[i]; \ t ^= e_key[4 * i]; e_key[4 * i + 4] = t; \ t ^= e_key[4 * i + 1]; e_key[4 * i + 5] = t; \ t ^= e_key[4 * i + 2]; e_key[4 * i + 6] = t; \ t ^= e_key[4 * i + 3]; e_key[4 * i + 7] = t; \ } #define loop6(i) \ { t = ls_box(rotr(t, 8)) ^ rco_tab[i]; \ t ^= e_key[6 * i]; e_key[6 * i + 6] = t; \ t ^= e_key[6 * i + 1]; e_key[6 * i + 7] = t; \ t ^= e_key[6 * i + 2]; e_key[6 * i + 8] = t; \ t ^= e_key[6 * i + 3]; e_key[6 * i + 9] = t; \ t ^= e_key[6 * i + 4]; e_key[6 * i + 10] = t; \ t ^= e_key[6 * i + 5]; e_key[6 * i + 11] = t; \ } #define loop8(i) \ { t = ls_box(rotr(t, 8)) ^ rco_tab[i]; \ t ^= e_key[8 * i]; e_key[8 * i + 8] = t; \ t ^= e_key[8 * i + 1]; e_key[8 * i + 9] = t; \ t ^= e_key[8 * i + 2]; e_key[8 * i + 10] = t; \ t ^= e_key[8 * i + 3]; e_key[8 * i + 11] = t; \ t = e_key[8 * i + 4] ^ ls_box(t); \ e_key[8 * i + 12] = t; \ t ^= e_key[8 * i + 5]; e_key[8 * i + 13] = t; \ t ^= e_key[8 * i + 6]; e_key[8 * i + 14] = t; \ t ^= e_key[8 * i + 7]; e_key[8 * i + 15] = t; \ } void aes::setkey (const void *_key, const u_int keylen, bool encrypt_only) { const u_char *key = static_cast (_key); u_int32_t i, t, u, v, w; decrypt = !encrypt_only; if (!tab_gen) gen_tabs (); assert (keylen == 16 || keylen == 24 || keylen == 32); k_len = (keylen + 3) / 4; e_key[0] = getleword (key); e_key[1] = getleword (key + 4); e_key[2] = getleword (key + 8); e_key[3] = getleword (key + 12); switch (k_len) { case 4: t = e_key[3]; for (i = 0; i < 10; ++i) loop4 (i); break; case 6: e_key[4] = getleword (key + 16); e_key[5] = t = getleword (key + 20); for (i = 0; i < 8; ++i) loop6 (i); break; case 8: e_key[4] = getleword (key + 16); e_key[5] = getleword (key + 20); e_key[6] = getleword (key + 24); e_key[7] = t = getleword (key + 28); for (i = 0; i < 7; ++i) loop8 (i); break; } if (decrypt) { d_key[0] = e_key[0]; d_key[1] = e_key[1]; d_key[2] = e_key[2]; d_key[3] = e_key[3]; for (i = 4; i < 4 * k_len + 24; ++i) imix_col (d_key[i], e_key[i]); } } /* encrypt a block of text */ #define f_nround(bo, bi, k) \ f_rn(bo, bi, 0, k); \ f_rn(bo, bi, 1, k); \ f_rn(bo, bi, 2, k); \ f_rn(bo, bi, 3, k); \ k += 4 #define f_lround(bo, bi, k) \ f_rl(bo, bi, 0, k); \ f_rl(bo, bi, 1, k); \ f_rl(bo, bi, 2, k); \ f_rl(bo, bi, 3, k) void aes::encipher (u_int32_t out_blk[4], const u_int32_t in_blk[4]) { u_int32_t b0[4], b1[4]; const u_int32_t *kp; b0[0] = io_swap (in_blk[0]) ^ e_key[0]; b0[1] = io_swap (in_blk[1]) ^ e_key[1]; b0[2] = io_swap (in_blk[2]) ^ e_key[2]; b0[3] = io_swap (in_blk[3]) ^ e_key[3]; kp = e_key + 4; if (k_len > 6) { f_nround (b1, b0, kp); f_nround (b0, b1, kp); } if (k_len > 4) { f_nround (b1, b0, kp); f_nround (b0, b1, kp); } f_nround (b1, b0, kp); f_nround (b0, b1, kp); f_nround (b1, b0, kp); f_nround (b0, b1, kp); f_nround (b1, b0, kp); f_nround (b0, b1, kp); f_nround (b1, b0, kp); f_nround (b0, b1, kp); f_nround (b1, b0, kp); f_lround (b0, b1, kp); out_blk[0] = io_swap (b0[0]); out_blk[1] = io_swap (b0[1]); out_blk[2] = io_swap (b0[2]); out_blk[3] = io_swap (b0[3]); } /* decrypt a block of text */ #define i_nround(bo, bi, k) \ i_rn(bo, bi, 0, k); \ i_rn(bo, bi, 1, k); \ i_rn(bo, bi, 2, k); \ i_rn(bo, bi, 3, k); \ k -= 4 #define i_lround(bo, bi, k) \ i_rl(bo, bi, 0, k); \ i_rl(bo, bi, 1, k); \ i_rl(bo, bi, 2, k); \ i_rl(bo, bi, 3, k) void aes::decipher (u_int32_t out_blk[4], const u_int32_t in_blk[4]) { u_int32_t b0[4], b1[4]; const u_int32_t *kp; #ifdef CHECK_BOUNDS assert (decrypt); #endif /* CHECK_BOUNDS */ b0[0] = io_swap (in_blk[0]) ^ e_key[4 * k_len + 24]; b0[1] = io_swap (in_blk[1]) ^ e_key[4 * k_len + 25]; b0[2] = io_swap (in_blk[2]) ^ e_key[4 * k_len + 26]; b0[3] = io_swap (in_blk[3]) ^ e_key[4 * k_len + 27]; kp = d_key + 4 * (k_len + 5); if (k_len > 6) { i_nround (b1, b0, kp); i_nround (b0, b1, kp); } if (k_len > 4) { i_nround (b1, b0, kp); i_nround (b0, b1, kp); } i_nround (b1, b0, kp); i_nround (b0, b1, kp); i_nround (b1, b0, kp); i_nround (b0, b1, kp); i_nround (b1, b0, kp); i_nround (b0, b1, kp); i_nround (b1, b0, kp); i_nround (b0, b1, kp); i_nround (b1, b0, kp); i_lround (b0, b1, kp); out_blk[0] = io_swap (b0[0]); out_blk[1] = io_swap (b0[1]); out_blk[2] = io_swap (b0[2]); out_blk[3] = io_swap (b0[3]); } void aes::encipher_bytes (void *_buf, const void *_ibuf) { u_char *buf = const_cast (static_cast (_ibuf)); u_int32_t words[4]; words[0] = getleword (buf); words[1] = getleword (buf+4); words[2] = getleword (buf+8); words[3] = getleword (buf+12); encipher (words, words); buf = static_cast (_buf); putleword (buf, words[0]); putleword (buf+4, words[1]); putleword (buf+8, words[2]); putleword (buf+12, words[3]); } void aes::decipher_bytes (void *_buf, const void *_ibuf) { u_char *buf = const_cast (static_cast (_ibuf)); u_int32_t words[4]; words[0] = getleword (buf); words[1] = getleword (buf+4); words[2] = getleword (buf+8); words[3] = getleword (buf+12); decipher (words, words); buf = static_cast (_buf); putleword (buf, words[0]); putleword (buf+4, words[1]); putleword (buf+8, words[2]); putleword (buf+12, words[3]); }