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); |
-} |