Skip to content
Snippets Groups Projects
rijndael.c 17.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • Rafael Sevilla's avatar
    Rafael Sevilla committed
    /* rijndael - An implementation of the Rijndael cipher.
    
    Rafael Sevilla's avatar
    Rafael Sevilla committed
     * Copyright (C) 2000 Rafael R. Sevilla <dido@pacific.net.ph>
     *
     * This library is free software; you can redistribute it and/or
     * modify it under the terms of the GNU Library 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 <assert.h>
    #include <stdio.h>
    
    Rafael Sevilla's avatar
    Rafael Sevilla committed
    #include <stdlib.h>
    #include <string.h>
    
    /* These tables combine both the S-boxes and the mixcolumn transformation, so
       that we can perform a round's encryption or by means of four table lookups
       and four XOR's per column of state.  They were generated by the
       makertbls.pl script. */
    
    static const UINT32 dtbl[] = {
    
    Rafael Sevilla's avatar
    Rafael Sevilla committed
      0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 
      0x0df2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, 
      0x50303060, 0x03010102, 0xa96767ce, 0x7d2b2b56, 
      0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec, 
      0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa, 
      0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb, 
      0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, 
      0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b, 
      0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c, 
      0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83, 
      0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9, 
      0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a, 
      0x0c040408, 0x52c7c795, 0x65232346, 0x5ec3c39d, 
      0x28181830, 0xa1969637, 0x0f05050a, 0xb59a9a2f, 
      0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df, 
      0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, 
      0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34, 
      0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b, 
      0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d, 
      0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413, 
      0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1, 
      0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, 
      0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972, 
      0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85, 
      0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed, 
      0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, 
      0xcf45458a, 0x10f9f9e9, 0x06020204, 0x817f7ffe, 
      0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b, 
      0xf35151a2, 0xfea3a35d, 0xc0404080, 0x8a8f8f05, 
      0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1, 
      0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, 
      0x30101020, 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf, 
      0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3, 
      0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e, 
      0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a, 
      0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, 
      0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3, 
      0x66222244, 0x7e2a2a54, 0xab90903b, 0x8388880b, 
      0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428, 
      0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad, 
      0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, 
      0xdb494992, 0x0a06060c, 0x6c242448, 0xe45c5cb8, 
      0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4, 
      0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2, 
      0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda, 
      0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, 
      0xb46c6cd8, 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf, 
      0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810, 
      0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c, 
      0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697, 
      0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, 
      0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, 
      0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc, 
      0xd8484890, 0x05030306, 0x01f6f6f7, 0x120e0e1c, 
      0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969, 
      0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, 
      0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122, 
      0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433, 
      0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9, 
      0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5, 
      0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 
      0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0, 
      0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e, 
      0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c, 
    };
    
    
    static const UINT32 itbl[] = {
    
    Rafael Sevilla's avatar
    Rafael Sevilla committed
      0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a, 
      0xcb6bab3b, 0xf1459d1f, 0xab58faac, 0x9303e34b, 
      0x55fa3020, 0xf66d76ad, 0x9176cc88, 0x254c02f5, 
      0xfcd7e54f, 0xd7cb2ac5, 0x80443526, 0x8fa362b5, 
      0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d, 
      0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b, 
      0xe75f8f03, 0x959c9215, 0xeb7a6dbf, 0xda595295, 
      0x2d83bed4, 0xd3217458, 0x2969e049, 0x44c8c98e, 
      0x6a89c275, 0x78798ef4, 0x6b3e5899, 0xdd71b927, 
      0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d, 
      0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362, 
      0xe07764b1, 0x84ae6bbb, 0x1ca081fe, 0x942b08f9, 
      0x58684870, 0x19fd458f, 0x876cde94, 0xb7f87b52, 
      0x23d373ab, 0xe2024b72, 0x578f1fe3, 0x2aab5566, 
      0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3, 
      0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed, 
      0x2b1ccf8a, 0x92b479a7, 0xf0f207f3, 0xa1e2694e, 
      0xcdf4da65, 0xd5be0506, 0x1f6234d1, 0x8afea6c4, 
      0x9d532e34, 0xa055f3a2, 0x32e18a05, 0x75ebf6a4, 
      0x39ec830b, 0xaaef6040, 0x069f715e, 0x51106ebd, 
      0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d, 
      0xb58d5491, 0x055dc471, 0x6fd40604, 0xff155060, 
      0x24fb9819, 0x97e9bdd6, 0xcc434089, 0x779ed967, 
      0xbd42e8b0, 0x888b8907, 0x385b19e7, 0xdbeec879, 
      0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000, 
      0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c, 
      0xfbff0efd, 0x5638850f, 0x1ed5ae3d, 0x27392d36, 
      0x64d90f0a, 0x21a65c68, 0xd1545b9b, 0x3a2e3624, 
      0xb1670a0c, 0x0fe75793, 0xd296eeb4, 0x9e919b1b, 
      0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c, 
      0x0aba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12, 
      0x0b0d090e, 0xadc78bf2, 0xb9a8b62d, 0xc8a91e14, 
      0x8519f157, 0x4c0775af, 0xbbdd99ee, 0xfd607fa3, 
      0x9f2601f7, 0xbcf5725c, 0xc53b6644, 0x347efb5b, 
      0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8, 
      0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684, 
      0x7d244a85, 0xf83dbbd2, 0x1132f9ae, 0x6da129c7, 
      0x4b2f9e1d, 0xf330b2dc, 0xec52860d, 0xd0e3c177, 
      0x6c16b32b, 0x99b970a9, 0xfa489411, 0x2264e947, 
      0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322, 
      0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498, 
      0xcf81f5a6, 0x28de7aa5, 0x268eb7da, 0xa4bfad3f, 
      0xe49d3a2c, 0x0d927850, 0x9bcc5f6a, 0x62467e54, 
      0xc2138df6, 0xe8b8d890, 0x5ef7392e, 0xf5afc382, 
      0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf, 
      0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb, 
      0x097826cd, 0xf418596e, 0x01b79aec, 0xa89a4f83, 
      0x656e95e6, 0x7ee6ffaa, 0x08cfbc21, 0xe6e815ef, 
      0xd99be7ba, 0xce366f4a, 0xd4099fea, 0xd67cb029, 
      0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235, 
      0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733, 
      0x4a9804f1, 0xf7daec41, 0x0e50cd7f, 0x2ff69117, 
      0x8dd64d76, 0x4db0ef43, 0x544daacc, 0xdf0496e4, 
      0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1, 0x7f516546, 
      0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb, 
      0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d, 
      0x8c61d79a, 0x7a0ca137, 0x8e14f859, 0x893c13eb, 
      0xee27a9ce, 0x35c961b7, 0xede51ce1, 0x3cb1477a, 
      0x59dfd29c, 0x3f73f255, 0x79ce1418, 0xbf37c773, 
      0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478, 
      0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2, 
      0x72c31d16, 0x0c25e2bc, 0x8b493c28, 0x41950dff, 
      0x7101a839, 0xdeb30c08, 0x9ce4b4d8, 0x90c15664, 
      0x6184cb7b, 0x70b632d5, 0x745c6c48, 0x4257b8d0, 
    };
    
    
    /* Needed only for the key schedule and for final rounds */
    
    static const UINT8 sbox[256] = {
    
    Rafael Sevilla's avatar
    Rafael Sevilla committed
      99, 124, 119, 123, 242, 107, 111, 197,  48,   1, 103,  43, 254, 215, 171,
      118, 202, 130, 201, 125, 250,  89,  71, 240, 173, 212, 162, 175, 156, 164,
      114, 192, 183, 253, 147,  38,  54,  63, 247, 204,  52, 165, 229, 241, 113,
      216,  49,  21,  4, 199,  35, 195,  24, 150,   5, 154,   7,  18, 128, 226,
      235,  39, 178, 117,  9, 131,  44,  26,  27, 110,  90, 160,  82,  59, 214,
      179,  41, 227,  47, 132, 83, 209,   0, 237,  32, 252, 177,  91, 106, 203,
      190,  57,  74,  76,  88, 207, 208, 239, 170, 251,  67,  77,  51, 133,  69,
      249,   2, 127,  80,  60, 159, 168, 81, 163,  64, 143, 146, 157,  56, 245,
      188, 182, 218,  33,  16, 255, 243, 210, 205,  12,  19, 236,  95, 151,  68,
      23, 196, 167, 126,  61, 100,  93,  25, 115, 96, 129,  79, 220,  34,  42,
      144, 136,  70, 238, 184,  20, 222,  94,  11, 219, 224,  50,  58,  10,  73,
      6,  36,  92, 194, 211, 172,  98, 145, 149, 228, 121, 231, 200,  55, 109, 
      141, 213,  78, 169, 108,  86, 244, 234, 101, 122, 174,   8, 186, 120,  37,
      46,  28, 166, 180, 198, 232, 221, 116,  31,  75, 189, 139, 138, 112,  62,
      181, 102,  72,   3, 246,  14,  97,  53,  87, 185, 134, 193,  29, 158, 225,
      248, 152,  17, 105, 217, 142, 148, 155,  30, 135, 233, 206,  85,  40, 223, 
      140, 161, 137,  13, 191, 230,  66, 104,  65, 153,  45,  15, 176,  84, 187,
      22, 
    };
    
    
    static const UINT8 isbox[256] = {
    
    Rafael Sevilla's avatar
    Rafael Sevilla committed
      82,   9, 106, 213,  48,  54, 165,  56, 191,  64, 163, 158, 129, 243, 215,
      251, 124, 227,  57, 130, 155,  47, 255, 135,  52, 142,  67,  68, 196, 222,
      233, 203, 84, 123, 148,  50, 166, 194,  35,  61, 238,  76, 149,  11,  66,
      250, 195,  78,  8,  46, 161, 102,  40, 217,  36, 178, 118,  91, 162,  73,
      109, 139, 209,  37, 114, 248, 246, 100, 134, 104, 152,  22, 212, 164,  92,
      204,  93, 101, 182, 146, 108, 112,  72,  80, 253, 237, 185, 218,  94,  21,
      70,  87, 167, 141, 157, 132, 144, 216, 171,   0, 140, 188, 211,  10, 247,
      228,  88,   5, 184, 179,  69,   6, 208,  44,  30, 143, 202,  63,  15,   2,
      193, 175, 189,   3,   1,  19, 138, 107,  58, 145,  17,  65,  79, 103, 220,
      234, 151, 242, 207, 206, 240, 180, 230, 115, 150, 172, 116,  34, 231, 173,
      53, 133, 226, 249,  55, 232,  28, 117, 223, 110,  71, 241,  26, 113,  29,
      41, 197, 137, 111, 183,  98,  14, 170,  24, 190,  27, 252,  86,  62,  75,
      198, 210, 121,  32, 154, 219, 192, 254, 120, 205,  90, 244,  31, 221, 168,
      51, 136,   7, 199,  49, 177,  18,  16,  89,  39, 128, 236,  95,  96,  81,
      127, 169,  25, 181,  74,  13,  45, 229, 122, 159, 147, 201, 156, 239, 160,
      224,  59,  77, 174,  42, 245, 176, 200, 235, 187,  60, 131,  83, 153,  97,
      23,  43,   4, 126, 186, 119, 214,  38, 225, 105,  20,  99,  85,  33,  12,
      125, 
    };
    
    /* Used only by the key schedule */
    
    static const UINT8 Logtable[256] = {
    
    Rafael Sevilla's avatar
    Rafael Sevilla committed
      0,   0,  25,   1,  50,   2,  26, 198,  75, 199,  27, 104,  51, 238, 223,  3,
      100,   4, 224,  14,  52, 141, 129, 239,  76, 113,   8, 200, 248, 105,  28,
      193, 125, 194,  29, 181, 249, 185,  39, 106,  77, 228, 166, 114, 154, 201,
      9, 120, 101,  47, 138,   5,  33,  15, 225,  36,  18, 240, 130,  69,  53,
      147, 218, 142, 150, 143, 219, 189,  54, 208, 206, 148,  19,  92, 210, 241,
      64,  70, 131,  56, 102, 221, 253,  48, 191,   6, 139,  98, 179,  37, 226,
      152,  34, 136, 145,  16, 126, 110,  72, 195, 163, 182,  30,  66,  58, 107,
      40,  84, 250, 133,  61, 186, 43, 121,  10,  21, 155, 159,  94, 202,  78,
      212, 172, 229, 243, 115, 167,  87, 175,  88, 168,  80, 244, 234, 214, 116,
      79, 174, 233, 213, 231, 230, 173, 232, 44, 215, 117, 122, 235,  22,  11,
      245,  89, 203,  95, 176, 156, 169,  81, 160, 127,  12, 246, 111,  23, 196,
      73, 236, 216,  67,  31,  45, 164, 118, 123, 183, 204, 187,  62,  90, 251,
      96, 177, 134,  59,  82, 161, 108, 170,  85,  41, 157, 151, 178, 135, 144,
      97, 190, 220, 252, 188, 149, 207, 205,  55,  63,  91, 209, 83,  57, 132,
      60,  65, 162, 109,  71,  20,  42, 158,  93,  86, 242, 211, 171, 68,  17,
      146, 217,  35,  32,  46, 137, 180, 124, 184,  38, 119, 153, 227, 165, 103,  
      74, 237, 222, 197,  49, 254,  24,  13,  99, 140, 128, 192, 247, 112,   7, 
    };
    
    
    static const UINT8 Alogtable[256] = {
    
    Rafael Sevilla's avatar
    Rafael Sevilla committed
      1,   3,   5,  15,  17,  51,  85, 255,  26,  46, 114, 150, 161, 248,  19, 
      53, 95, 225,  56,  72, 216, 115, 149, 164, 247,   2,   6,  10,  30,  34,
      102, 170, 229,  52,  92, 228,  55,  89, 235,  38, 106, 190, 217, 112, 144,
      171, 230,  49,  83, 245,   4,  12,  20,  60,  68, 204,  79, 209, 104, 184,
      211, 110, 178, 205,  76, 212, 103, 169, 224,  59,  77, 215,  98, 166, 241,
      8,  24,  40, 120, 136, 131, 158, 185, 208, 107, 189, 220, 127, 129, 152,
      179, 206,  73, 219, 118, 154, 181, 196,  87, 249,  16,  48,  80, 240,  11,
      29,  39, 105, 187, 214,  97, 163, 254,  25,  43, 125, 135, 146, 173, 236,
      47, 113, 147, 174, 233,  32,  96, 160, 251,  22,  58,  78, 210, 109, 183,
      194,  93, 231,  50,  86, 250,  21,  63,  65, 195,  94, 226,  61,  71, 201,
      64, 192,  91, 237,  44, 116, 156, 191, 218, 117, 159, 186, 213, 100, 172,
      239,  42, 126, 130, 157, 188, 223, 122, 142, 137, 128, 155, 182, 193,  88,
      232,  35, 101, 175, 234,  37, 111, 177, 200,  67, 197,  84, 252,  31,  33,
      99, 165, 244,   7,   9,  27,  45, 119, 153, 176, 203,  70, 202,  69, 207,
      74, 222, 121, 139, 134, 145, 168, 227,  62,  66, 198,  81, 243,  14,  18,
      54,  90, 238,  41, 123, 141, 140, 143, 138, 133, 148, 167, 242,  13,  23,
      57,  75, 221, 124, 132, 151, 162, 253,  28,  36, 108, 180, 199,  82, 246, 1, 
    };
    
    #define ROTBYTE(x) (((x) >> 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 */
    
    Rafael Sevilla's avatar
    Rafael Sevilla committed
        nk = 4;
        nr = 10;
      }
    
      lastkey = (RIJNDAEL_BLOCKSIZE/4) * (nr + 1);
      ctx->nrounds = nr;
      rcon = 1;
      for (i=0; i<nk; i++) {
        ctx->keys[i] = key[i*4] + (key[i*4+1]<<8) + (key[i*4+2]<<16) +
          (key[i*4+3]<<24);
      }
    
      for (i=nk; i<lastkey; i++) {
        temp = ctx->keys[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; i<lastkey-4; i+=4)
        inv_mix_column(&(ctx->keys[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 const int idx[4][4] = {
    
    Rafael Sevilla's avatar
    Rafael Sevilla committed
      { 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; r<ctx->nrounds; 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]]) & (0xff << 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 const int iidx[4][4] = {
    
    Rafael Sevilla's avatar
    Rafael Sevilla committed
      { 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]]) & (0xff << 24);
        t[j] = e;
      }
      for (j=0; j<4; j++)
        t[j] = SUBBYTE(t[j], isbox);
      key_addition32to8(t, &(ctx->ikeys[0]), plaintext);
    }