/* * aes_tables.c * * generate tables for the AES cipher * * David A. McGrew * Cisco Systems, Inc. */ /* * * Copyright(c) 2001-2006 Cisco Systems, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of the Cisco Systems, Inc. nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include <stdio.h> #include "gf2_8.h" #include "crypto_math.h" unsigned char aes_sbox[256]; unsigned char aes_inv_sbox[256]; uint32_t T0[256], T1[256], T2[256], T3[256], T4[256]; #define AES_INVERSE_TEST 0 /* set to 1 to test forward/backwards aes */ /* functions for precomputing AES values */ /* * A[] is the 8 x 8 binary matrix (represented as an array of columns, * where each column is an octet) which defines the affine * transformation used in the AES substitution table (Section * 4.2.1 of the spec). */ uint8_t A[8] = { 31, 62, 124, 248, 241, 227, 199, 143 }; /* * b is the 8 bit vector (represented as an octet) used in the affine * transform described above. */ uint8_t b = 99; void aes_init_sbox(void) { unsigned int i; uint8_t x; for (i=0; i < 256; i++) { x = gf2_8_compute_inverse((gf2_8)i); x = A_times_x_plus_b(A, x, b); aes_sbox[i] = x; aes_inv_sbox[x] = i; } } void aes_compute_tables(void) { int i; uint32_t x1, x2, x3; v32_t tmp; /* initialize substitution table */ aes_init_sbox(); /* combine sbox with linear operations to form 8-bit to 32-bit tables */ for (i=0; i < 256; i++) { x1 = aes_sbox[i]; x2 = gf2_8_shift(x1); x3 = x2 ^ x1; tmp.v8[0] = x2; tmp.v8[1] = x1; tmp.v8[2] = x1; tmp.v8[3] = x3; T0[i] = tmp.value; tmp.v8[0] = x3; tmp.v8[1] = x2; tmp.v8[2] = x1; tmp.v8[3] = x1; T1[i] = tmp.value; tmp.v8[0] = x1; tmp.v8[1] = x3; tmp.v8[2] = x2; tmp.v8[3] = x1; T2[i] = tmp.value; tmp.v8[0] = x1; tmp.v8[1] = x1; tmp.v8[2] = x3; tmp.v8[3] = x2; T3[i] = tmp.value; } } /* * the tables U0, U1, U2, U3 implement the aes operations invSubBytes, * invMixColumns, and invShiftRows */ uint32_t U0[256], U1[256], U2[256], U3[256], U4[256]; extern uint8_t aes_inv_sbox[256]; void aes_compute_inv_tables(void) { int i; uint8_t x, xe, x9, xd, xb; v32_t tmp; /* combine sbox with linear operations to form 8-bit to 32-bit tables */ for (i=0; i < 256; i++) { x = aes_inv_sbox[i]; xe = gf2_8_multiply(0x0e, x); x9 = gf2_8_multiply(0x09, x); xd = gf2_8_multiply(0x0d, x); xb = gf2_8_multiply(0x0b, x); tmp.v8[0] = xe; tmp.v8[1] = x9; tmp.v8[2] = xd; tmp.v8[3] = xb; U0[i] = tmp.value; tmp.v8[0] = xb; tmp.v8[1] = xe; tmp.v8[2] = x9; tmp.v8[3] = xd; U1[i] = tmp.value; tmp.v8[0] = xd; tmp.v8[1] = xb; tmp.v8[2] = xe; tmp.v8[3] = x9; U2[i] = tmp.value; tmp.v8[0] = x9; tmp.v8[1] = xd; tmp.v8[2] = xb; tmp.v8[3] = xe; U3[i] = tmp.value; tmp.v8[0] = tmp.v8[1] = tmp.v8[2] = tmp.v8[3] = x; U4[i] = tmp.value; } } /* * aes_test_inverse() returns err_status_ok if aes * encryption and decryption are true inverses of each other, and * returns err_status_algo_fail otherwise */ #include "err.h" err_status_t aes_test_inverse(void); #define TABLES_32BIT 1 #ifndef HIDE_AES_TABLES_MAIN int main(void) { int i; aes_init_sbox(); aes_compute_inv_tables(); #if TABLES_32BIT printf("uint32_t U0 = {"); for (i=0; i < 256; i++) { if ((i % 4) == 0) printf("\n"); printf("0x%0x, ", U0[i]); } printf("\n}\n"); printf("uint32_t U1 = {"); for (i=0; i < 256; i++) { if ((i % 4) == 0) printf("\n"); printf("0x%x, ", U1[i]); } printf("\n}\n"); printf("uint32_t U2 = {"); for (i=0; i < 256; i++) { if ((i % 4) == 0) printf("\n"); printf("0x%x, ", U2[i]); } printf("\n}\n"); printf("uint32_t U3 = {"); for (i=0; i < 256; i++) { if ((i % 4) == 0) printf("\n"); printf("0x%x, ", U3[i]); } printf("\n}\n"); printf("uint32_t U4 = {"); for (i=0; i < 256; i++) { if ((i % 4) == 0) printf("\n"); printf("0x%x, ", U4[i]); } printf("\n}\n"); #else printf("uint32_t U0 = {"); for (i=0; i < 256; i++) { if ((i % 4) == 0) printf("\n"); printf("0x%lx, ", U0[i]); } printf("\n}\n"); printf("uint32_t U1 = {"); for (i=0; i < 256; i++) { if ((i % 4) == 0) printf("\n"); printf("0x%lx, ", U1[i]); } printf("\n}\n"); printf("uint32_t U2 = {"); for (i=0; i < 256; i++) { if ((i % 4) == 0) printf("\n"); printf("0x%lx, ", U2[i]); } printf("\n}\n"); printf("uint32_t U3 = {"); for (i=0; i < 256; i++) { if ((i % 4) == 0) printf("\n"); printf("0x%lx, ", U3[i]); } printf("\n}\n"); printf("uint32_t U4 = {"); for (i=0; i < 256; i++) { if ((i % 4) == 0) printf("\n"); printf("0x%lx, ", U4[i]); } printf("\n}\n"); #endif /* TABLES_32BIT */ #if AES_INVERSE_TEST /* * test that aes_encrypt and aes_decrypt are actually * inverses of each other */ printf("aes inverse test: "); if (aes_test_inverse() == err_status_ok) printf("passed\n"); else { printf("failed\n"); exit(1); } #endif return 0; } #endif // HIDE_AES_TABLES_MAIN #if AES_INVERSE_TEST err_status_t aes_test_inverse(void) { v128_t x, y; aes_expanded_key_t expanded_key, decrypt_key; uint8_t plaintext[16] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }; uint8_t key[16] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; v128_t k; v128_set_to_zero(&x); v128_copy_octet_string(&k, key); v128_copy_octet_string(&x, plaintext); aes_expand_encryption_key(k, expanded_key); aes_expand_decryption_key(k, decrypt_key); aes_encrypt(&x, expanded_key); aes_decrypt(&x, decrypt_key); /* compare to expected value then report */ v128_copy_octet_string(&y, plaintext); if (v128_is_eq(&x, &y)) return err_status_ok; return err_status_algo_fail; } #endif