| Index: mozilla/security/nss/lib/freebl/rijndael.c
|
| ===================================================================
|
| --- mozilla/security/nss/lib/freebl/rijndael.c (revision 191424)
|
| +++ mozilla/security/nss/lib/freebl/rijndael.c (working copy)
|
| @@ -1,1271 +0,0 @@
|
| -/* This Source Code Form is subject to the terms of the Mozilla Public
|
| - * License, v. 2.0. If a copy of the MPL was not distributed with this
|
| - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
| -/* $Id: rijndael.c,v 1.30 2013/01/25 18:02:53 rrelyea%redhat.com Exp $ */
|
| -
|
| -#ifdef FREEBL_NO_DEPEND
|
| -#include "stubs.h"
|
| -#endif
|
| -
|
| -#include "prinit.h"
|
| -#include "prerr.h"
|
| -#include "secerr.h"
|
| -
|
| -#include "prtypes.h"
|
| -#include "blapi.h"
|
| -#include "rijndael.h"
|
| -
|
| -#include "cts.h"
|
| -#include "ctr.h"
|
| -#include "gcm.h"
|
| -
|
| -#if USE_HW_AES
|
| -#include "intel-gcm.h"
|
| -#include "intel-aes.h"
|
| -#include "mpi.h"
|
| -
|
| -static int has_intel_aes = 0;
|
| -static int has_intel_avx = 0;
|
| -static int has_intel_clmul = 0;
|
| -static PRBool use_hw_aes = PR_FALSE;
|
| -static PRBool use_hw_avx = PR_FALSE;
|
| -static PRBool use_hw_gcm = PR_FALSE;
|
| -#endif
|
| -
|
| -/*
|
| - * There are currently five ways to build this code, varying in performance
|
| - * and code size.
|
| - *
|
| - * RIJNDAEL_INCLUDE_TABLES Include all tables from rijndael32.tab
|
| - * RIJNDAEL_GENERATE_TABLES Generate tables on first
|
| - * encryption/decryption, then store them;
|
| - * use the function gfm
|
| - * RIJNDAEL_GENERATE_TABLES_MACRO Same as above, but use macros to do
|
| - * the generation
|
| - * RIJNDAEL_GENERATE_VALUES Do not store tables, generate the table
|
| - * values "on-the-fly", using gfm
|
| - * RIJNDAEL_GENERATE_VALUES_MACRO Same as above, but use macros
|
| - *
|
| - * The default is RIJNDAEL_INCLUDE_TABLES.
|
| - */
|
| -
|
| -/*
|
| - * When building RIJNDAEL_INCLUDE_TABLES, includes S**-1, Rcon, T[0..4],
|
| - * T**-1[0..4], IMXC[0..4]
|
| - * When building anything else, includes S, S**-1, Rcon
|
| - */
|
| -#include "rijndael32.tab"
|
| -
|
| -#if defined(RIJNDAEL_INCLUDE_TABLES)
|
| -/*
|
| - * RIJNDAEL_INCLUDE_TABLES
|
| - */
|
| -#define T0(i) _T0[i]
|
| -#define T1(i) _T1[i]
|
| -#define T2(i) _T2[i]
|
| -#define T3(i) _T3[i]
|
| -#define TInv0(i) _TInv0[i]
|
| -#define TInv1(i) _TInv1[i]
|
| -#define TInv2(i) _TInv2[i]
|
| -#define TInv3(i) _TInv3[i]
|
| -#define IMXC0(b) _IMXC0[b]
|
| -#define IMXC1(b) _IMXC1[b]
|
| -#define IMXC2(b) _IMXC2[b]
|
| -#define IMXC3(b) _IMXC3[b]
|
| -/* The S-box can be recovered from the T-tables */
|
| -#ifdef IS_LITTLE_ENDIAN
|
| -#define SBOX(b) ((PRUint8)_T3[b])
|
| -#else
|
| -#define SBOX(b) ((PRUint8)_T1[b])
|
| -#endif
|
| -#define SINV(b) (_SInv[b])
|
| -
|
| -#else /* not RIJNDAEL_INCLUDE_TABLES */
|
| -
|
| -/*
|
| - * Code for generating T-table values.
|
| - */
|
| -
|
| -#ifdef IS_LITTLE_ENDIAN
|
| -#define WORD4(b0, b1, b2, b3) \
|
| - (((b3) << 24) | ((b2) << 16) | ((b1) << 8) | (b0))
|
| -#else
|
| -#define WORD4(b0, b1, b2, b3) \
|
| - (((b0) << 24) | ((b1) << 16) | ((b2) << 8) | (b3))
|
| -#endif
|
| -
|
| -/*
|
| - * Define the S and S**-1 tables (both have been stored)
|
| - */
|
| -#define SBOX(b) (_S[b])
|
| -#define SINV(b) (_SInv[b])
|
| -
|
| -/*
|
| - * The function xtime, used for Galois field multiplication
|
| - */
|
| -#define XTIME(a) \
|
| - ((a & 0x80) ? ((a << 1) ^ 0x1b) : (a << 1))
|
| -
|
| -/* Choose GFM method (macros or function) */
|
| -#if defined(RIJNDAEL_GENERATE_TABLES_MACRO) || \
|
| - defined(RIJNDAEL_GENERATE_VALUES_MACRO)
|
| -
|
| -/*
|
| - * Galois field GF(2**8) multipliers, in macro form
|
| - */
|
| -#define GFM01(a) \
|
| - (a) /* a * 01 = a, the identity */
|
| -#define GFM02(a) \
|
| - (XTIME(a) & 0xff) /* a * 02 = xtime(a) */
|
| -#define GFM04(a) \
|
| - (GFM02(GFM02(a))) /* a * 04 = xtime**2(a) */
|
| -#define GFM08(a) \
|
| - (GFM02(GFM04(a))) /* a * 08 = xtime**3(a) */
|
| -#define GFM03(a) \
|
| - (GFM01(a) ^ GFM02(a)) /* a * 03 = a * (01 + 02) */
|
| -#define GFM09(a) \
|
| - (GFM01(a) ^ GFM08(a)) /* a * 09 = a * (01 + 08) */
|
| -#define GFM0B(a) \
|
| - (GFM01(a) ^ GFM02(a) ^ GFM08(a)) /* a * 0B = a * (01 + 02 + 08) */
|
| -#define GFM0D(a) \
|
| - (GFM01(a) ^ GFM04(a) ^ GFM08(a)) /* a * 0D = a * (01 + 04 + 08) */
|
| -#define GFM0E(a) \
|
| - (GFM02(a) ^ GFM04(a) ^ GFM08(a)) /* a * 0E = a * (02 + 04 + 08) */
|
| -
|
| -#else /* RIJNDAEL_GENERATE_TABLES or RIJNDAEL_GENERATE_VALUES */
|
| -
|
| -/* GF_MULTIPLY
|
| - *
|
| - * multiply two bytes represented in GF(2**8), mod (x**4 + 1)
|
| - */
|
| -PRUint8 gfm(PRUint8 a, PRUint8 b)
|
| -{
|
| - PRUint8 res = 0;
|
| - while (b > 0) {
|
| - res = (b & 0x01) ? res ^ a : res;
|
| - a = XTIME(a);
|
| - b >>= 1;
|
| - }
|
| - return res;
|
| -}
|
| -
|
| -#define GFM01(a) \
|
| - (a) /* a * 01 = a, the identity */
|
| -#define GFM02(a) \
|
| - (XTIME(a) & 0xff) /* a * 02 = xtime(a) */
|
| -#define GFM03(a) \
|
| - (gfm(a, 0x03)) /* a * 03 */
|
| -#define GFM09(a) \
|
| - (gfm(a, 0x09)) /* a * 09 */
|
| -#define GFM0B(a) \
|
| - (gfm(a, 0x0B)) /* a * 0B */
|
| -#define GFM0D(a) \
|
| - (gfm(a, 0x0D)) /* a * 0D */
|
| -#define GFM0E(a) \
|
| - (gfm(a, 0x0E)) /* a * 0E */
|
| -
|
| -#endif /* choosing GFM function */
|
| -
|
| -/*
|
| - * The T-tables
|
| - */
|
| -#define G_T0(i) \
|
| - ( WORD4( GFM02(SBOX(i)), GFM01(SBOX(i)), GFM01(SBOX(i)), GFM03(SBOX(i)) ) )
|
| -#define G_T1(i) \
|
| - ( WORD4( GFM03(SBOX(i)), GFM02(SBOX(i)), GFM01(SBOX(i)), GFM01(SBOX(i)) ) )
|
| -#define G_T2(i) \
|
| - ( WORD4( GFM01(SBOX(i)), GFM03(SBOX(i)), GFM02(SBOX(i)), GFM01(SBOX(i)) ) )
|
| -#define G_T3(i) \
|
| - ( WORD4( GFM01(SBOX(i)), GFM01(SBOX(i)), GFM03(SBOX(i)), GFM02(SBOX(i)) ) )
|
| -
|
| -/*
|
| - * The inverse T-tables
|
| - */
|
| -#define G_TInv0(i) \
|
| - ( WORD4( GFM0E(SINV(i)), GFM09(SINV(i)), GFM0D(SINV(i)), GFM0B(SINV(i)) ) )
|
| -#define G_TInv1(i) \
|
| - ( WORD4( GFM0B(SINV(i)), GFM0E(SINV(i)), GFM09(SINV(i)), GFM0D(SINV(i)) ) )
|
| -#define G_TInv2(i) \
|
| - ( WORD4( GFM0D(SINV(i)), GFM0B(SINV(i)), GFM0E(SINV(i)), GFM09(SINV(i)) ) )
|
| -#define G_TInv3(i) \
|
| - ( WORD4( GFM09(SINV(i)), GFM0D(SINV(i)), GFM0B(SINV(i)), GFM0E(SINV(i)) ) )
|
| -
|
| -/*
|
| - * The inverse mix column tables
|
| - */
|
| -#define G_IMXC0(i) \
|
| - ( WORD4( GFM0E(i), GFM09(i), GFM0D(i), GFM0B(i) ) )
|
| -#define G_IMXC1(i) \
|
| - ( WORD4( GFM0B(i), GFM0E(i), GFM09(i), GFM0D(i) ) )
|
| -#define G_IMXC2(i) \
|
| - ( WORD4( GFM0D(i), GFM0B(i), GFM0E(i), GFM09(i) ) )
|
| -#define G_IMXC3(i) \
|
| - ( WORD4( GFM09(i), GFM0D(i), GFM0B(i), GFM0E(i) ) )
|
| -
|
| -/* Now choose the T-table indexing method */
|
| -#if defined(RIJNDAEL_GENERATE_VALUES)
|
| -/* generate values for the tables with a function*/
|
| -static PRUint32 gen_TInvXi(PRUint8 tx, PRUint8 i)
|
| -{
|
| - PRUint8 si01, si02, si03, si04, si08, si09, si0B, si0D, si0E;
|
| - si01 = SINV(i);
|
| - si02 = XTIME(si01);
|
| - si04 = XTIME(si02);
|
| - si08 = XTIME(si04);
|
| - si03 = si02 ^ si01;
|
| - si09 = si08 ^ si01;
|
| - si0B = si08 ^ si03;
|
| - si0D = si09 ^ si04;
|
| - si0E = si08 ^ si04 ^ si02;
|
| - switch (tx) {
|
| - case 0:
|
| - return WORD4(si0E, si09, si0D, si0B);
|
| - case 1:
|
| - return WORD4(si0B, si0E, si09, si0D);
|
| - case 2:
|
| - return WORD4(si0D, si0B, si0E, si09);
|
| - case 3:
|
| - return WORD4(si09, si0D, si0B, si0E);
|
| - }
|
| - return -1;
|
| -}
|
| -#define T0(i) G_T0(i)
|
| -#define T1(i) G_T1(i)
|
| -#define T2(i) G_T2(i)
|
| -#define T3(i) G_T3(i)
|
| -#define TInv0(i) gen_TInvXi(0, i)
|
| -#define TInv1(i) gen_TInvXi(1, i)
|
| -#define TInv2(i) gen_TInvXi(2, i)
|
| -#define TInv3(i) gen_TInvXi(3, i)
|
| -#define IMXC0(b) G_IMXC0(b)
|
| -#define IMXC1(b) G_IMXC1(b)
|
| -#define IMXC2(b) G_IMXC2(b)
|
| -#define IMXC3(b) G_IMXC3(b)
|
| -#elif defined(RIJNDAEL_GENERATE_VALUES_MACRO)
|
| -/* generate values for the tables with macros */
|
| -#define T0(i) G_T0(i)
|
| -#define T1(i) G_T1(i)
|
| -#define T2(i) G_T2(i)
|
| -#define T3(i) G_T3(i)
|
| -#define TInv0(i) G_TInv0(i)
|
| -#define TInv1(i) G_TInv1(i)
|
| -#define TInv2(i) G_TInv2(i)
|
| -#define TInv3(i) G_TInv3(i)
|
| -#define IMXC0(b) G_IMXC0(b)
|
| -#define IMXC1(b) G_IMXC1(b)
|
| -#define IMXC2(b) G_IMXC2(b)
|
| -#define IMXC3(b) G_IMXC3(b)
|
| -#else /* RIJNDAEL_GENERATE_TABLES or RIJNDAEL_GENERATE_TABLES_MACRO */
|
| -/* Generate T and T**-1 table values and store, then index */
|
| -/* The inverse mix column tables are still generated */
|
| -#define T0(i) rijndaelTables->T0[i]
|
| -#define T1(i) rijndaelTables->T1[i]
|
| -#define T2(i) rijndaelTables->T2[i]
|
| -#define T3(i) rijndaelTables->T3[i]
|
| -#define TInv0(i) rijndaelTables->TInv0[i]
|
| -#define TInv1(i) rijndaelTables->TInv1[i]
|
| -#define TInv2(i) rijndaelTables->TInv2[i]
|
| -#define TInv3(i) rijndaelTables->TInv3[i]
|
| -#define IMXC0(b) G_IMXC0(b)
|
| -#define IMXC1(b) G_IMXC1(b)
|
| -#define IMXC2(b) G_IMXC2(b)
|
| -#define IMXC3(b) G_IMXC3(b)
|
| -#endif /* choose T-table indexing method */
|
| -
|
| -#endif /* not RIJNDAEL_INCLUDE_TABLES */
|
| -
|
| -#if defined(RIJNDAEL_GENERATE_TABLES) || \
|
| - defined(RIJNDAEL_GENERATE_TABLES_MACRO)
|
| -
|
| -/* Code to generate and store the tables */
|
| -
|
| -struct rijndael_tables_str {
|
| - PRUint32 T0[256];
|
| - PRUint32 T1[256];
|
| - PRUint32 T2[256];
|
| - PRUint32 T3[256];
|
| - PRUint32 TInv0[256];
|
| - PRUint32 TInv1[256];
|
| - PRUint32 TInv2[256];
|
| - PRUint32 TInv3[256];
|
| -};
|
| -
|
| -static struct rijndael_tables_str *rijndaelTables = NULL;
|
| -static PRCallOnceType coRTInit = { 0, 0, 0 };
|
| -static PRStatus
|
| -init_rijndael_tables(void)
|
| -{
|
| - PRUint32 i;
|
| - PRUint8 si01, si02, si03, si04, si08, si09, si0B, si0D, si0E;
|
| - struct rijndael_tables_str *rts;
|
| - rts = (struct rijndael_tables_str *)
|
| - PORT_Alloc(sizeof(struct rijndael_tables_str));
|
| - if (!rts) return PR_FAILURE;
|
| - for (i=0; i<256; i++) {
|
| - /* The forward values */
|
| - si01 = SBOX(i);
|
| - si02 = XTIME(si01);
|
| - si03 = si02 ^ si01;
|
| - rts->T0[i] = WORD4(si02, si01, si01, si03);
|
| - rts->T1[i] = WORD4(si03, si02, si01, si01);
|
| - rts->T2[i] = WORD4(si01, si03, si02, si01);
|
| - rts->T3[i] = WORD4(si01, si01, si03, si02);
|
| - /* The inverse values */
|
| - si01 = SINV(i);
|
| - si02 = XTIME(si01);
|
| - si04 = XTIME(si02);
|
| - si08 = XTIME(si04);
|
| - si03 = si02 ^ si01;
|
| - si09 = si08 ^ si01;
|
| - si0B = si08 ^ si03;
|
| - si0D = si09 ^ si04;
|
| - si0E = si08 ^ si04 ^ si02;
|
| - rts->TInv0[i] = WORD4(si0E, si09, si0D, si0B);
|
| - rts->TInv1[i] = WORD4(si0B, si0E, si09, si0D);
|
| - rts->TInv2[i] = WORD4(si0D, si0B, si0E, si09);
|
| - rts->TInv3[i] = WORD4(si09, si0D, si0B, si0E);
|
| - }
|
| - /* wait until all the values are in to set */
|
| - rijndaelTables = rts;
|
| - return PR_SUCCESS;
|
| -}
|
| -
|
| -#endif /* code to generate tables */
|
| -
|
| -/**************************************************************************
|
| - *
|
| - * Stuff related to the Rijndael key schedule
|
| - *
|
| - *************************************************************************/
|
| -
|
| -#define SUBBYTE(w) \
|
| - ((SBOX((w >> 24) & 0xff) << 24) | \
|
| - (SBOX((w >> 16) & 0xff) << 16) | \
|
| - (SBOX((w >> 8) & 0xff) << 8) | \
|
| - (SBOX((w ) & 0xff) ))
|
| -
|
| -#ifdef IS_LITTLE_ENDIAN
|
| -#define ROTBYTE(b) \
|
| - ((b >> 8) | (b << 24))
|
| -#else
|
| -#define ROTBYTE(b) \
|
| - ((b << 8) | (b >> 24))
|
| -#endif
|
| -
|
| -/* rijndael_key_expansion7
|
| - *
|
| - * Generate the expanded key from the key input by the user.
|
| - * XXX
|
| - * Nk == 7 (224 key bits) is a weird case. Since Nk > 6, an added SubByte
|
| - * transformation is done periodically. The period is every 4 bytes, and
|
| - * since 7%4 != 0 this happens at different times for each key word (unlike
|
| - * Nk == 8 where it happens twice in every key word, in the same positions).
|
| - * For now, I'm implementing this case "dumbly", w/o any unrolling.
|
| - */
|
| -static SECStatus
|
| -rijndael_key_expansion7(AESContext *cx, const unsigned char *key, unsigned int Nk)
|
| -{
|
| - unsigned int i;
|
| - PRUint32 *W;
|
| - PRUint32 *pW;
|
| - PRUint32 tmp;
|
| - W = cx->expandedKey;
|
| - /* 1. the first Nk words contain the cipher key */
|
| - memcpy(W, key, Nk * 4);
|
| - i = Nk;
|
| - /* 2. loop until full expanded key is obtained */
|
| - pW = W + i - 1;
|
| - for (; i < cx->Nb * (cx->Nr + 1); ++i) {
|
| - tmp = *pW++;
|
| - if (i % Nk == 0)
|
| - tmp = SUBBYTE(ROTBYTE(tmp)) ^ Rcon[i / Nk - 1];
|
| - else if (i % Nk == 4)
|
| - tmp = SUBBYTE(tmp);
|
| - *pW = W[i - Nk] ^ tmp;
|
| - }
|
| - return SECSuccess;
|
| -}
|
| -
|
| -/* rijndael_key_expansion
|
| - *
|
| - * Generate the expanded key from the key input by the user.
|
| - */
|
| -static SECStatus
|
| -rijndael_key_expansion(AESContext *cx, const unsigned char *key, unsigned int Nk)
|
| -{
|
| - unsigned int i;
|
| - PRUint32 *W;
|
| - PRUint32 *pW;
|
| - PRUint32 tmp;
|
| - unsigned int round_key_words = cx->Nb * (cx->Nr + 1);
|
| - if (Nk == 7)
|
| - return rijndael_key_expansion7(cx, key, Nk);
|
| - W = cx->expandedKey;
|
| - /* The first Nk words contain the input cipher key */
|
| - memcpy(W, key, Nk * 4);
|
| - i = Nk;
|
| - pW = W + i - 1;
|
| - /* Loop over all sets of Nk words, except the last */
|
| - while (i < round_key_words - Nk) {
|
| - tmp = *pW++;
|
| - tmp = SUBBYTE(ROTBYTE(tmp)) ^ Rcon[i / Nk - 1];
|
| - *pW = W[i++ - Nk] ^ tmp;
|
| - tmp = *pW++; *pW = W[i++ - Nk] ^ tmp;
|
| - tmp = *pW++; *pW = W[i++ - Nk] ^ tmp;
|
| - tmp = *pW++; *pW = W[i++ - Nk] ^ tmp;
|
| - if (Nk == 4)
|
| - continue;
|
| - switch (Nk) {
|
| - case 8: tmp = *pW++; tmp = SUBBYTE(tmp); *pW = W[i++ - Nk] ^ tmp;
|
| - case 7: tmp = *pW++; *pW = W[i++ - Nk] ^ tmp;
|
| - case 6: tmp = *pW++; *pW = W[i++ - Nk] ^ tmp;
|
| - case 5: tmp = *pW++; *pW = W[i++ - Nk] ^ tmp;
|
| - }
|
| - }
|
| - /* Generate the last word */
|
| - tmp = *pW++;
|
| - tmp = SUBBYTE(ROTBYTE(tmp)) ^ Rcon[i / Nk - 1];
|
| - *pW = W[i++ - Nk] ^ tmp;
|
| - /* There may be overflow here, if Nk % (Nb * (Nr + 1)) > 0. However,
|
| - * since the above loop generated all but the last Nk key words, there
|
| - * is no more need for the SubByte transformation.
|
| - */
|
| - if (Nk < 8) {
|
| - for (; i < round_key_words; ++i) {
|
| - tmp = *pW++;
|
| - *pW = W[i - Nk] ^ tmp;
|
| - }
|
| - } else {
|
| - /* except in the case when Nk == 8. Then one more SubByte may have
|
| - * to be performed, at i % Nk == 4.
|
| - */
|
| - for (; i < round_key_words; ++i) {
|
| - tmp = *pW++;
|
| - if (i % Nk == 4)
|
| - tmp = SUBBYTE(tmp);
|
| - *pW = W[i - Nk] ^ tmp;
|
| - }
|
| - }
|
| - return SECSuccess;
|
| -}
|
| -
|
| -/* rijndael_invkey_expansion
|
| - *
|
| - * Generate the expanded key for the inverse cipher from the key input by
|
| - * the user.
|
| - */
|
| -static SECStatus
|
| -rijndael_invkey_expansion(AESContext *cx, const unsigned char *key, unsigned int Nk)
|
| -{
|
| - unsigned int r;
|
| - PRUint32 *roundkeyw;
|
| - PRUint8 *b;
|
| - int Nb = cx->Nb;
|
| - /* begins like usual key expansion ... */
|
| - if (rijndael_key_expansion(cx, key, Nk) != SECSuccess)
|
| - return SECFailure;
|
| - /* ... but has the additional step of InvMixColumn,
|
| - * excepting the first and last round keys.
|
| - */
|
| - roundkeyw = cx->expandedKey + cx->Nb;
|
| - for (r=1; r<cx->Nr; ++r) {
|
| - /* each key word, roundkeyw, represents a column in the key
|
| - * matrix. Each column is multiplied by the InvMixColumn matrix.
|
| - * [ 0E 0B 0D 09 ] [ b0 ]
|
| - * [ 09 0E 0B 0D ] * [ b1 ]
|
| - * [ 0D 09 0E 0B ] [ b2 ]
|
| - * [ 0B 0D 09 0E ] [ b3 ]
|
| - */
|
| - b = (PRUint8 *)roundkeyw;
|
| - *roundkeyw++ = IMXC0(b[0]) ^ IMXC1(b[1]) ^ IMXC2(b[2]) ^ IMXC3(b[3]);
|
| - b = (PRUint8 *)roundkeyw;
|
| - *roundkeyw++ = IMXC0(b[0]) ^ IMXC1(b[1]) ^ IMXC2(b[2]) ^ IMXC3(b[3]);
|
| - b = (PRUint8 *)roundkeyw;
|
| - *roundkeyw++ = IMXC0(b[0]) ^ IMXC1(b[1]) ^ IMXC2(b[2]) ^ IMXC3(b[3]);
|
| - b = (PRUint8 *)roundkeyw;
|
| - *roundkeyw++ = IMXC0(b[0]) ^ IMXC1(b[1]) ^ IMXC2(b[2]) ^ IMXC3(b[3]);
|
| - if (Nb <= 4)
|
| - continue;
|
| - switch (Nb) {
|
| - case 8: b = (PRUint8 *)roundkeyw;
|
| - *roundkeyw++ = IMXC0(b[0]) ^ IMXC1(b[1]) ^
|
| - IMXC2(b[2]) ^ IMXC3(b[3]);
|
| - case 7: b = (PRUint8 *)roundkeyw;
|
| - *roundkeyw++ = IMXC0(b[0]) ^ IMXC1(b[1]) ^
|
| - IMXC2(b[2]) ^ IMXC3(b[3]);
|
| - case 6: b = (PRUint8 *)roundkeyw;
|
| - *roundkeyw++ = IMXC0(b[0]) ^ IMXC1(b[1]) ^
|
| - IMXC2(b[2]) ^ IMXC3(b[3]);
|
| - case 5: b = (PRUint8 *)roundkeyw;
|
| - *roundkeyw++ = IMXC0(b[0]) ^ IMXC1(b[1]) ^
|
| - IMXC2(b[2]) ^ IMXC3(b[3]);
|
| - }
|
| - }
|
| - return SECSuccess;
|
| -}
|
| -/**************************************************************************
|
| - *
|
| - * Stuff related to Rijndael encryption/decryption, optimized for
|
| - * a 128-bit blocksize.
|
| - *
|
| - *************************************************************************/
|
| -
|
| -#ifdef IS_LITTLE_ENDIAN
|
| -#define BYTE0WORD(w) ((w) & 0x000000ff)
|
| -#define BYTE1WORD(w) ((w) & 0x0000ff00)
|
| -#define BYTE2WORD(w) ((w) & 0x00ff0000)
|
| -#define BYTE3WORD(w) ((w) & 0xff000000)
|
| -#else
|
| -#define BYTE0WORD(w) ((w) & 0xff000000)
|
| -#define BYTE1WORD(w) ((w) & 0x00ff0000)
|
| -#define BYTE2WORD(w) ((w) & 0x0000ff00)
|
| -#define BYTE3WORD(w) ((w) & 0x000000ff)
|
| -#endif
|
| -
|
| -typedef union {
|
| - PRUint32 w[4];
|
| - PRUint8 b[16];
|
| -} rijndael_state;
|
| -
|
| -#define COLUMN_0(state) state.w[0]
|
| -#define COLUMN_1(state) state.w[1]
|
| -#define COLUMN_2(state) state.w[2]
|
| -#define COLUMN_3(state) state.w[3]
|
| -
|
| -#define STATE_BYTE(i) state.b[i]
|
| -
|
| -static SECStatus
|
| -rijndael_encryptBlock128(AESContext *cx,
|
| - unsigned char *output,
|
| - const unsigned char *input)
|
| -{
|
| - unsigned int r;
|
| - PRUint32 *roundkeyw;
|
| - rijndael_state state;
|
| - PRUint32 C0, C1, C2, C3;
|
| -#if defined(NSS_X86_OR_X64)
|
| -#define pIn input
|
| -#define pOut output
|
| -#else
|
| - unsigned char *pIn, *pOut;
|
| - PRUint32 inBuf[4], outBuf[4];
|
| -
|
| - if ((ptrdiff_t)input & 0x3) {
|
| - memcpy(inBuf, input, sizeof inBuf);
|
| - pIn = (unsigned char *)inBuf;
|
| - } else {
|
| - pIn = (unsigned char *)input;
|
| - }
|
| - if ((ptrdiff_t)output & 0x3) {
|
| - pOut = (unsigned char *)outBuf;
|
| - } else {
|
| - pOut = (unsigned char *)output;
|
| - }
|
| -#endif
|
| - roundkeyw = cx->expandedKey;
|
| - /* Step 1: Add Round Key 0 to initial state */
|
| - COLUMN_0(state) = *((PRUint32 *)(pIn )) ^ *roundkeyw++;
|
| - COLUMN_1(state) = *((PRUint32 *)(pIn + 4 )) ^ *roundkeyw++;
|
| - COLUMN_2(state) = *((PRUint32 *)(pIn + 8 )) ^ *roundkeyw++;
|
| - COLUMN_3(state) = *((PRUint32 *)(pIn + 12)) ^ *roundkeyw++;
|
| - /* Step 2: Loop over rounds [1..NR-1] */
|
| - for (r=1; r<cx->Nr; ++r) {
|
| - /* Do ShiftRow, ByteSub, and MixColumn all at once */
|
| - C0 = T0(STATE_BYTE(0)) ^
|
| - T1(STATE_BYTE(5)) ^
|
| - T2(STATE_BYTE(10)) ^
|
| - T3(STATE_BYTE(15));
|
| - C1 = T0(STATE_BYTE(4)) ^
|
| - T1(STATE_BYTE(9)) ^
|
| - T2(STATE_BYTE(14)) ^
|
| - T3(STATE_BYTE(3));
|
| - C2 = T0(STATE_BYTE(8)) ^
|
| - T1(STATE_BYTE(13)) ^
|
| - T2(STATE_BYTE(2)) ^
|
| - T3(STATE_BYTE(7));
|
| - C3 = T0(STATE_BYTE(12)) ^
|
| - T1(STATE_BYTE(1)) ^
|
| - T2(STATE_BYTE(6)) ^
|
| - T3(STATE_BYTE(11));
|
| - /* Round key addition */
|
| - COLUMN_0(state) = C0 ^ *roundkeyw++;
|
| - COLUMN_1(state) = C1 ^ *roundkeyw++;
|
| - COLUMN_2(state) = C2 ^ *roundkeyw++;
|
| - COLUMN_3(state) = C3 ^ *roundkeyw++;
|
| - }
|
| - /* Step 3: Do the last round */
|
| - /* Final round does not employ MixColumn */
|
| - C0 = ((BYTE0WORD(T2(STATE_BYTE(0)))) |
|
| - (BYTE1WORD(T3(STATE_BYTE(5)))) |
|
| - (BYTE2WORD(T0(STATE_BYTE(10)))) |
|
| - (BYTE3WORD(T1(STATE_BYTE(15))))) ^
|
| - *roundkeyw++;
|
| - C1 = ((BYTE0WORD(T2(STATE_BYTE(4)))) |
|
| - (BYTE1WORD(T3(STATE_BYTE(9)))) |
|
| - (BYTE2WORD(T0(STATE_BYTE(14)))) |
|
| - (BYTE3WORD(T1(STATE_BYTE(3))))) ^
|
| - *roundkeyw++;
|
| - C2 = ((BYTE0WORD(T2(STATE_BYTE(8)))) |
|
| - (BYTE1WORD(T3(STATE_BYTE(13)))) |
|
| - (BYTE2WORD(T0(STATE_BYTE(2)))) |
|
| - (BYTE3WORD(T1(STATE_BYTE(7))))) ^
|
| - *roundkeyw++;
|
| - C3 = ((BYTE0WORD(T2(STATE_BYTE(12)))) |
|
| - (BYTE1WORD(T3(STATE_BYTE(1)))) |
|
| - (BYTE2WORD(T0(STATE_BYTE(6)))) |
|
| - (BYTE3WORD(T1(STATE_BYTE(11))))) ^
|
| - *roundkeyw++;
|
| - *((PRUint32 *) pOut ) = C0;
|
| - *((PRUint32 *)(pOut + 4)) = C1;
|
| - *((PRUint32 *)(pOut + 8)) = C2;
|
| - *((PRUint32 *)(pOut + 12)) = C3;
|
| -#if defined(NSS_X86_OR_X64)
|
| -#undef pIn
|
| -#undef pOut
|
| -#else
|
| - if ((ptrdiff_t)output & 0x3) {
|
| - memcpy(output, outBuf, sizeof outBuf);
|
| - }
|
| -#endif
|
| - return SECSuccess;
|
| -}
|
| -
|
| -static SECStatus
|
| -rijndael_decryptBlock128(AESContext *cx,
|
| - unsigned char *output,
|
| - const unsigned char *input)
|
| -{
|
| - int r;
|
| - PRUint32 *roundkeyw;
|
| - rijndael_state state;
|
| - PRUint32 C0, C1, C2, C3;
|
| -#if defined(NSS_X86_OR_X64)
|
| -#define pIn input
|
| -#define pOut output
|
| -#else
|
| - unsigned char *pIn, *pOut;
|
| - PRUint32 inBuf[4], outBuf[4];
|
| -
|
| - if ((ptrdiff_t)input & 0x3) {
|
| - memcpy(inBuf, input, sizeof inBuf);
|
| - pIn = (unsigned char *)inBuf;
|
| - } else {
|
| - pIn = (unsigned char *)input;
|
| - }
|
| - if ((ptrdiff_t)output & 0x3) {
|
| - pOut = (unsigned char *)outBuf;
|
| - } else {
|
| - pOut = (unsigned char *)output;
|
| - }
|
| -#endif
|
| - roundkeyw = cx->expandedKey + cx->Nb * cx->Nr + 3;
|
| - /* reverse the final key addition */
|
| - COLUMN_3(state) = *((PRUint32 *)(pIn + 12)) ^ *roundkeyw--;
|
| - COLUMN_2(state) = *((PRUint32 *)(pIn + 8)) ^ *roundkeyw--;
|
| - COLUMN_1(state) = *((PRUint32 *)(pIn + 4)) ^ *roundkeyw--;
|
| - COLUMN_0(state) = *((PRUint32 *)(pIn )) ^ *roundkeyw--;
|
| - /* Loop over rounds in reverse [NR..1] */
|
| - for (r=cx->Nr; r>1; --r) {
|
| - /* Invert the (InvByteSub*InvMixColumn)(InvShiftRow(state)) */
|
| - C0 = TInv0(STATE_BYTE(0)) ^
|
| - TInv1(STATE_BYTE(13)) ^
|
| - TInv2(STATE_BYTE(10)) ^
|
| - TInv3(STATE_BYTE(7));
|
| - C1 = TInv0(STATE_BYTE(4)) ^
|
| - TInv1(STATE_BYTE(1)) ^
|
| - TInv2(STATE_BYTE(14)) ^
|
| - TInv3(STATE_BYTE(11));
|
| - C2 = TInv0(STATE_BYTE(8)) ^
|
| - TInv1(STATE_BYTE(5)) ^
|
| - TInv2(STATE_BYTE(2)) ^
|
| - TInv3(STATE_BYTE(15));
|
| - C3 = TInv0(STATE_BYTE(12)) ^
|
| - TInv1(STATE_BYTE(9)) ^
|
| - TInv2(STATE_BYTE(6)) ^
|
| - TInv3(STATE_BYTE(3));
|
| - /* Invert the key addition step */
|
| - COLUMN_3(state) = C3 ^ *roundkeyw--;
|
| - COLUMN_2(state) = C2 ^ *roundkeyw--;
|
| - COLUMN_1(state) = C1 ^ *roundkeyw--;
|
| - COLUMN_0(state) = C0 ^ *roundkeyw--;
|
| - }
|
| - /* inverse sub */
|
| - pOut[ 0] = SINV(STATE_BYTE( 0));
|
| - pOut[ 1] = SINV(STATE_BYTE(13));
|
| - pOut[ 2] = SINV(STATE_BYTE(10));
|
| - pOut[ 3] = SINV(STATE_BYTE( 7));
|
| - pOut[ 4] = SINV(STATE_BYTE( 4));
|
| - pOut[ 5] = SINV(STATE_BYTE( 1));
|
| - pOut[ 6] = SINV(STATE_BYTE(14));
|
| - pOut[ 7] = SINV(STATE_BYTE(11));
|
| - pOut[ 8] = SINV(STATE_BYTE( 8));
|
| - pOut[ 9] = SINV(STATE_BYTE( 5));
|
| - pOut[10] = SINV(STATE_BYTE( 2));
|
| - pOut[11] = SINV(STATE_BYTE(15));
|
| - pOut[12] = SINV(STATE_BYTE(12));
|
| - pOut[13] = SINV(STATE_BYTE( 9));
|
| - pOut[14] = SINV(STATE_BYTE( 6));
|
| - pOut[15] = SINV(STATE_BYTE( 3));
|
| - /* final key addition */
|
| - *((PRUint32 *)(pOut + 12)) ^= *roundkeyw--;
|
| - *((PRUint32 *)(pOut + 8)) ^= *roundkeyw--;
|
| - *((PRUint32 *)(pOut + 4)) ^= *roundkeyw--;
|
| - *((PRUint32 *) pOut ) ^= *roundkeyw--;
|
| -#if defined(NSS_X86_OR_X64)
|
| -#undef pIn
|
| -#undef pOut
|
| -#else
|
| - if ((ptrdiff_t)output & 0x3) {
|
| - memcpy(output, outBuf, sizeof outBuf);
|
| - }
|
| -#endif
|
| - return SECSuccess;
|
| -}
|
| -
|
| -/**************************************************************************
|
| - *
|
| - * Stuff related to general Rijndael encryption/decryption, for blocksizes
|
| - * greater than 128 bits.
|
| - *
|
| - * XXX This code is currently untested! So far, AES specs have only been
|
| - * released for 128 bit blocksizes. This will be tested, but for now
|
| - * only the code above has been tested using known values.
|
| - *
|
| - *************************************************************************/
|
| -
|
| -#define COLUMN(array, j) *((PRUint32 *)(array + j))
|
| -
|
| -SECStatus
|
| -rijndael_encryptBlock(AESContext *cx,
|
| - unsigned char *output,
|
| - const unsigned char *input)
|
| -{
|
| - return SECFailure;
|
| -#ifdef rijndael_large_blocks_fixed
|
| - unsigned int j, r, Nb;
|
| - unsigned int c2=0, c3=0;
|
| - PRUint32 *roundkeyw;
|
| - PRUint8 clone[RIJNDAEL_MAX_STATE_SIZE];
|
| - Nb = cx->Nb;
|
| - roundkeyw = cx->expandedKey;
|
| - /* Step 1: Add Round Key 0 to initial state */
|
| - for (j=0; j<4*Nb; j+=4) {
|
| - COLUMN(clone, j) = COLUMN(input, j) ^ *roundkeyw++;
|
| - }
|
| - /* Step 2: Loop over rounds [1..NR-1] */
|
| - for (r=1; r<cx->Nr; ++r) {
|
| - for (j=0; j<Nb; ++j) {
|
| - COLUMN(output, j) = T0(STATE_BYTE(4* j )) ^
|
| - T1(STATE_BYTE(4*((j+ 1)%Nb)+1)) ^
|
| - T2(STATE_BYTE(4*((j+c2)%Nb)+2)) ^
|
| - T3(STATE_BYTE(4*((j+c3)%Nb)+3));
|
| - }
|
| - for (j=0; j<4*Nb; j+=4) {
|
| - COLUMN(clone, j) = COLUMN(output, j) ^ *roundkeyw++;
|
| - }
|
| - }
|
| - /* Step 3: Do the last round */
|
| - /* Final round does not employ MixColumn */
|
| - for (j=0; j<Nb; ++j) {
|
| - COLUMN(output, j) = ((BYTE0WORD(T2(STATE_BYTE(4* j )))) |
|
| - (BYTE1WORD(T3(STATE_BYTE(4*(j+ 1)%Nb)+1))) |
|
| - (BYTE2WORD(T0(STATE_BYTE(4*(j+c2)%Nb)+2))) |
|
| - (BYTE3WORD(T1(STATE_BYTE(4*(j+c3)%Nb)+3)))) ^
|
| - *roundkeyw++;
|
| - }
|
| - return SECSuccess;
|
| -#endif
|
| -}
|
| -
|
| -SECStatus
|
| -rijndael_decryptBlock(AESContext *cx,
|
| - unsigned char *output,
|
| - const unsigned char *input)
|
| -{
|
| - return SECFailure;
|
| -#ifdef rijndael_large_blocks_fixed
|
| - int j, r, Nb;
|
| - int c2=0, c3=0;
|
| - PRUint32 *roundkeyw;
|
| - PRUint8 clone[RIJNDAEL_MAX_STATE_SIZE];
|
| - Nb = cx->Nb;
|
| - roundkeyw = cx->expandedKey + cx->Nb * cx->Nr + 3;
|
| - /* reverse key addition */
|
| - for (j=4*Nb; j>=0; j-=4) {
|
| - COLUMN(clone, j) = COLUMN(input, j) ^ *roundkeyw--;
|
| - }
|
| - /* Loop over rounds in reverse [NR..1] */
|
| - for (r=cx->Nr; r>1; --r) {
|
| - /* Invert the (InvByteSub*InvMixColumn)(InvShiftRow(state)) */
|
| - for (j=0; j<Nb; ++j) {
|
| - COLUMN(output, 4*j) = TInv0(STATE_BYTE(4* j )) ^
|
| - TInv1(STATE_BYTE(4*(j+Nb- 1)%Nb)+1) ^
|
| - TInv2(STATE_BYTE(4*(j+Nb-c2)%Nb)+2) ^
|
| - TInv3(STATE_BYTE(4*(j+Nb-c3)%Nb)+3);
|
| - }
|
| - /* Invert the key addition step */
|
| - for (j=4*Nb; j>=0; j-=4) {
|
| - COLUMN(clone, j) = COLUMN(output, j) ^ *roundkeyw--;
|
| - }
|
| - }
|
| - /* inverse sub */
|
| - for (j=0; j<4*Nb; ++j) {
|
| - output[j] = SINV(clone[j]);
|
| - }
|
| - /* final key addition */
|
| - for (j=4*Nb; j>=0; j-=4) {
|
| - COLUMN(output, j) ^= *roundkeyw--;
|
| - }
|
| - return SECSuccess;
|
| -#endif
|
| -}
|
| -
|
| -/**************************************************************************
|
| - *
|
| - * Rijndael modes of operation (ECB and CBC)
|
| - *
|
| - *************************************************************************/
|
| -
|
| -static SECStatus
|
| -rijndael_encryptECB(AESContext *cx, unsigned char *output,
|
| - unsigned int *outputLen, unsigned int maxOutputLen,
|
| - const unsigned char *input, unsigned int inputLen,
|
| - unsigned int blocksize)
|
| -{
|
| - SECStatus rv;
|
| - AESBlockFunc *encryptor;
|
| -
|
| -
|
| - encryptor = (blocksize == RIJNDAEL_MIN_BLOCKSIZE)
|
| - ? &rijndael_encryptBlock128
|
| - : &rijndael_encryptBlock;
|
| - while (inputLen > 0) {
|
| - rv = (*encryptor)(cx, output, input);
|
| - if (rv != SECSuccess)
|
| - return rv;
|
| - output += blocksize;
|
| - input += blocksize;
|
| - inputLen -= blocksize;
|
| - }
|
| - return SECSuccess;
|
| -}
|
| -
|
| -static SECStatus
|
| -rijndael_encryptCBC(AESContext *cx, unsigned char *output,
|
| - unsigned int *outputLen, unsigned int maxOutputLen,
|
| - const unsigned char *input, unsigned int inputLen,
|
| - unsigned int blocksize)
|
| -{
|
| - unsigned int j;
|
| - SECStatus rv;
|
| - AESBlockFunc *encryptor;
|
| - unsigned char *lastblock;
|
| - unsigned char inblock[RIJNDAEL_MAX_STATE_SIZE * 8];
|
| -
|
| - if (!inputLen)
|
| - return SECSuccess;
|
| - lastblock = cx->iv;
|
| - encryptor = (blocksize == RIJNDAEL_MIN_BLOCKSIZE)
|
| - ? &rijndael_encryptBlock128
|
| - : &rijndael_encryptBlock;
|
| - while (inputLen > 0) {
|
| - /* XOR with the last block (IV if first block) */
|
| - for (j=0; j<blocksize; ++j)
|
| - inblock[j] = input[j] ^ lastblock[j];
|
| - /* encrypt */
|
| - rv = (*encryptor)(cx, output, inblock);
|
| - if (rv != SECSuccess)
|
| - return rv;
|
| - /* move to the next block */
|
| - lastblock = output;
|
| - output += blocksize;
|
| - input += blocksize;
|
| - inputLen -= blocksize;
|
| - }
|
| - memcpy(cx->iv, lastblock, blocksize);
|
| - return SECSuccess;
|
| -}
|
| -
|
| -static SECStatus
|
| -rijndael_decryptECB(AESContext *cx, unsigned char *output,
|
| - unsigned int *outputLen, unsigned int maxOutputLen,
|
| - const unsigned char *input, unsigned int inputLen,
|
| - unsigned int blocksize)
|
| -{
|
| - SECStatus rv;
|
| - AESBlockFunc *decryptor;
|
| -
|
| - decryptor = (blocksize == RIJNDAEL_MIN_BLOCKSIZE)
|
| - ? &rijndael_decryptBlock128
|
| - : &rijndael_decryptBlock;
|
| - while (inputLen > 0) {
|
| - rv = (*decryptor)(cx, output, input);
|
| - if (rv != SECSuccess)
|
| - return rv;
|
| - output += blocksize;
|
| - input += blocksize;
|
| - inputLen -= blocksize;
|
| - }
|
| - return SECSuccess;
|
| -}
|
| -
|
| -static SECStatus
|
| -rijndael_decryptCBC(AESContext *cx, unsigned char *output,
|
| - unsigned int *outputLen, unsigned int maxOutputLen,
|
| - const unsigned char *input, unsigned int inputLen,
|
| - unsigned int blocksize)
|
| -{
|
| - SECStatus rv;
|
| - AESBlockFunc *decryptor;
|
| - const unsigned char *in;
|
| - unsigned char *out;
|
| - unsigned int j;
|
| - unsigned char newIV[RIJNDAEL_MAX_BLOCKSIZE];
|
| -
|
| -
|
| - if (!inputLen)
|
| - return SECSuccess;
|
| - PORT_Assert(output - input >= 0 || input - output >= (int)inputLen );
|
| - decryptor = (blocksize == RIJNDAEL_MIN_BLOCKSIZE)
|
| - ? &rijndael_decryptBlock128
|
| - : &rijndael_decryptBlock;
|
| - in = input + (inputLen - blocksize);
|
| - memcpy(newIV, in, blocksize);
|
| - out = output + (inputLen - blocksize);
|
| - while (inputLen > blocksize) {
|
| - rv = (*decryptor)(cx, out, in);
|
| - if (rv != SECSuccess)
|
| - return rv;
|
| - for (j=0; j<blocksize; ++j)
|
| - out[j] ^= in[(int)(j - blocksize)];
|
| - out -= blocksize;
|
| - in -= blocksize;
|
| - inputLen -= blocksize;
|
| - }
|
| - if (in == input) {
|
| - rv = (*decryptor)(cx, out, in);
|
| - if (rv != SECSuccess)
|
| - return rv;
|
| - for (j=0; j<blocksize; ++j)
|
| - out[j] ^= cx->iv[j];
|
| - }
|
| - memcpy(cx->iv, newIV, blocksize);
|
| - return SECSuccess;
|
| -}
|
| -
|
| -/************************************************************************
|
| - *
|
| - * BLAPI Interface functions
|
| - *
|
| - * The following functions implement the encryption routines defined in
|
| - * BLAPI for the AES cipher, Rijndael.
|
| - *
|
| - ***********************************************************************/
|
| -
|
| -AESContext * AES_AllocateContext(void)
|
| -{
|
| - return PORT_ZNew(AESContext);
|
| -}
|
| -
|
| -
|
| -/*
|
| -** Initialize a new AES context suitable for AES encryption/decryption in
|
| -** the ECB or CBC mode.
|
| -** "mode" the mode of operation, which must be NSS_AES or NSS_AES_CBC
|
| -*/
|
| -static SECStatus
|
| -aes_InitContext(AESContext *cx, const unsigned char *key, unsigned int keysize,
|
| - const unsigned char *iv, int mode, unsigned int encrypt,
|
| - unsigned int blocksize)
|
| -{
|
| - unsigned int Nk;
|
| - /* According to Rijndael AES Proposal, section 12.1, block and key
|
| - * lengths between 128 and 256 bits are supported, as long as the
|
| - * length in bytes is divisible by 4.
|
| - */
|
| - if (key == NULL ||
|
| - keysize < RIJNDAEL_MIN_BLOCKSIZE ||
|
| - keysize > RIJNDAEL_MAX_BLOCKSIZE ||
|
| - keysize % 4 != 0 ||
|
| - blocksize < RIJNDAEL_MIN_BLOCKSIZE ||
|
| - blocksize > RIJNDAEL_MAX_BLOCKSIZE ||
|
| - blocksize % 4 != 0) {
|
| - PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
| - return SECFailure;
|
| - }
|
| - if (mode != NSS_AES && mode != NSS_AES_CBC) {
|
| - PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
| - return SECFailure;
|
| - }
|
| - if (mode == NSS_AES_CBC && iv == NULL) {
|
| - PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
| - return SECFailure;
|
| - }
|
| - if (!cx) {
|
| - PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
| - return SECFailure;
|
| - }
|
| -#if USE_HW_AES
|
| - if (has_intel_aes == 0) {
|
| - unsigned long eax, ebx, ecx, edx;
|
| - char *disable_hw_aes = getenv("NSS_DISABLE_HW_AES");
|
| -
|
| - if (disable_hw_aes == NULL) {
|
| - freebl_cpuid(1, &eax, &ebx, &ecx, &edx);
|
| - has_intel_aes = (ecx & (1 << 25)) != 0 ? 1 : -1;
|
| - has_intel_clmul = (ecx & (1 << 1)) != 0 ? 1 : -1;
|
| - has_intel_avx = (ecx & (1 << 28)) != 0 ? 1 : -1;
|
| - } else {
|
| - has_intel_aes = -1;
|
| - has_intel_avx = -1;
|
| - has_intel_clmul = -1;
|
| - }
|
| - }
|
| - use_hw_aes = (PRBool)
|
| - (has_intel_aes > 0 && (keysize % 8) == 0 && blocksize == 16);
|
| - use_hw_gcm = (PRBool)
|
| - (use_hw_aes && has_intel_avx>0 && has_intel_clmul>0);
|
| -#endif
|
| - /* Nb = (block size in bits) / 32 */
|
| - cx->Nb = blocksize / 4;
|
| - /* Nk = (key size in bits) / 32 */
|
| - Nk = keysize / 4;
|
| - /* Obtain number of rounds from "table" */
|
| - cx->Nr = RIJNDAEL_NUM_ROUNDS(Nk, cx->Nb);
|
| - /* copy in the iv, if neccessary */
|
| - if (mode == NSS_AES_CBC) {
|
| - memcpy(cx->iv, iv, blocksize);
|
| -#if USE_HW_AES
|
| - if (use_hw_aes) {
|
| - cx->worker = (freeblCipherFunc)
|
| - intel_aes_cbc_worker(encrypt, keysize);
|
| - } else
|
| -#endif
|
| - cx->worker = (freeblCipherFunc) (encrypt
|
| - ? &rijndael_encryptCBC : &rijndael_decryptCBC);
|
| - } else {
|
| -#if USE_HW_AES
|
| - if (use_hw_aes) {
|
| - cx->worker = (freeblCipherFunc)
|
| - intel_aes_ecb_worker(encrypt, keysize);
|
| - } else
|
| -#endif
|
| - cx->worker = (freeblCipherFunc) (encrypt
|
| - ? &rijndael_encryptECB : &rijndael_decryptECB);
|
| - }
|
| - PORT_Assert((cx->Nb * (cx->Nr + 1)) <= RIJNDAEL_MAX_EXP_KEY_SIZE);
|
| - if ((cx->Nb * (cx->Nr + 1)) > RIJNDAEL_MAX_EXP_KEY_SIZE) {
|
| - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
|
| - goto cleanup;
|
| - }
|
| -#ifdef USE_HW_AES
|
| - if (use_hw_aes) {
|
| - intel_aes_init(encrypt, keysize);
|
| - } else
|
| -#endif
|
| - {
|
| -
|
| -#if defined(RIJNDAEL_GENERATE_TABLES) || \
|
| - defined(RIJNDAEL_GENERATE_TABLES_MACRO)
|
| - if (rijndaelTables == NULL) {
|
| - if (PR_CallOnce(&coRTInit, init_rijndael_tables)
|
| - != PR_SUCCESS) {
|
| - return SecFailure;
|
| - }
|
| - }
|
| -#endif
|
| - /* Generate expanded key */
|
| - if (encrypt) {
|
| - if (rijndael_key_expansion(cx, key, Nk) != SECSuccess)
|
| - goto cleanup;
|
| - } else {
|
| - if (rijndael_invkey_expansion(cx, key, Nk) != SECSuccess)
|
| - goto cleanup;
|
| - }
|
| - }
|
| - cx->worker_cx = cx;
|
| - cx->destroy = NULL;
|
| - cx->isBlock = PR_TRUE;
|
| - return SECSuccess;
|
| -cleanup:
|
| - return SECFailure;
|
| -}
|
| -
|
| -SECStatus
|
| -AES_InitContext(AESContext *cx, const unsigned char *key, unsigned int keysize,
|
| - const unsigned char *iv, int mode, unsigned int encrypt,
|
| - unsigned int blocksize)
|
| -{
|
| - int basemode = mode;
|
| - PRBool baseencrypt = encrypt;
|
| - SECStatus rv;
|
| -
|
| - switch (mode) {
|
| - case NSS_AES_CTS:
|
| - basemode = NSS_AES_CBC;
|
| - break;
|
| - case NSS_AES_GCM:
|
| - case NSS_AES_CTR:
|
| - basemode = NSS_AES;
|
| - baseencrypt = PR_TRUE;
|
| - break;
|
| - }
|
| - /* make sure enough is initializes so we can safely call Destroy */
|
| - cx->worker_cx = NULL;
|
| - cx->destroy = NULL;
|
| - rv = aes_InitContext(cx, key, keysize, iv, basemode,
|
| - baseencrypt, blocksize);
|
| - if (rv != SECSuccess) {
|
| - AES_DestroyContext(cx, PR_FALSE);
|
| - return rv;
|
| - }
|
| -
|
| - /* finally, set up any mode specific contexts */
|
| - switch (mode) {
|
| - case NSS_AES_CTS:
|
| - cx->worker_cx = CTS_CreateContext(cx, cx->worker, iv, blocksize);
|
| - cx->worker = (freeblCipherFunc)
|
| - (encrypt ? CTS_EncryptUpdate : CTS_DecryptUpdate);
|
| - cx->destroy = (freeblDestroyFunc) CTS_DestroyContext;
|
| - cx->isBlock = PR_FALSE;
|
| - break;
|
| - case NSS_AES_GCM:
|
| -#if USE_HW_AES
|
| - if(use_hw_gcm) {
|
| - cx->worker_cx = intel_AES_GCM_CreateContext(cx, cx->worker, iv, blocksize);
|
| - cx->worker = (freeblCipherFunc)
|
| - (encrypt ? intel_AES_GCM_EncryptUpdate : intel_AES_GCM_DecryptUpdate);
|
| - cx->destroy = (freeblDestroyFunc) intel_AES_GCM_DestroyContext;
|
| - cx->isBlock = PR_FALSE;
|
| - } else
|
| -#endif
|
| - {
|
| - cx->worker_cx = GCM_CreateContext(cx, cx->worker, iv, blocksize);
|
| - cx->worker = (freeblCipherFunc)
|
| - (encrypt ? GCM_EncryptUpdate : GCM_DecryptUpdate);
|
| - cx->destroy = (freeblDestroyFunc) GCM_DestroyContext;
|
| - cx->isBlock = PR_FALSE;
|
| - }
|
| - break;
|
| - case NSS_AES_CTR:
|
| - cx->worker_cx = CTR_CreateContext(cx, cx->worker, iv, blocksize);
|
| - cx->worker = (freeblCipherFunc) CTR_Update ;
|
| - cx->destroy = (freeblDestroyFunc) CTR_DestroyContext;
|
| - cx->isBlock = PR_FALSE;
|
| - break;
|
| - default:
|
| - /* everything has already been set up by aes_InitContext, just
|
| - * return */
|
| - return SECSuccess;
|
| - }
|
| - /* check to see if we succeeded in getting the worker context */
|
| - if (cx->worker_cx == NULL) {
|
| - /* no, just destroy the existing context */
|
| - cx->destroy = NULL; /* paranoia, though you can see a dozen lines */
|
| - /* below that this isn't necessary */
|
| - AES_DestroyContext(cx, PR_FALSE);
|
| - return SECFailure;
|
| - }
|
| - return SECSuccess;
|
| -}
|
| -
|
| -/* AES_CreateContext
|
| - *
|
| - * create a new context for Rijndael operations
|
| - */
|
| -AESContext *
|
| -AES_CreateContext(const unsigned char *key, const unsigned char *iv,
|
| - int mode, int encrypt,
|
| - unsigned int keysize, unsigned int blocksize)
|
| -{
|
| - AESContext *cx = AES_AllocateContext();
|
| - if (cx) {
|
| - SECStatus rv = AES_InitContext(cx, key, keysize, iv, mode, encrypt,
|
| - blocksize);
|
| - if (rv != SECSuccess) {
|
| - AES_DestroyContext(cx, PR_TRUE);
|
| - cx = NULL;
|
| - }
|
| - }
|
| - return cx;
|
| -}
|
| -
|
| -/*
|
| - * AES_DestroyContext
|
| - *
|
| - * Zero an AES cipher context. If freeit is true, also free the pointer
|
| - * to the context.
|
| - */
|
| -void
|
| -AES_DestroyContext(AESContext *cx, PRBool freeit)
|
| -{
|
| - if (cx->worker_cx && cx->destroy) {
|
| - (*cx->destroy)(cx->worker_cx, PR_TRUE);
|
| - cx->worker_cx = NULL;
|
| - cx->destroy = NULL;
|
| - }
|
| - if (freeit)
|
| - PORT_Free(cx);
|
| -}
|
| -
|
| -/*
|
| - * AES_Encrypt
|
| - *
|
| - * Encrypt an arbitrary-length buffer. The output buffer must already be
|
| - * allocated to at least inputLen.
|
| - */
|
| -SECStatus
|
| -AES_Encrypt(AESContext *cx, unsigned char *output,
|
| - unsigned int *outputLen, unsigned int maxOutputLen,
|
| - const unsigned char *input, unsigned int inputLen)
|
| -{
|
| - int blocksize;
|
| - /* Check args */
|
| - if (cx == NULL || output == NULL || (input == NULL && inputLen != 0)) {
|
| - PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
| - return SECFailure;
|
| - }
|
| - blocksize = 4 * cx->Nb;
|
| - if (cx->isBlock && (inputLen % blocksize != 0)) {
|
| - PORT_SetError(SEC_ERROR_INPUT_LEN);
|
| - return SECFailure;
|
| - }
|
| - if (maxOutputLen < inputLen) {
|
| - PORT_SetError(SEC_ERROR_OUTPUT_LEN);
|
| - return SECFailure;
|
| - }
|
| - *outputLen = inputLen;
|
| - return (*cx->worker)(cx->worker_cx, output, outputLen, maxOutputLen,
|
| - input, inputLen, blocksize);
|
| -}
|
| -
|
| -/*
|
| - * AES_Decrypt
|
| - *
|
| - * Decrypt and arbitrary-length buffer. The output buffer must already be
|
| - * allocated to at least inputLen.
|
| - */
|
| -SECStatus
|
| -AES_Decrypt(AESContext *cx, unsigned char *output,
|
| - unsigned int *outputLen, unsigned int maxOutputLen,
|
| - const unsigned char *input, unsigned int inputLen)
|
| -{
|
| - int blocksize;
|
| - /* Check args */
|
| - if (cx == NULL || output == NULL || (input == NULL && inputLen != 0)) {
|
| - PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
| - return SECFailure;
|
| - }
|
| - blocksize = 4 * cx->Nb;
|
| - if (cx->isBlock && (inputLen % blocksize != 0)) {
|
| - PORT_SetError(SEC_ERROR_INPUT_LEN);
|
| - return SECFailure;
|
| - }
|
| - if (maxOutputLen < inputLen) {
|
| - PORT_SetError(SEC_ERROR_OUTPUT_LEN);
|
| - return SECFailure;
|
| - }
|
| - *outputLen = inputLen;
|
| - return (*cx->worker)(cx->worker_cx, output, outputLen, maxOutputLen,
|
| - input, inputLen, blocksize);
|
| -}
|
|
|