Back to index

lightning-sunbird  0.9+nobinonly
rijndael.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 /* $Id: rijndael.c,v 1.20 2005/08/09 03:09:38 nelsonb%netscape.com Exp $ */
00037 
00038 #include "prinit.h"
00039 #include "prerr.h"
00040 #include "secerr.h"
00041 
00042 #include "prtypes.h"
00043 #include "blapi.h"
00044 #include "rijndael.h"
00045 
00046 /*
00047  * There are currently five ways to build this code, varying in performance
00048  * and code size.
00049  *
00050  * RIJNDAEL_INCLUDE_TABLES         Include all tables from rijndael32.tab
00051  * RIJNDAEL_GENERATE_TABLES        Generate tables on first 
00052  *                                 encryption/decryption, then store them;
00053  *                                 use the function gfm
00054  * RIJNDAEL_GENERATE_TABLES_MACRO  Same as above, but use macros to do
00055  *                                 the generation
00056  * RIJNDAEL_GENERATE_VALUES        Do not store tables, generate the table
00057  *                                 values "on-the-fly", using gfm
00058  * RIJNDAEL_GENERATE_VALUES_MACRO  Same as above, but use macros
00059  *
00060  * The default is RIJNDAEL_INCLUDE_TABLES.
00061  */
00062 
00063 /*
00064  * When building RIJNDAEL_INCLUDE_TABLES, includes S**-1, Rcon, T[0..4], 
00065  *                                                 T**-1[0..4], IMXC[0..4]
00066  * When building anything else, includes S, S**-1, Rcon
00067  */
00068 #include "rijndael32.tab"
00069 
00070 #if defined(RIJNDAEL_INCLUDE_TABLES)
00071 /*
00072  * RIJNDAEL_INCLUDE_TABLES
00073  */
00074 #define T0(i)    _T0[i]
00075 #define T1(i)    _T1[i]
00076 #define T2(i)    _T2[i]
00077 #define T3(i)    _T3[i]
00078 #define TInv0(i) _TInv0[i]
00079 #define TInv1(i) _TInv1[i]
00080 #define TInv2(i) _TInv2[i]
00081 #define TInv3(i) _TInv3[i]
00082 #define IMXC0(b) _IMXC0[b]
00083 #define IMXC1(b) _IMXC1[b]
00084 #define IMXC2(b) _IMXC2[b]
00085 #define IMXC3(b) _IMXC3[b]
00086 /* The S-box can be recovered from the T-tables */
00087 #ifdef IS_LITTLE_ENDIAN
00088 #define SBOX(b)    ((PRUint8)_T3[b])
00089 #else
00090 #define SBOX(b)    ((PRUint8)_T1[b])
00091 #endif
00092 #define SINV(b) (_SInv[b])
00093 
00094 #else /* not RIJNDAEL_INCLUDE_TABLES */
00095 
00096 /*
00097  * Code for generating T-table values.
00098  */
00099 
00100 #ifdef IS_LITTLE_ENDIAN
00101 #define WORD4(b0, b1, b2, b3) \
00102     (((b3) << 24) | ((b2) << 16) | ((b1) << 8) | (b0))
00103 #else
00104 #define WORD4(b0, b1, b2, b3) \
00105     (((b0) << 24) | ((b1) << 16) | ((b2) << 8) | (b3))
00106 #endif
00107 
00108 /*
00109  * Define the S and S**-1 tables (both have been stored)
00110  */
00111 #define SBOX(b)    (_S[b])
00112 #define SINV(b) (_SInv[b])
00113 
00114 /*
00115  * The function xtime, used for Galois field multiplication
00116  */
00117 #define XTIME(a) \
00118     ((a & 0x80) ? ((a << 1) ^ 0x1b) : (a << 1))
00119 
00120 /* Choose GFM method (macros or function) */
00121 #if defined(RIJNDAEL_GENERATE_TABLES_MACRO) ||  \
00122     defined(RIJNDAEL_GENERATE_VALUES_MACRO)
00123 
00124 /*
00125  * Galois field GF(2**8) multipliers, in macro form
00126  */
00127 #define GFM01(a) \
00128     (a)                                 /* a * 01 = a, the identity */
00129 #define GFM02(a) \
00130     (XTIME(a) & 0xff)                   /* a * 02 = xtime(a) */
00131 #define GFM04(a) \
00132     (GFM02(GFM02(a)))                   /* a * 04 = xtime**2(a) */
00133 #define GFM08(a) \
00134     (GFM02(GFM04(a)))                   /* a * 08 = xtime**3(a) */
00135 #define GFM03(a) \
00136     (GFM01(a) ^ GFM02(a))               /* a * 03 = a * (01 + 02) */
00137 #define GFM09(a) \
00138     (GFM01(a) ^ GFM08(a))               /* a * 09 = a * (01 + 08) */
00139 #define GFM0B(a) \
00140     (GFM01(a) ^ GFM02(a) ^ GFM08(a))    /* a * 0B = a * (01 + 02 + 08) */
00141 #define GFM0D(a) \
00142     (GFM01(a) ^ GFM04(a) ^ GFM08(a))    /* a * 0D = a * (01 + 04 + 08) */
00143 #define GFM0E(a) \
00144     (GFM02(a) ^ GFM04(a) ^ GFM08(a))    /* a * 0E = a * (02 + 04 + 08) */
00145 
00146 #else  /* RIJNDAEL_GENERATE_TABLES or RIJNDAEL_GENERATE_VALUES */
00147 
00148 /* GF_MULTIPLY
00149  *
00150  * multiply two bytes represented in GF(2**8), mod (x**4 + 1)
00151  */
00152 PRUint8 gfm(PRUint8 a, PRUint8 b)
00153 {
00154     PRUint8 res = 0;
00155     while (b > 0) {
00156        res = (b & 0x01) ? res ^ a : res;
00157        a = XTIME(a);
00158        b >>= 1;
00159     }
00160     return res;
00161 }
00162 
00163 #define GFM01(a) \
00164     (a)                                 /* a * 01 = a, the identity */
00165 #define GFM02(a) \
00166     (XTIME(a) & 0xff)                   /* a * 02 = xtime(a) */
00167 #define GFM03(a) \
00168     (gfm(a, 0x03))                      /* a * 03 */
00169 #define GFM09(a) \
00170     (gfm(a, 0x09))                      /* a * 09 */
00171 #define GFM0B(a) \
00172     (gfm(a, 0x0B))                      /* a * 0B */
00173 #define GFM0D(a) \
00174     (gfm(a, 0x0D))                      /* a * 0D */
00175 #define GFM0E(a) \
00176     (gfm(a, 0x0E))                      /* a * 0E */
00177 
00178 #endif /* choosing GFM function */
00179 
00180 /*
00181  * The T-tables
00182  */
00183 #define G_T0(i) \
00184     ( WORD4( GFM02(SBOX(i)), GFM01(SBOX(i)), GFM01(SBOX(i)), GFM03(SBOX(i)) ) )
00185 #define G_T1(i) \
00186     ( WORD4( GFM03(SBOX(i)), GFM02(SBOX(i)), GFM01(SBOX(i)), GFM01(SBOX(i)) ) )
00187 #define G_T2(i) \
00188     ( WORD4( GFM01(SBOX(i)), GFM03(SBOX(i)), GFM02(SBOX(i)), GFM01(SBOX(i)) ) )
00189 #define G_T3(i) \
00190     ( WORD4( GFM01(SBOX(i)), GFM01(SBOX(i)), GFM03(SBOX(i)), GFM02(SBOX(i)) ) )
00191 
00192 /*
00193  * The inverse T-tables
00194  */
00195 #define G_TInv0(i) \
00196     ( WORD4( GFM0E(SINV(i)), GFM09(SINV(i)), GFM0D(SINV(i)), GFM0B(SINV(i)) ) )
00197 #define G_TInv1(i) \
00198     ( WORD4( GFM0B(SINV(i)), GFM0E(SINV(i)), GFM09(SINV(i)), GFM0D(SINV(i)) ) )
00199 #define G_TInv2(i) \
00200     ( WORD4( GFM0D(SINV(i)), GFM0B(SINV(i)), GFM0E(SINV(i)), GFM09(SINV(i)) ) )
00201 #define G_TInv3(i) \
00202     ( WORD4( GFM09(SINV(i)), GFM0D(SINV(i)), GFM0B(SINV(i)), GFM0E(SINV(i)) ) )
00203 
00204 /*
00205  * The inverse mix column tables
00206  */
00207 #define G_IMXC0(i) \
00208     ( WORD4( GFM0E(i), GFM09(i), GFM0D(i), GFM0B(i) ) )
00209 #define G_IMXC1(i) \
00210     ( WORD4( GFM0B(i), GFM0E(i), GFM09(i), GFM0D(i) ) )
00211 #define G_IMXC2(i) \
00212     ( WORD4( GFM0D(i), GFM0B(i), GFM0E(i), GFM09(i) ) )
00213 #define G_IMXC3(i) \
00214     ( WORD4( GFM09(i), GFM0D(i), GFM0B(i), GFM0E(i) ) )
00215 
00216 /* Now choose the T-table indexing method */
00217 #if defined(RIJNDAEL_GENERATE_VALUES)
00218 /* generate values for the tables with a function*/
00219 static PRUint32 gen_TInvXi(PRUint8 tx, PRUint8 i)
00220 {
00221     PRUint8 si01, si02, si03, si04, si08, si09, si0B, si0D, si0E;
00222     si01 = SINV(i);
00223     si02 = XTIME(si01);
00224     si04 = XTIME(si02);
00225     si08 = XTIME(si04);
00226     si03 = si02 ^ si01;
00227     si09 = si08 ^ si01;
00228     si0B = si08 ^ si03;
00229     si0D = si09 ^ si04;
00230     si0E = si08 ^ si04 ^ si02;
00231     switch (tx) {
00232     case 0:
00233        return WORD4(si0E, si09, si0D, si0B);
00234     case 1:
00235        return WORD4(si0B, si0E, si09, si0D);
00236     case 2:
00237        return WORD4(si0D, si0B, si0E, si09);
00238     case 3:
00239        return WORD4(si09, si0D, si0B, si0E);
00240     }
00241     return -1;
00242 }
00243 #define T0(i)    G_T0(i)
00244 #define T1(i)    G_T1(i)
00245 #define T2(i)    G_T2(i)
00246 #define T3(i)    G_T3(i)
00247 #define TInv0(i) gen_TInvXi(0, i)
00248 #define TInv1(i) gen_TInvXi(1, i)
00249 #define TInv2(i) gen_TInvXi(2, i)
00250 #define TInv3(i) gen_TInvXi(3, i)
00251 #define IMXC0(b) G_IMXC0(b)
00252 #define IMXC1(b) G_IMXC1(b)
00253 #define IMXC2(b) G_IMXC2(b)
00254 #define IMXC3(b) G_IMXC3(b)
00255 #elif defined(RIJNDAEL_GENERATE_VALUES_MACRO)
00256 /* generate values for the tables with macros */
00257 #define T0(i)    G_T0(i)
00258 #define T1(i)    G_T1(i)
00259 #define T2(i)    G_T2(i)
00260 #define T3(i)    G_T3(i)
00261 #define TInv0(i) G_TInv0(i)
00262 #define TInv1(i) G_TInv1(i)
00263 #define TInv2(i) G_TInv2(i)
00264 #define TInv3(i) G_TInv3(i)
00265 #define IMXC0(b) G_IMXC0(b)
00266 #define IMXC1(b) G_IMXC1(b)
00267 #define IMXC2(b) G_IMXC2(b)
00268 #define IMXC3(b) G_IMXC3(b)
00269 #else  /* RIJNDAEL_GENERATE_TABLES or RIJNDAEL_GENERATE_TABLES_MACRO */
00270 /* Generate T and T**-1 table values and store, then index */
00271 /* The inverse mix column tables are still generated */
00272 #define T0(i)    rijndaelTables->T0[i]
00273 #define T1(i)    rijndaelTables->T1[i]
00274 #define T2(i)    rijndaelTables->T2[i]
00275 #define T3(i)    rijndaelTables->T3[i]
00276 #define TInv0(i) rijndaelTables->TInv0[i]
00277 #define TInv1(i) rijndaelTables->TInv1[i]
00278 #define TInv2(i) rijndaelTables->TInv2[i]
00279 #define TInv3(i) rijndaelTables->TInv3[i]
00280 #define IMXC0(b) G_IMXC0(b)
00281 #define IMXC1(b) G_IMXC1(b)
00282 #define IMXC2(b) G_IMXC2(b)
00283 #define IMXC3(b) G_IMXC3(b)
00284 #endif /* choose T-table indexing method */
00285 
00286 #endif /* not RIJNDAEL_INCLUDE_TABLES */
00287 
00288 #if defined(RIJNDAEL_GENERATE_TABLES) ||  \
00289     defined(RIJNDAEL_GENERATE_TABLES_MACRO)
00290 
00291 /* Code to generate and store the tables */
00292 
00293 struct rijndael_tables_str {
00294     PRUint32 T0[256];
00295     PRUint32 T1[256];
00296     PRUint32 T2[256];
00297     PRUint32 T3[256];
00298     PRUint32 TInv0[256];
00299     PRUint32 TInv1[256];
00300     PRUint32 TInv2[256];
00301     PRUint32 TInv3[256];
00302 };
00303 
00304 static struct rijndael_tables_str *rijndaelTables = NULL;
00305 static PRCallOnceType coRTInit = { 0, 0, 0 };
00306 static PRStatus 
00307 init_rijndael_tables(void)
00308 {
00309     PRUint32 i;
00310     PRUint8 si01, si02, si03, si04, si08, si09, si0B, si0D, si0E;
00311     struct rijndael_tables_str *rts;
00312     rts = (struct rijndael_tables_str *)
00313                    PORT_Alloc(sizeof(struct rijndael_tables_str));
00314     if (!rts) return PR_FAILURE;
00315     for (i=0; i<256; i++) {
00316        /* The forward values */
00317        si01 = SBOX(i);
00318        si02 = XTIME(si01);
00319        si03 = si02 ^ si01;
00320        rts->T0[i] = WORD4(si02, si01, si01, si03);
00321        rts->T1[i] = WORD4(si03, si02, si01, si01);
00322        rts->T2[i] = WORD4(si01, si03, si02, si01);
00323        rts->T3[i] = WORD4(si01, si01, si03, si02);
00324        /* The inverse values */
00325        si01 = SINV(i);
00326        si02 = XTIME(si01);
00327        si04 = XTIME(si02);
00328        si08 = XTIME(si04);
00329        si03 = si02 ^ si01;
00330        si09 = si08 ^ si01;
00331        si0B = si08 ^ si03;
00332        si0D = si09 ^ si04;
00333        si0E = si08 ^ si04 ^ si02;
00334        rts->TInv0[i] = WORD4(si0E, si09, si0D, si0B);
00335        rts->TInv1[i] = WORD4(si0B, si0E, si09, si0D);
00336        rts->TInv2[i] = WORD4(si0D, si0B, si0E, si09);
00337        rts->TInv3[i] = WORD4(si09, si0D, si0B, si0E);
00338     }
00339     /* wait until all the values are in to set */
00340     rijndaelTables = rts;
00341     return PR_SUCCESS;
00342 }
00343 
00344 #endif /* code to generate tables */
00345 
00346 /**************************************************************************
00347  *
00348  * Stuff related to the Rijndael key schedule
00349  *
00350  *************************************************************************/
00351 
00352 #define SUBBYTE(w) \
00353     ((SBOX((w >> 24) & 0xff) << 24) | \
00354      (SBOX((w >> 16) & 0xff) << 16) | \
00355      (SBOX((w >>  8) & 0xff) <<  8) | \
00356      (SBOX((w      ) & 0xff)         ))
00357 
00358 #ifdef IS_LITTLE_ENDIAN
00359 #define ROTBYTE(b) \
00360     ((b >> 8) | (b << 24))
00361 #else
00362 #define ROTBYTE(b) \
00363     ((b << 8) | (b >> 24))
00364 #endif
00365 
00366 /* rijndael_key_expansion7
00367  *
00368  * Generate the expanded key from the key input by the user.
00369  * XXX
00370  * Nk == 7 (224 key bits) is a weird case.  Since Nk > 6, an added SubByte
00371  * transformation is done periodically.  The period is every 4 bytes, and
00372  * since 7%4 != 0 this happens at different times for each key word (unlike
00373  * Nk == 8 where it happens twice in every key word, in the same positions).
00374  * For now, I'm implementing this case "dumbly", w/o any unrolling.
00375  */
00376 static SECStatus
00377 rijndael_key_expansion7(AESContext *cx, const unsigned char *key, unsigned int Nk)
00378 {
00379     unsigned int i;
00380     PRUint32 *W;
00381     PRUint32 *pW;
00382     PRUint32 tmp;
00383     W = cx->expandedKey;
00384     /* 1.  the first Nk words contain the cipher key */
00385     memcpy(W, key, Nk * 4);
00386     i = Nk;
00387     /* 2.  loop until full expanded key is obtained */
00388     pW = W + i - 1;
00389     for (; i < cx->Nb * (cx->Nr + 1); ++i) {
00390        tmp = *pW++;
00391        if (i % Nk == 0)
00392            tmp = SUBBYTE(ROTBYTE(tmp)) ^ Rcon[i / Nk - 1];
00393        else if (i % Nk == 4)
00394            tmp = SUBBYTE(tmp);
00395        *pW = W[i - Nk] ^ tmp;
00396     }
00397     return SECSuccess;
00398 }
00399 
00400 /* rijndael_key_expansion
00401  *
00402  * Generate the expanded key from the key input by the user.
00403  */
00404 static SECStatus
00405 rijndael_key_expansion(AESContext *cx, const unsigned char *key, unsigned int Nk)
00406 {
00407     unsigned int i;
00408     PRUint32 *W;
00409     PRUint32 *pW;
00410     PRUint32 tmp;
00411     unsigned int round_key_words = cx->Nb * (cx->Nr + 1);
00412     if (Nk == 7)
00413        return rijndael_key_expansion7(cx, key, Nk);
00414     W = cx->expandedKey;
00415     /* The first Nk words contain the input cipher key */
00416     memcpy(W, key, Nk * 4);
00417     i = Nk;
00418     pW = W + i - 1;
00419     /* Loop over all sets of Nk words, except the last */
00420     while (i < round_key_words - Nk) {
00421        tmp = *pW++;
00422        tmp = SUBBYTE(ROTBYTE(tmp)) ^ Rcon[i / Nk - 1];
00423        *pW = W[i++ - Nk] ^ tmp;
00424        tmp = *pW++; *pW = W[i++ - Nk] ^ tmp;
00425        tmp = *pW++; *pW = W[i++ - Nk] ^ tmp;
00426        tmp = *pW++; *pW = W[i++ - Nk] ^ tmp;
00427        if (Nk == 4)
00428            continue;
00429        switch (Nk) {
00430        case 8: tmp = *pW++; tmp = SUBBYTE(tmp); *pW = W[i++ - Nk] ^ tmp;
00431        case 7: tmp = *pW++; *pW = W[i++ - Nk] ^ tmp;
00432        case 6: tmp = *pW++; *pW = W[i++ - Nk] ^ tmp;
00433        case 5: tmp = *pW++; *pW = W[i++ - Nk] ^ tmp;
00434        }
00435     }
00436     /* Generate the last word */
00437     tmp = *pW++;
00438     tmp = SUBBYTE(ROTBYTE(tmp)) ^ Rcon[i / Nk - 1];
00439     *pW = W[i++ - Nk] ^ tmp;
00440     /* There may be overflow here, if Nk % (Nb * (Nr + 1)) > 0.  However,
00441      * since the above loop generated all but the last Nk key words, there
00442      * is no more need for the SubByte transformation.
00443      */
00444     if (Nk < 8) {
00445        for (; i < round_key_words; ++i) {
00446            tmp = *pW++; 
00447            *pW = W[i - Nk] ^ tmp;
00448        }
00449     } else {
00450        /* except in the case when Nk == 8.  Then one more SubByte may have
00451         * to be performed, at i % Nk == 4.
00452         */
00453        for (; i < round_key_words; ++i) {
00454            tmp = *pW++;
00455            if (i % Nk == 4)
00456               tmp = SUBBYTE(tmp);
00457            *pW = W[i - Nk] ^ tmp;
00458        }
00459     }
00460     return SECSuccess;
00461 }
00462 
00463 /* rijndael_invkey_expansion
00464  *
00465  * Generate the expanded key for the inverse cipher from the key input by 
00466  * the user.
00467  */
00468 static SECStatus
00469 rijndael_invkey_expansion(AESContext *cx, const unsigned char *key, unsigned int Nk)
00470 {
00471     unsigned int r;
00472     PRUint32 *roundkeyw;
00473     PRUint8 *b;
00474     int Nb = cx->Nb;
00475     /* begins like usual key expansion ... */
00476     if (rijndael_key_expansion(cx, key, Nk) != SECSuccess)
00477        return SECFailure;
00478     /* ... but has the additional step of InvMixColumn,
00479      * excepting the first and last round keys.
00480      */
00481     roundkeyw = cx->expandedKey + cx->Nb;
00482     for (r=1; r<cx->Nr; ++r) {
00483        /* each key word, roundkeyw, represents a column in the key
00484         * matrix.  Each column is multiplied by the InvMixColumn matrix.
00485         *   [ 0E 0B 0D 09 ]   [ b0 ]
00486         *   [ 09 0E 0B 0D ] * [ b1 ]
00487         *   [ 0D 09 0E 0B ]   [ b2 ]
00488         *   [ 0B 0D 09 0E ]   [ b3 ]
00489         */
00490        b = (PRUint8 *)roundkeyw;
00491        *roundkeyw++ = IMXC0(b[0]) ^ IMXC1(b[1]) ^ IMXC2(b[2]) ^ IMXC3(b[3]);
00492        b = (PRUint8 *)roundkeyw;
00493        *roundkeyw++ = IMXC0(b[0]) ^ IMXC1(b[1]) ^ IMXC2(b[2]) ^ IMXC3(b[3]);
00494        b = (PRUint8 *)roundkeyw;
00495        *roundkeyw++ = IMXC0(b[0]) ^ IMXC1(b[1]) ^ IMXC2(b[2]) ^ IMXC3(b[3]);
00496        b = (PRUint8 *)roundkeyw;
00497        *roundkeyw++ = IMXC0(b[0]) ^ IMXC1(b[1]) ^ IMXC2(b[2]) ^ IMXC3(b[3]);
00498        if (Nb <= 4)
00499            continue;
00500        switch (Nb) {
00501        case 8: b = (PRUint8 *)roundkeyw;
00502                *roundkeyw++ = IMXC0(b[0]) ^ IMXC1(b[1]) ^ 
00503                               IMXC2(b[2]) ^ IMXC3(b[3]);
00504        case 7: b = (PRUint8 *)roundkeyw;
00505                *roundkeyw++ = IMXC0(b[0]) ^ IMXC1(b[1]) ^ 
00506                               IMXC2(b[2]) ^ IMXC3(b[3]);
00507        case 6: b = (PRUint8 *)roundkeyw;
00508                *roundkeyw++ = IMXC0(b[0]) ^ IMXC1(b[1]) ^ 
00509                               IMXC2(b[2]) ^ IMXC3(b[3]);
00510        case 5: b = (PRUint8 *)roundkeyw;
00511                *roundkeyw++ = IMXC0(b[0]) ^ IMXC1(b[1]) ^ 
00512                               IMXC2(b[2]) ^ IMXC3(b[3]);
00513        }
00514     }
00515     return SECSuccess;
00516 }
00517 /**************************************************************************
00518  *
00519  * Stuff related to Rijndael encryption/decryption, optimized for
00520  * a 128-bit blocksize.
00521  *
00522  *************************************************************************/
00523 
00524 #ifdef IS_LITTLE_ENDIAN
00525 #define BYTE0WORD(w) ((w) & 0x000000ff)
00526 #define BYTE1WORD(w) ((w) & 0x0000ff00)
00527 #define BYTE2WORD(w) ((w) & 0x00ff0000)
00528 #define BYTE3WORD(w) ((w) & 0xff000000)
00529 #else
00530 #define BYTE0WORD(w) ((w) & 0xff000000)
00531 #define BYTE1WORD(w) ((w) & 0x00ff0000)
00532 #define BYTE2WORD(w) ((w) & 0x0000ff00)
00533 #define BYTE3WORD(w) ((w) & 0x000000ff)
00534 #endif
00535 
00536 typedef union {
00537     PRUint32 w[4];
00538     PRUint8  b[16];
00539 } rijndael_state;
00540 
00541 #define COLUMN_0(state) state.w[0]
00542 #define COLUMN_1(state) state.w[1]
00543 #define COLUMN_2(state) state.w[2]
00544 #define COLUMN_3(state) state.w[3]
00545 
00546 #define STATE_BYTE(i) state.b[i]
00547 
00548 static SECStatus 
00549 rijndael_encryptBlock128(AESContext *cx, 
00550                          unsigned char *output,
00551                          const unsigned char *input)
00552 {
00553     unsigned int r;
00554     PRUint32 *roundkeyw;
00555     rijndael_state state;
00556     PRUint32 C0, C1, C2, C3;
00557 #if defined(_X86_)
00558 #define pIn input
00559 #define pOut output
00560 #else
00561     unsigned char *pIn, *pOut;
00562     PRUint32 inBuf[4], outBuf[4];
00563 
00564     if ((ptrdiff_t)input & 0x3) {
00565        memcpy(inBuf, input, sizeof inBuf);
00566        pIn = (unsigned char *)inBuf;
00567     } else {
00568        pIn = (unsigned char *)input;
00569     }
00570     if ((ptrdiff_t)output & 0x3) {
00571        pOut = (unsigned char *)outBuf;
00572     } else {
00573        pOut = (unsigned char *)output;
00574     }
00575 #endif
00576     roundkeyw = cx->expandedKey;
00577     /* Step 1: Add Round Key 0 to initial state */
00578     COLUMN_0(state) = *((PRUint32 *)(pIn     )) ^ *roundkeyw++;
00579     COLUMN_1(state) = *((PRUint32 *)(pIn + 4 )) ^ *roundkeyw++;
00580     COLUMN_2(state) = *((PRUint32 *)(pIn + 8 )) ^ *roundkeyw++;
00581     COLUMN_3(state) = *((PRUint32 *)(pIn + 12)) ^ *roundkeyw++;
00582     /* Step 2: Loop over rounds [1..NR-1] */
00583     for (r=1; r<cx->Nr; ++r) {
00584         /* Do ShiftRow, ByteSub, and MixColumn all at once */
00585        C0 = T0(STATE_BYTE(0))  ^
00586             T1(STATE_BYTE(5))  ^
00587             T2(STATE_BYTE(10)) ^
00588             T3(STATE_BYTE(15));
00589        C1 = T0(STATE_BYTE(4))  ^
00590             T1(STATE_BYTE(9))  ^
00591             T2(STATE_BYTE(14)) ^
00592             T3(STATE_BYTE(3));
00593        C2 = T0(STATE_BYTE(8))  ^
00594             T1(STATE_BYTE(13)) ^
00595             T2(STATE_BYTE(2))  ^
00596             T3(STATE_BYTE(7));
00597        C3 = T0(STATE_BYTE(12)) ^
00598             T1(STATE_BYTE(1))  ^
00599             T2(STATE_BYTE(6))  ^
00600             T3(STATE_BYTE(11));
00601        /* Round key addition */
00602        COLUMN_0(state) = C0 ^ *roundkeyw++;
00603        COLUMN_1(state) = C1 ^ *roundkeyw++;
00604        COLUMN_2(state) = C2 ^ *roundkeyw++;
00605        COLUMN_3(state) = C3 ^ *roundkeyw++;
00606     }
00607     /* Step 3: Do the last round */
00608     /* Final round does not employ MixColumn */
00609     C0 = ((BYTE0WORD(T2(STATE_BYTE(0))))   |
00610           (BYTE1WORD(T3(STATE_BYTE(5))))   |
00611           (BYTE2WORD(T0(STATE_BYTE(10))))  |
00612           (BYTE3WORD(T1(STATE_BYTE(15)))))  ^
00613           *roundkeyw++;
00614     C1 = ((BYTE0WORD(T2(STATE_BYTE(4))))   |
00615           (BYTE1WORD(T3(STATE_BYTE(9))))   |
00616           (BYTE2WORD(T0(STATE_BYTE(14))))  |
00617           (BYTE3WORD(T1(STATE_BYTE(3)))))   ^
00618           *roundkeyw++;
00619     C2 = ((BYTE0WORD(T2(STATE_BYTE(8))))   |
00620           (BYTE1WORD(T3(STATE_BYTE(13))))  |
00621           (BYTE2WORD(T0(STATE_BYTE(2))))   |
00622           (BYTE3WORD(T1(STATE_BYTE(7)))))   ^
00623           *roundkeyw++;
00624     C3 = ((BYTE0WORD(T2(STATE_BYTE(12))))  |
00625           (BYTE1WORD(T3(STATE_BYTE(1))))   |
00626           (BYTE2WORD(T0(STATE_BYTE(6))))   |
00627           (BYTE3WORD(T1(STATE_BYTE(11)))))  ^
00628           *roundkeyw++;
00629     *((PRUint32 *) pOut     )  = C0;
00630     *((PRUint32 *)(pOut + 4))  = C1;
00631     *((PRUint32 *)(pOut + 8))  = C2;
00632     *((PRUint32 *)(pOut + 12)) = C3;
00633 #if defined(_X86_)
00634 #undef pIn
00635 #undef pOut
00636 #else
00637     if ((ptrdiff_t)output & 0x3) {
00638        memcpy(output, outBuf, sizeof outBuf);
00639     }
00640 #endif
00641     return SECSuccess;
00642 }
00643 
00644 static SECStatus 
00645 rijndael_decryptBlock128(AESContext *cx, 
00646                          unsigned char *output,
00647                          const unsigned char *input)
00648 {
00649     int r;
00650     PRUint32 *roundkeyw;
00651     rijndael_state state;
00652     PRUint32 C0, C1, C2, C3;
00653 #if defined(_X86_)
00654 #define pIn input
00655 #define pOut output
00656 #else
00657     unsigned char *pIn, *pOut;
00658     PRUint32 inBuf[4], outBuf[4];
00659 
00660     if ((ptrdiff_t)input & 0x3) {
00661        memcpy(inBuf, input, sizeof inBuf);
00662        pIn = (unsigned char *)inBuf;
00663     } else {
00664        pIn = (unsigned char *)input;
00665     }
00666     if ((ptrdiff_t)output & 0x3) {
00667        pOut = (unsigned char *)outBuf;
00668     } else {
00669        pOut = (unsigned char *)output;
00670     }
00671 #endif
00672     roundkeyw = cx->expandedKey + cx->Nb * cx->Nr + 3;
00673     /* reverse the final key addition */
00674     COLUMN_3(state) = *((PRUint32 *)(pIn + 12)) ^ *roundkeyw--;
00675     COLUMN_2(state) = *((PRUint32 *)(pIn +  8)) ^ *roundkeyw--;
00676     COLUMN_1(state) = *((PRUint32 *)(pIn +  4)) ^ *roundkeyw--;
00677     COLUMN_0(state) = *((PRUint32 *)(pIn     )) ^ *roundkeyw--;
00678     /* Loop over rounds in reverse [NR..1] */
00679     for (r=cx->Nr; r>1; --r) {
00680        /* Invert the (InvByteSub*InvMixColumn)(InvShiftRow(state)) */
00681        C0 = TInv0(STATE_BYTE(0))  ^
00682             TInv1(STATE_BYTE(13)) ^
00683             TInv2(STATE_BYTE(10)) ^
00684             TInv3(STATE_BYTE(7));
00685        C1 = TInv0(STATE_BYTE(4))  ^
00686             TInv1(STATE_BYTE(1))  ^
00687             TInv2(STATE_BYTE(14)) ^
00688             TInv3(STATE_BYTE(11));
00689        C2 = TInv0(STATE_BYTE(8))  ^
00690             TInv1(STATE_BYTE(5))  ^
00691             TInv2(STATE_BYTE(2))  ^
00692             TInv3(STATE_BYTE(15));
00693        C3 = TInv0(STATE_BYTE(12)) ^
00694             TInv1(STATE_BYTE(9))  ^
00695             TInv2(STATE_BYTE(6))  ^
00696             TInv3(STATE_BYTE(3));
00697        /* Invert the key addition step */
00698        COLUMN_3(state) = C3 ^ *roundkeyw--;
00699        COLUMN_2(state) = C2 ^ *roundkeyw--;
00700        COLUMN_1(state) = C1 ^ *roundkeyw--;
00701        COLUMN_0(state) = C0 ^ *roundkeyw--;
00702     }
00703     /* inverse sub */
00704     pOut[ 0] = SINV(STATE_BYTE( 0));
00705     pOut[ 1] = SINV(STATE_BYTE(13));
00706     pOut[ 2] = SINV(STATE_BYTE(10));
00707     pOut[ 3] = SINV(STATE_BYTE( 7));
00708     pOut[ 4] = SINV(STATE_BYTE( 4));
00709     pOut[ 5] = SINV(STATE_BYTE( 1));
00710     pOut[ 6] = SINV(STATE_BYTE(14));
00711     pOut[ 7] = SINV(STATE_BYTE(11));
00712     pOut[ 8] = SINV(STATE_BYTE( 8));
00713     pOut[ 9] = SINV(STATE_BYTE( 5));
00714     pOut[10] = SINV(STATE_BYTE( 2));
00715     pOut[11] = SINV(STATE_BYTE(15));
00716     pOut[12] = SINV(STATE_BYTE(12));
00717     pOut[13] = SINV(STATE_BYTE( 9));
00718     pOut[14] = SINV(STATE_BYTE( 6));
00719     pOut[15] = SINV(STATE_BYTE( 3));
00720     /* final key addition */
00721     *((PRUint32 *)(pOut + 12)) ^= *roundkeyw--;
00722     *((PRUint32 *)(pOut +  8)) ^= *roundkeyw--;
00723     *((PRUint32 *)(pOut +  4)) ^= *roundkeyw--;
00724     *((PRUint32 *) pOut      ) ^= *roundkeyw--;
00725 #if defined(_X86_)
00726 #undef pIn
00727 #undef pOut
00728 #else
00729     if ((ptrdiff_t)output & 0x3) {
00730        memcpy(output, outBuf, sizeof outBuf);
00731     }
00732 #endif
00733     return SECSuccess;
00734 }
00735 
00736 /**************************************************************************
00737  *
00738  * Stuff related to general Rijndael encryption/decryption, for blocksizes
00739  * greater than 128 bits.
00740  *
00741  * XXX This code is currently untested!  So far, AES specs have only been
00742  *     released for 128 bit blocksizes.  This will be tested, but for now
00743  *     only the code above has been tested using known values.
00744  *
00745  *************************************************************************/
00746 
00747 #define COLUMN(array, j) *((PRUint32 *)(array + j))
00748 
00749 SECStatus 
00750 rijndael_encryptBlock(AESContext *cx, 
00751                       unsigned char *output,
00752                       const unsigned char *input)
00753 {
00754     return SECFailure;
00755 #ifdef rijndael_large_blocks_fixed
00756     unsigned int j, r, Nb;
00757     unsigned int c2=0, c3=0;
00758     PRUint32 *roundkeyw;
00759     PRUint8 clone[RIJNDAEL_MAX_STATE_SIZE];
00760     Nb = cx->Nb;
00761     roundkeyw = cx->expandedKey;
00762     /* Step 1: Add Round Key 0 to initial state */
00763     for (j=0; j<4*Nb; j+=4) {
00764        COLUMN(clone, j) = COLUMN(input, j) ^ *roundkeyw++;
00765     }
00766     /* Step 2: Loop over rounds [1..NR-1] */
00767     for (r=1; r<cx->Nr; ++r) {
00768        for (j=0; j<Nb; ++j) {
00769            COLUMN(output, j) = T0(STATE_BYTE(4*  j          )) ^
00770                                T1(STATE_BYTE(4*((j+ 1)%Nb)+1)) ^
00771                                T2(STATE_BYTE(4*((j+c2)%Nb)+2)) ^
00772                                T3(STATE_BYTE(4*((j+c3)%Nb)+3));
00773        }
00774        for (j=0; j<4*Nb; j+=4) {
00775            COLUMN(clone, j) = COLUMN(output, j) ^ *roundkeyw++;
00776        }
00777     }
00778     /* Step 3: Do the last round */
00779     /* Final round does not employ MixColumn */
00780     for (j=0; j<Nb; ++j) {
00781        COLUMN(output, j) = ((BYTE0WORD(T2(STATE_BYTE(4* j         ))))  |
00782                              (BYTE1WORD(T3(STATE_BYTE(4*(j+ 1)%Nb)+1)))  |
00783                              (BYTE2WORD(T0(STATE_BYTE(4*(j+c2)%Nb)+2)))  |
00784                              (BYTE3WORD(T1(STATE_BYTE(4*(j+c3)%Nb)+3)))) ^
00785                             *roundkeyw++;
00786     }
00787     return SECSuccess;
00788 #endif
00789 }
00790 
00791 SECStatus 
00792 rijndael_decryptBlock(AESContext *cx, 
00793                       unsigned char *output,
00794                       const unsigned char *input)
00795 {
00796     return SECFailure;
00797 #ifdef rijndael_large_blocks_fixed
00798     int j, r, Nb;
00799     int c2=0, c3=0;
00800     PRUint32 *roundkeyw;
00801     PRUint8 clone[RIJNDAEL_MAX_STATE_SIZE];
00802     Nb = cx->Nb;
00803     roundkeyw = cx->expandedKey + cx->Nb * cx->Nr + 3;
00804     /* reverse key addition */
00805     for (j=4*Nb; j>=0; j-=4) {
00806        COLUMN(clone, j) = COLUMN(input, j) ^ *roundkeyw--;
00807     }
00808     /* Loop over rounds in reverse [NR..1] */
00809     for (r=cx->Nr; r>1; --r) {
00810        /* Invert the (InvByteSub*InvMixColumn)(InvShiftRow(state)) */
00811        for (j=0; j<Nb; ++j) {
00812            COLUMN(output, 4*j) = TInv0(STATE_BYTE(4* j            )) ^
00813                                  TInv1(STATE_BYTE(4*(j+Nb- 1)%Nb)+1) ^
00814                                  TInv2(STATE_BYTE(4*(j+Nb-c2)%Nb)+2) ^
00815                                  TInv3(STATE_BYTE(4*(j+Nb-c3)%Nb)+3);
00816        }
00817        /* Invert the key addition step */
00818        for (j=4*Nb; j>=0; j-=4) {
00819            COLUMN(clone, j) = COLUMN(output, j) ^ *roundkeyw--;
00820        }
00821     }
00822     /* inverse sub */
00823     for (j=0; j<4*Nb; ++j) {
00824        output[j] = SINV(clone[j]);
00825     }
00826     /* final key addition */
00827     for (j=4*Nb; j>=0; j-=4) {
00828        COLUMN(output, j) ^= *roundkeyw--;
00829     }
00830     return SECSuccess;
00831 #endif
00832 }
00833 
00834 /**************************************************************************
00835  *
00836  *  Rijndael modes of operation (ECB and CBC)
00837  *
00838  *************************************************************************/
00839 
00840 static SECStatus 
00841 rijndael_encryptECB(AESContext *cx, unsigned char *output,
00842                     unsigned int *outputLen, unsigned int maxOutputLen,
00843                     const unsigned char *input, unsigned int inputLen, 
00844                     unsigned int blocksize)
00845 {
00846     SECStatus rv;
00847     AESBlockFunc *encryptor;
00848     encryptor = (blocksize == RIJNDAEL_MIN_BLOCKSIZE) 
00849                               ? &rijndael_encryptBlock128 
00850                               : &rijndael_encryptBlock;
00851     while (inputLen > 0) {
00852         rv = (*encryptor)(cx, output, input);
00853        if (rv != SECSuccess)
00854            return rv;
00855        output += blocksize;
00856        input += blocksize;
00857        inputLen -= blocksize;
00858     }
00859     return SECSuccess;
00860 }
00861 
00862 static SECStatus 
00863 rijndael_encryptCBC(AESContext *cx, unsigned char *output,
00864                     unsigned int *outputLen, unsigned int maxOutputLen,
00865                     const unsigned char *input, unsigned int inputLen, 
00866                     unsigned int blocksize)
00867 {
00868     unsigned int j;
00869     SECStatus rv;
00870     AESBlockFunc *encryptor;
00871     unsigned char *lastblock;
00872     unsigned char inblock[RIJNDAEL_MAX_STATE_SIZE * 8];
00873 
00874     if (!inputLen)
00875        return SECSuccess;
00876     lastblock = cx->iv;
00877     encryptor = (blocksize == RIJNDAEL_MIN_BLOCKSIZE) 
00878                               ? &rijndael_encryptBlock128 
00879                               : &rijndael_encryptBlock;
00880     while (inputLen > 0) {
00881        /* XOR with the last block (IV if first block) */
00882        for (j=0; j<blocksize; ++j)
00883            inblock[j] = input[j] ^ lastblock[j];
00884        /* encrypt */
00885         rv = (*encryptor)(cx, output, inblock);
00886        if (rv != SECSuccess)
00887            return rv;
00888        /* move to the next block */
00889        lastblock = output;
00890        output += blocksize;
00891        input += blocksize;
00892        inputLen -= blocksize;
00893     }
00894     memcpy(cx->iv, lastblock, blocksize);
00895     return SECSuccess;
00896 }
00897 
00898 static SECStatus 
00899 rijndael_decryptECB(AESContext *cx, unsigned char *output,
00900                     unsigned int *outputLen, unsigned int maxOutputLen,
00901                     const unsigned char *input, unsigned int inputLen, 
00902                     unsigned int blocksize)
00903 {
00904     SECStatus rv;
00905     AESBlockFunc *decryptor;
00906     decryptor = (blocksize == RIJNDAEL_MIN_BLOCKSIZE) 
00907                               ? &rijndael_decryptBlock128 
00908                               : &rijndael_decryptBlock;
00909     while (inputLen > 0) {
00910         rv = (*decryptor)(cx, output, input);
00911        if (rv != SECSuccess)
00912            return rv;
00913        output += blocksize;
00914        input += blocksize;
00915        inputLen -= blocksize;
00916     }
00917     return SECSuccess;
00918 }
00919 
00920 static SECStatus 
00921 rijndael_decryptCBC(AESContext *cx, unsigned char *output,
00922                     unsigned int *outputLen, unsigned int maxOutputLen,
00923                     const unsigned char *input, unsigned int inputLen, 
00924                     unsigned int blocksize)
00925 {
00926     SECStatus rv;
00927     AESBlockFunc *decryptor;
00928     const unsigned char *in;
00929     unsigned char *out;
00930     unsigned int j;
00931     unsigned char newIV[RIJNDAEL_MAX_BLOCKSIZE];
00932 
00933     if (!inputLen) 
00934        return SECSuccess;
00935     PORT_Assert(output - input >= 0 || input - output >= (int)inputLen );
00936     decryptor = (blocksize == RIJNDAEL_MIN_BLOCKSIZE) 
00937                                   ? &rijndael_decryptBlock128 
00938                               : &rijndael_decryptBlock;
00939     in  = input  + (inputLen - blocksize);
00940     memcpy(newIV, in, blocksize);
00941     out = output + (inputLen - blocksize);
00942     while (inputLen > blocksize) {
00943         rv = (*decryptor)(cx, out, in);
00944        if (rv != SECSuccess)
00945            return rv;
00946        for (j=0; j<blocksize; ++j)
00947            out[j] ^= in[(int)(j - blocksize)];
00948        out -= blocksize;
00949        in -= blocksize;
00950        inputLen -= blocksize;
00951     }
00952     if (in == input) {
00953         rv = (*decryptor)(cx, out, in);
00954        if (rv != SECSuccess)
00955            return rv;
00956        for (j=0; j<blocksize; ++j)
00957            out[j] ^= cx->iv[j];
00958     }
00959     memcpy(cx->iv, newIV, blocksize);
00960     return SECSuccess;
00961 }
00962 
00963 /************************************************************************
00964  *
00965  * BLAPI Interface functions
00966  *
00967  * The following functions implement the encryption routines defined in
00968  * BLAPI for the AES cipher, Rijndael.
00969  *
00970  ***********************************************************************/
00971 
00972 AESContext * AES_AllocateContext(void)
00973 {
00974     return PORT_ZNew(AESContext);
00975 }
00976 
00977 SECStatus   
00978 AES_InitContext(AESContext *cx, const unsigned char *key, unsigned int keysize, 
00979                const unsigned char *iv, int mode, unsigned int encrypt,
00980                unsigned int blocksize)
00981 {
00982     unsigned int Nk;
00983     /* According to Rijndael AES Proposal, section 12.1, block and key
00984      * lengths between 128 and 256 bits are supported, as long as the
00985      * length in bytes is divisible by 4.
00986      */
00987     if (key == NULL || 
00988         keysize < RIJNDAEL_MIN_BLOCKSIZE   || 
00989        keysize > RIJNDAEL_MAX_BLOCKSIZE   || 
00990        keysize % 4 != 0 ||
00991         blocksize < RIJNDAEL_MIN_BLOCKSIZE || 
00992        blocksize > RIJNDAEL_MAX_BLOCKSIZE || 
00993        blocksize % 4 != 0) {
00994        PORT_SetError(SEC_ERROR_INVALID_ARGS);
00995        return SECFailure;
00996     }
00997     if (mode != NSS_AES && mode != NSS_AES_CBC) {
00998        PORT_SetError(SEC_ERROR_INVALID_ARGS);
00999        return SECFailure;
01000     }
01001     if (mode == NSS_AES_CBC && iv == NULL) {
01002        PORT_SetError(SEC_ERROR_INVALID_ARGS);
01003        return SECFailure;
01004     }
01005     if (!cx) {
01006        PORT_SetError(SEC_ERROR_INVALID_ARGS);
01007        return SECFailure;
01008     }
01009     /* Nb = (block size in bits) / 32 */
01010     cx->Nb = blocksize / 4;
01011     /* Nk = (key size in bits) / 32 */
01012     Nk = keysize / 4;
01013     /* Obtain number of rounds from "table" */
01014     cx->Nr = RIJNDAEL_NUM_ROUNDS(Nk, cx->Nb);
01015     /* copy in the iv, if neccessary */
01016     if (mode == NSS_AES_CBC) {
01017        memcpy(cx->iv, iv, blocksize);
01018        cx->worker = (encrypt) ? &rijndael_encryptCBC : &rijndael_decryptCBC;
01019     } else {
01020        cx->worker = (encrypt) ? &rijndael_encryptECB : &rijndael_decryptECB;
01021     }
01022     PORT_Assert((cx->Nb * (cx->Nr + 1)) <= RIJNDAEL_MAX_EXP_KEY_SIZE);
01023     if ((cx->Nb * (cx->Nr + 1)) > RIJNDAEL_MAX_EXP_KEY_SIZE) {
01024        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
01025        goto cleanup;
01026     }
01027     /* Generate expanded key */
01028     if (encrypt) {
01029        if (rijndael_key_expansion(cx, key, Nk) != SECSuccess)
01030            goto cleanup;
01031     } else {
01032        if (rijndael_invkey_expansion(cx, key, Nk) != SECSuccess)
01033            goto cleanup;
01034     }
01035     return SECSuccess;
01036 cleanup:
01037     return SECFailure;
01038 }
01039 
01040 
01041 /* AES_CreateContext
01042  *
01043  * create a new context for Rijndael operations
01044  */
01045 AESContext *
01046 AES_CreateContext(const unsigned char *key, const unsigned char *iv, 
01047                   int mode, int encrypt,
01048                   unsigned int keysize, unsigned int blocksize)
01049 {
01050     AESContext *cx = AES_AllocateContext();
01051     if (cx) {
01052        SECStatus rv = AES_InitContext(cx, key, keysize, iv, mode, encrypt,
01053                                    blocksize);
01054        if (rv != SECSuccess) {
01055            AES_DestroyContext(cx, PR_TRUE);
01056            cx = NULL;
01057        }
01058     }
01059     return cx;
01060 }
01061 
01062 /*
01063  * AES_DestroyContext
01064  * 
01065  * Zero an AES cipher context.  If freeit is true, also free the pointer
01066  * to the context.
01067  */
01068 void 
01069 AES_DestroyContext(AESContext *cx, PRBool freeit)
01070 {
01071 /*  memset(cx, 0, sizeof *cx); */
01072     if (freeit)
01073        PORT_Free(cx);
01074 }
01075 
01076 /*
01077  * AES_Encrypt
01078  *
01079  * Encrypt an arbitrary-length buffer.  The output buffer must already be
01080  * allocated to at least inputLen.
01081  */
01082 SECStatus 
01083 AES_Encrypt(AESContext *cx, unsigned char *output,
01084             unsigned int *outputLen, unsigned int maxOutputLen,
01085             const unsigned char *input, unsigned int inputLen)
01086 {
01087     int blocksize;
01088     /* Check args */
01089     if (cx == NULL || output == NULL || input == NULL) {
01090        PORT_SetError(SEC_ERROR_INVALID_ARGS);
01091        return SECFailure;
01092     }
01093     blocksize = 4 * cx->Nb;
01094     if (inputLen % blocksize != 0) {
01095        PORT_SetError(SEC_ERROR_INPUT_LEN);
01096        return SECFailure;
01097     }
01098     if (maxOutputLen < inputLen) {
01099        PORT_SetError(SEC_ERROR_OUTPUT_LEN);
01100        return SECFailure;
01101     }
01102     *outputLen = inputLen;
01103 #if defined(RIJNDAEL_GENERATE_TABLES) ||  \
01104     defined(RIJNDAEL_GENERATE_TABLES_MACRO)
01105     if (rijndaelTables == NULL) {
01106        if (PR_CallOnce(&coRTInit, init_rijndael_tables) 
01107              != PR_SUCCESS) {
01108            return PR_FAILURE;
01109        }
01110     }
01111 #endif
01112     return (*cx->worker)(cx, output, outputLen, maxOutputLen,  
01113                              input, inputLen, blocksize);
01114 }
01115 
01116 /*
01117  * AES_Decrypt
01118  *
01119  * Decrypt and arbitrary-length buffer.  The output buffer must already be
01120  * allocated to at least inputLen.
01121  */
01122 SECStatus 
01123 AES_Decrypt(AESContext *cx, unsigned char *output,
01124             unsigned int *outputLen, unsigned int maxOutputLen,
01125             const unsigned char *input, unsigned int inputLen)
01126 {
01127     int blocksize;
01128     /* Check args */
01129     if (cx == NULL || output == NULL || input == NULL) {
01130        PORT_SetError(SEC_ERROR_INVALID_ARGS);
01131        return SECFailure;
01132     }
01133     blocksize = 4 * cx->Nb;
01134     if (inputLen % blocksize != 0) {
01135        PORT_SetError(SEC_ERROR_INPUT_LEN);
01136        return SECFailure;
01137     }
01138     if (maxOutputLen < inputLen) {
01139        PORT_SetError(SEC_ERROR_OUTPUT_LEN);
01140        return SECFailure;
01141     }
01142     *outputLen = inputLen;
01143 #if defined(RIJNDAEL_GENERATE_TABLES) ||  \
01144     defined(RIJNDAEL_GENERATE_TABLES_MACRO)
01145     if (rijndaelTables == NULL) {
01146        if (PR_CallOnce(&coRTInit, init_rijndael_tables) 
01147              != PR_SUCCESS) {
01148            return PR_FAILURE;
01149        }
01150     }
01151 #endif
01152     return (*cx->worker)(cx, output, outputLen, maxOutputLen,  
01153                              input, inputLen, blocksize);
01154 }
01155