| /* Rijndael (AES) for GnuPG |
| * Copyright (C) 2000, 2001, 2002, 2003, 2007, |
| * 2008 Free Software Foundation, Inc. |
| * |
| * This file is part of Libgcrypt. |
| * |
| * Libgcrypt is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU Lesser General Public License as |
| * published by the Free Software Foundation; either version 2.1 of |
| * the License, or (at your option) any later version. |
| * |
| * Libgcrypt is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this program; if not, see <http://www.gnu.org/licenses/>. |
| ******************************************************************* |
| * The code here is based on the optimized implementation taken from |
| * http://www.esat.kuleuven.ac.be/~rijmen/rijndael/ on Oct 2, 2000, |
| * which carries this notice: |
| *------------------------------------------ |
| * rijndael-alg-fst.c v2.3 April '2000 |
| * |
| * Optimised ANSI C code |
| * |
| * authors: v1.0: Antoon Bosselaers |
| * v2.0: Vincent Rijmen |
| * v2.3: Paulo Barreto |
| * |
| * This code is placed in the public domain. |
| *------------------------------------------ |
| * |
| * The SP800-38a document is available at: |
| * http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf |
| * |
| */ |
| |
| #include <config.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> /* for memcmp() */ |
| |
| #include "types.h" /* for byte and u32 typedefs */ |
| #include "g10lib.h" |
| #include "cipher.h" |
| |
| #define MAXKC (256/32) |
| #define MAXROUNDS 14 |
| #define BLOCKSIZE (128/8) |
| |
| |
| /* USE_PADLOCK indicates whether to compile the padlock specific |
| code. */ |
| #undef USE_PADLOCK |
| #ifdef ENABLE_PADLOCK_SUPPORT |
| # if defined (__i386__) && SIZEOF_UNSIGNED_LONG == 4 && defined (__GNUC__) |
| # define USE_PADLOCK |
| # endif |
| #endif /*ENABLE_PADLOCK_SUPPORT*/ |
| |
| static const char *selftest(void); |
| |
| typedef struct |
| { |
| int ROUNDS; /* Key-length-dependent number of rounds. */ |
| int decryption_prepared; /* The decryption key schedule is available. */ |
| #ifdef USE_PADLOCK |
| int use_padlock; /* Padlock shall be used. */ |
| /* The key as passed to the padlock engine. */ |
| unsigned char padlock_key[16] __attribute__ ((aligned (16))); |
| #endif |
| union |
| { |
| PROPERLY_ALIGNED_TYPE dummy; |
| byte keyschedule[MAXROUNDS+1][4][4]; |
| } u1; |
| union |
| { |
| PROPERLY_ALIGNED_TYPE dummy; |
| byte keyschedule[MAXROUNDS+1][4][4]; |
| } u2; |
| } RIJNDAEL_context; |
| |
| #define keySched u1.keyschedule |
| #define keySched2 u2.keyschedule |
| |
| /* All the numbers. */ |
| #include "rijndael-tables.h" |
| |
| |
| /* Perform the key setup. */ |
| static gcry_err_code_t |
| do_setkey (RIJNDAEL_context *ctx, const byte *key, const unsigned keylen) |
| { |
| static int initialized = 0; |
| static const char *selftest_failed=0; |
| int ROUNDS; |
| int i,j, r, t, rconpointer = 0; |
| int KC; |
| union |
| { |
| PROPERLY_ALIGNED_TYPE dummy; |
| byte k[MAXKC][4]; |
| } k; |
| #define k k.k |
| union |
| { |
| PROPERLY_ALIGNED_TYPE dummy; |
| byte tk[MAXKC][4]; |
| } tk; |
| #define tk tk.tk |
| |
| /* The on-the-fly self tests are only run in non-fips mode. In fips |
| mode explicit self-tests are required. Actually the on-the-fly |
| self-tests are not fully thread-safe and it might happen that a |
| failed self-test won't get noticed in another thread. |
| |
| FIXME: We might want to have a central registry of succeeded |
| self-tests. */ |
| if (!fips_mode () && !initialized) |
| { |
| initialized = 1; |
| selftest_failed = selftest (); |
| if (selftest_failed) |
| log_error ("%s\n", selftest_failed ); |
| } |
| if (selftest_failed) |
| return GPG_ERR_SELFTEST_FAILED; |
| |
| ctx->decryption_prepared = 0; |
| #ifdef USE_PADLOCK |
| ctx->use_padlock = 0; |
| #endif |
| |
| if( keylen == 128/8 ) |
| { |
| ROUNDS = 10; |
| KC = 4; |
| #ifdef USE_PADLOCK |
| if ((_gcry_get_hw_features () & HWF_PADLOCK_AES)) |
| { |
| ctx->use_padlock = 1; |
| memcpy (ctx->padlock_key, key, keylen); |
| } |
| #endif |
| } |
| else if ( keylen == 192/8 ) |
| { |
| ROUNDS = 12; |
| KC = 6; |
| } |
| else if ( keylen == 256/8 ) |
| { |
| ROUNDS = 14; |
| KC = 8; |
| } |
| else |
| return GPG_ERR_INV_KEYLEN; |
| |
| ctx->ROUNDS = ROUNDS; |
| |
| #ifdef USE_PADLOCK |
| if (ctx->use_padlock) |
| { |
| /* Nothing to do as we support only hardware key generation for |
| now. */ |
| } |
| else |
| #endif /*USE_PADLOCK*/ |
| { |
| #define W (ctx->keySched) |
| for (i = 0; i < keylen; i++) |
| { |
| k[i >> 2][i & 3] = key[i]; |
| } |
| |
| for (j = KC-1; j >= 0; j--) |
| { |
| *((u32*)tk[j]) = *((u32*)k[j]); |
| } |
| r = 0; |
| t = 0; |
| /* Copy values into round key array. */ |
| for (j = 0; (j < KC) && (r < ROUNDS + 1); ) |
| { |
| for (; (j < KC) && (t < 4); j++, t++) |
| { |
| *((u32*)W[r][t]) = *((u32*)tk[j]); |
| } |
| if (t == 4) |
| { |
| r++; |
| t = 0; |
| } |
| } |
| |
| while (r < ROUNDS + 1) |
| { |
| /* While not enough round key material calculated calculate |
| new values. */ |
| tk[0][0] ^= S[tk[KC-1][1]]; |
| tk[0][1] ^= S[tk[KC-1][2]]; |
| tk[0][2] ^= S[tk[KC-1][3]]; |
| tk[0][3] ^= S[tk[KC-1][0]]; |
| tk[0][0] ^= rcon[rconpointer++]; |
| |
| if (KC != 8) |
| { |
| for (j = 1; j < KC; j++) |
| { |
| *((u32*)tk[j]) ^= *((u32*)tk[j-1]); |
| } |
| } |
| else |
| { |
| for (j = 1; j < KC/2; j++) |
| { |
| *((u32*)tk[j]) ^= *((u32*)tk[j-1]); |
| } |
| tk[KC/2][0] ^= S[tk[KC/2 - 1][0]]; |
| tk[KC/2][1] ^= S[tk[KC/2 - 1][1]]; |
| tk[KC/2][2] ^= S[tk[KC/2 - 1][2]]; |
| tk[KC/2][3] ^= S[tk[KC/2 - 1][3]]; |
| for (j = KC/2 + 1; j < KC; j++) |
| { |
| *((u32*)tk[j]) ^= *((u32*)tk[j-1]); |
| } |
| } |
| |
| /* Copy values into round key array. */ |
| for (j = 0; (j < KC) && (r < ROUNDS + 1); ) |
| { |
| for (; (j < KC) && (t < 4); j++, t++) |
| { |
| *((u32*)W[r][t]) = *((u32*)tk[j]); |
| } |
| if (t == 4) |
| { |
| r++; |
| t = 0; |
| } |
| } |
| } |
| #undef W |
| } |
| |
| return 0; |
| #undef tk |
| #undef k |
| } |
| |
| |
| static gcry_err_code_t |
| rijndael_setkey (void *context, const byte *key, const unsigned keylen) |
| { |
| RIJNDAEL_context *ctx = context; |
| |
| int rc = do_setkey (ctx, key, keylen); |
| _gcry_burn_stack ( 100 + 16*sizeof(int)); |
| return rc; |
| } |
| |
| |
| /* Make a decryption key from an encryption key. */ |
| static void |
| prepare_decryption( RIJNDAEL_context *ctx ) |
| { |
| int r; |
| union |
| { |
| PROPERLY_ALIGNED_TYPE dummy; |
| byte *w; |
| } w; |
| #define w w.w |
| |
| for (r=0; r < MAXROUNDS+1; r++ ) |
| { |
| *((u32*)ctx->keySched2[r][0]) = *((u32*)ctx->keySched[r][0]); |
| *((u32*)ctx->keySched2[r][1]) = *((u32*)ctx->keySched[r][1]); |
| *((u32*)ctx->keySched2[r][2]) = *((u32*)ctx->keySched[r][2]); |
| *((u32*)ctx->keySched2[r][3]) = *((u32*)ctx->keySched[r][3]); |
| } |
| #define W (ctx->keySched2) |
| for (r = 1; r < ctx->ROUNDS; r++) |
| { |
| w = W[r][0]; |
| *((u32*)w) = *((u32*)U1[w[0]]) ^ *((u32*)U2[w[1]]) |
| ^ *((u32*)U3[w[2]]) ^ *((u32*)U4[w[3]]); |
| |
| w = W[r][1]; |
| *((u32*)w) = *((u32*)U1[w[0]]) ^ *((u32*)U2[w[1]]) |
| ^ *((u32*)U3[w[2]]) ^ *((u32*)U4[w[3]]); |
| |
| w = W[r][2]; |
| *((u32*)w) = *((u32*)U1[w[0]]) ^ *((u32*)U2[w[1]]) |
| ^ *((u32*)U3[w[2]]) ^ *((u32*)U4[w[3]]); |
| |
| w = W[r][3]; |
| *((u32*)w) = *((u32*)U1[w[0]]) ^ *((u32*)U2[w[1]]) |
| ^ *((u32*)U3[w[2]]) ^ *((u32*)U4[w[3]]); |
| } |
| #undef W |
| #undef w |
| } |
| |
| |
| |
| /* Encrypt one block. A and B need to be aligned on a 4 byte |
| boundary. A and B may be the same. */ |
| static void |
| do_encrypt_aligned (const RIJNDAEL_context *ctx, |
| unsigned char *b, const unsigned char *a) |
| { |
| #define rk (ctx->keySched) |
| int ROUNDS = ctx->ROUNDS; |
| int r; |
| union |
| { |
| u32 tempu32[4]; /* Force correct alignment. */ |
| byte temp[4][4]; |
| } u; |
| |
| *((u32*)u.temp[0]) = *((u32*)(a )) ^ *((u32*)rk[0][0]); |
| *((u32*)u.temp[1]) = *((u32*)(a+ 4)) ^ *((u32*)rk[0][1]); |
| *((u32*)u.temp[2]) = *((u32*)(a+ 8)) ^ *((u32*)rk[0][2]); |
| *((u32*)u.temp[3]) = *((u32*)(a+12)) ^ *((u32*)rk[0][3]); |
| *((u32*)(b )) = (*((u32*)T1[u.temp[0][0]]) |
| ^ *((u32*)T2[u.temp[1][1]]) |
| ^ *((u32*)T3[u.temp[2][2]]) |
| ^ *((u32*)T4[u.temp[3][3]])); |
| *((u32*)(b + 4)) = (*((u32*)T1[u.temp[1][0]]) |
| ^ *((u32*)T2[u.temp[2][1]]) |
| ^ *((u32*)T3[u.temp[3][2]]) |
| ^ *((u32*)T4[u.temp[0][3]])); |
| *((u32*)(b + 8)) = (*((u32*)T1[u.temp[2][0]]) |
| ^ *((u32*)T2[u.temp[3][1]]) |
| ^ *((u32*)T3[u.temp[0][2]]) |
| ^ *((u32*)T4[u.temp[1][3]])); |
| *((u32*)(b +12)) = (*((u32*)T1[u.temp[3][0]]) |
| ^ *((u32*)T2[u.temp[0][1]]) |
| ^ *((u32*)T3[u.temp[1][2]]) |
| ^ *((u32*)T4[u.temp[2][3]])); |
| |
| for (r = 1; r < ROUNDS-1; r++) |
| { |
| *((u32*)u.temp[0]) = *((u32*)(b )) ^ *((u32*)rk[r][0]); |
| *((u32*)u.temp[1]) = *((u32*)(b+ 4)) ^ *((u32*)rk[r][1]); |
| *((u32*)u.temp[2]) = *((u32*)(b+ 8)) ^ *((u32*)rk[r][2]); |
| *((u32*)u.temp[3]) = *((u32*)(b+12)) ^ *((u32*)rk[r][3]); |
| |
| *((u32*)(b )) = (*((u32*)T1[u.temp[0][0]]) |
| ^ *((u32*)T2[u.temp[1][1]]) |
| ^ *((u32*)T3[u.temp[2][2]]) |
| ^ *((u32*)T4[u.temp[3][3]])); |
| *((u32*)(b + 4)) = (*((u32*)T1[u.temp[1][0]]) |
| ^ *((u32*)T2[u.temp[2][1]]) |
| ^ *((u32*)T3[u.temp[3][2]]) |
| ^ *((u32*)T4[u.temp[0][3]])); |
| *((u32*)(b + 8)) = (*((u32*)T1[u.temp[2][0]]) |
| ^ *((u32*)T2[u.temp[3][1]]) |
| ^ *((u32*)T3[u.temp[0][2]]) |
| ^ *((u32*)T4[u.temp[1][3]])); |
| *((u32*)(b +12)) = (*((u32*)T1[u.temp[3][0]]) |
| ^ *((u32*)T2[u.temp[0][1]]) |
| ^ *((u32*)T3[u.temp[1][2]]) |
| ^ *((u32*)T4[u.temp[2][3]])); |
| } |
| |
| /* Last round is special. */ |
| *((u32*)u.temp[0]) = *((u32*)(b )) ^ *((u32*)rk[ROUNDS-1][0]); |
| *((u32*)u.temp[1]) = *((u32*)(b+ 4)) ^ *((u32*)rk[ROUNDS-1][1]); |
| *((u32*)u.temp[2]) = *((u32*)(b+ 8)) ^ *((u32*)rk[ROUNDS-1][2]); |
| *((u32*)u.temp[3]) = *((u32*)(b+12)) ^ *((u32*)rk[ROUNDS-1][3]); |
| b[ 0] = T1[u.temp[0][0]][1]; |
| b[ 1] = T1[u.temp[1][1]][1]; |
| b[ 2] = T1[u.temp[2][2]][1]; |
| b[ 3] = T1[u.temp[3][3]][1]; |
| b[ 4] = T1[u.temp[1][0]][1]; |
| b[ 5] = T1[u.temp[2][1]][1]; |
| b[ 6] = T1[u.temp[3][2]][1]; |
| b[ 7] = T1[u.temp[0][3]][1]; |
| b[ 8] = T1[u.temp[2][0]][1]; |
| b[ 9] = T1[u.temp[3][1]][1]; |
| b[10] = T1[u.temp[0][2]][1]; |
| b[11] = T1[u.temp[1][3]][1]; |
| b[12] = T1[u.temp[3][0]][1]; |
| b[13] = T1[u.temp[0][1]][1]; |
| b[14] = T1[u.temp[1][2]][1]; |
| b[15] = T1[u.temp[2][3]][1]; |
| *((u32*)(b )) ^= *((u32*)rk[ROUNDS][0]); |
| *((u32*)(b+ 4)) ^= *((u32*)rk[ROUNDS][1]); |
| *((u32*)(b+ 8)) ^= *((u32*)rk[ROUNDS][2]); |
| *((u32*)(b+12)) ^= *((u32*)rk[ROUNDS][3]); |
| #undef rk |
| } |
| |
| |
| static void |
| do_encrypt (const RIJNDAEL_context *ctx, |
| unsigned char *bx, const unsigned char *ax) |
| { |
| /* BX and AX are not necessary correctly aligned. Thus we need to |
| copy them here. */ |
| union |
| { |
| u32 dummy[4]; |
| byte a[16]; |
| } a; |
| union |
| { |
| u32 dummy[4]; |
| byte b[16]; |
| } b; |
| |
| memcpy (a.a, ax, 16); |
| do_encrypt_aligned (ctx, b.b, a.a); |
| memcpy (bx, b.b, 16); |
| } |
| |
| |
| /* Encrypt or decrypt one block using the padlock engine. A and B may |
| be the same. */ |
| #ifdef USE_PADLOCK |
| static void |
| do_padlock (const RIJNDAEL_context *ctx, int decrypt_flag, |
| unsigned char *bx, const unsigned char *ax) |
| { |
| /* BX and AX are not necessary correctly aligned. Thus we need to |
| copy them here. */ |
| unsigned char a[16] __attribute__ ((aligned (16))); |
| unsigned char b[16] __attribute__ ((aligned (16))); |
| unsigned int cword[4] __attribute__ ((aligned (16))); |
| |
| /* The control word fields are: |
| 127:12 11:10 9 8 7 6 5 4 3:0 |
| RESERVED KSIZE CRYPT INTER KEYGN CIPHR ALIGN DGEST ROUND */ |
| cword[0] = (ctx->ROUNDS & 15); /* (The mask is just a safeguard.) */ |
| cword[1] = 0; |
| cword[2] = 0; |
| cword[3] = 0; |
| if (decrypt_flag) |
| cword[0] |= 0x00000200; |
| |
| memcpy (a, ax, 16); |
| |
| asm volatile |
| ("pushfl\n\t" /* Force key reload. */ |
| "popfl\n\t" |
| "xchg %3, %%ebx\n\t" /* Load key. */ |
| "movl $1, %%ecx\n\t" /* Init counter for just one block. */ |
| ".byte 0xf3, 0x0f, 0xa7, 0xc8\n\t" /* REP XSTORE ECB. */ |
| "xchg %3, %%ebx\n" /* Restore GOT register. */ |
| : /* No output */ |
| : "S" (a), "D" (b), "d" (cword), "r" (ctx->padlock_key) |
| : "%ecx", "cc", "memory" |
| ); |
| |
| memcpy (bx, b, 16); |
| |
| } |
| #endif /*USE_PADLOCK*/ |
| |
| |
| static void |
| rijndael_encrypt (void *context, byte *b, const byte *a) |
| { |
| RIJNDAEL_context *ctx = context; |
| |
| #ifdef USE_PADLOCK |
| if (ctx->use_padlock) |
| { |
| do_padlock (ctx, 0, b, a); |
| _gcry_burn_stack (48 + 15 /* possible padding for alignment */); |
| } |
| else |
| #endif /*USE_PADLOCK*/ |
| { |
| do_encrypt (ctx, b, a); |
| _gcry_burn_stack (48 + 2*sizeof(int)); |
| } |
| } |
| |
| |
| /* Bulk encryption of complete blocks in CFB mode. Caller needs to |
| make sure that IV is aligned on an unsigned long boundary. This |
| function is only intended for the bulk encryption feature of |
| cipher.c. */ |
| void |
| _gcry_aes_cfb_enc (void *context, unsigned char *iv, |
| void *outbuf_arg, const void *inbuf_arg, |
| unsigned int nblocks) |
| { |
| RIJNDAEL_context *ctx = context; |
| unsigned char *outbuf = outbuf_arg; |
| const unsigned char *inbuf = inbuf_arg; |
| unsigned char *ivp; |
| int i; |
| |
| #ifdef USE_PADLOCK |
| if (ctx->use_padlock) |
| { |
| /* Fixme: Let Padlock do the CFBing. */ |
| for ( ;nblocks; nblocks-- ) |
| { |
| /* Encrypt the IV. */ |
| do_padlock (ctx, 0, iv, iv); |
| /* XOR the input with the IV and store input into IV. */ |
| for (ivp=iv,i=0; i < BLOCKSIZE; i++ ) |
| *outbuf++ = (*ivp++ ^= *inbuf++); |
| } |
| } |
| else |
| #endif /* USE_PADLOCK*/ |
| { |
| for ( ;nblocks; nblocks-- ) |
| { |
| /* Encrypt the IV. */ |
| do_encrypt_aligned (ctx, iv, iv); |
| /* XOR the input with the IV and store input into IV. */ |
| for (ivp=iv,i=0; i < BLOCKSIZE; i++ ) |
| *outbuf++ = (*ivp++ ^= *inbuf++); |
| } |
| } |
| |
| _gcry_burn_stack (48 + 2*sizeof(int)); |
| } |
| |
| |
| /* Bulk encryption of complete blocks in CBC mode. Caller needs to |
| make sure that IV is aligned on an unsigned long boundary. This |
| function is only intended for the bulk encryption feature of |
| cipher.c. */ |
| void |
| _gcry_aes_cbc_enc (void *context, unsigned char *iv, |
| void *outbuf_arg, const void *inbuf_arg, |
| unsigned int nblocks, int cbc_mac) |
| { |
| RIJNDAEL_context *ctx = context; |
| unsigned char *outbuf = outbuf_arg; |
| const unsigned char *inbuf = inbuf_arg; |
| unsigned char *ivp; |
| int i; |
| |
| for ( ;nblocks; nblocks-- ) |
| { |
| for (ivp=iv, i=0; i < BLOCKSIZE; i++ ) |
| outbuf[i] = inbuf[i] ^ *ivp++; |
| |
| #ifdef USE_PADLOCK |
| if (ctx->use_padlock) |
| do_padlock (ctx, 0, outbuf, outbuf); |
| else |
| #endif /*USE_PADLOCK*/ |
| do_encrypt (ctx, outbuf, outbuf ); |
| |
| memcpy (iv, outbuf, BLOCKSIZE); |
| inbuf += BLOCKSIZE; |
| if (!cbc_mac) |
| outbuf += BLOCKSIZE; |
| } |
| |
| _gcry_burn_stack (48 + 2*sizeof(int)); |
| } |
| |
| |
| |
| /* Decrypt one block. A and B need to be aligned on a 4 byte boundary |
| and the decryption must have been prepared. A and B may be the |
| same. */ |
| static void |
| do_decrypt_aligned (RIJNDAEL_context *ctx, |
| unsigned char *b, const unsigned char *a) |
| { |
| #define rk (ctx->keySched2) |
| int ROUNDS = ctx->ROUNDS; |
| int r; |
| union |
| { |
| u32 tempu32[4]; /* Force correct alignment. */ |
| byte temp[4][4]; |
| } u; |
| |
| |
| *((u32*)u.temp[0]) = *((u32*)(a )) ^ *((u32*)rk[ROUNDS][0]); |
| *((u32*)u.temp[1]) = *((u32*)(a+ 4)) ^ *((u32*)rk[ROUNDS][1]); |
| *((u32*)u.temp[2]) = *((u32*)(a+ 8)) ^ *((u32*)rk[ROUNDS][2]); |
| *((u32*)u.temp[3]) = *((u32*)(a+12)) ^ *((u32*)rk[ROUNDS][3]); |
| |
| *((u32*)(b )) = (*((u32*)T5[u.temp[0][0]]) |
| ^ *((u32*)T6[u.temp[3][1]]) |
| ^ *((u32*)T7[u.temp[2][2]]) |
| ^ *((u32*)T8[u.temp[1][3]])); |
| *((u32*)(b+ 4)) = (*((u32*)T5[u.temp[1][0]]) |
| ^ *((u32*)T6[u.temp[0][1]]) |
| ^ *((u32*)T7[u.temp[3][2]]) |
| ^ *((u32*)T8[u.temp[2][3]])); |
| *((u32*)(b+ 8)) = (*((u32*)T5[u.temp[2][0]]) |
| ^ *((u32*)T6[u.temp[1][1]]) |
| ^ *((u32*)T7[u.temp[0][2]]) |
| ^ *((u32*)T8[u.temp[3][3]])); |
| *((u32*)(b+12)) = (*((u32*)T5[u.temp[3][0]]) |
| ^ *((u32*)T6[u.temp[2][1]]) |
| ^ *((u32*)T7[u.temp[1][2]]) |
| ^ *((u32*)T8[u.temp[0][3]])); |
| |
| for (r = ROUNDS-1; r > 1; r--) |
| { |
| *((u32*)u.temp[0]) = *((u32*)(b )) ^ *((u32*)rk[r][0]); |
| *((u32*)u.temp[1]) = *((u32*)(b+ 4)) ^ *((u32*)rk[r][1]); |
| *((u32*)u.temp[2]) = *((u32*)(b+ 8)) ^ *((u32*)rk[r][2]); |
| *((u32*)u.temp[3]) = *((u32*)(b+12)) ^ *((u32*)rk[r][3]); |
| *((u32*)(b )) = (*((u32*)T5[u.temp[0][0]]) |
| ^ *((u32*)T6[u.temp[3][1]]) |
| ^ *((u32*)T7[u.temp[2][2]]) |
| ^ *((u32*)T8[u.temp[1][3]])); |
| *((u32*)(b+ 4)) = (*((u32*)T5[u.temp[1][0]]) |
| ^ *((u32*)T6[u.temp[0][1]]) |
| ^ *((u32*)T7[u.temp[3][2]]) |
| ^ *((u32*)T8[u.temp[2][3]])); |
| *((u32*)(b+ 8)) = (*((u32*)T5[u.temp[2][0]]) |
| ^ *((u32*)T6[u.temp[1][1]]) |
| ^ *((u32*)T7[u.temp[0][2]]) |
| ^ *((u32*)T8[u.temp[3][3]])); |
| *((u32*)(b+12)) = (*((u32*)T5[u.temp[3][0]]) |
| ^ *((u32*)T6[u.temp[2][1]]) |
| ^ *((u32*)T7[u.temp[1][2]]) |
| ^ *((u32*)T8[u.temp[0][3]])); |
| } |
| |
| /* Last round is special. */ |
| *((u32*)u.temp[0]) = *((u32*)(b )) ^ *((u32*)rk[1][0]); |
| *((u32*)u.temp[1]) = *((u32*)(b+ 4)) ^ *((u32*)rk[1][1]); |
| *((u32*)u.temp[2]) = *((u32*)(b+ 8)) ^ *((u32*)rk[1][2]); |
| *((u32*)u.temp[3]) = *((u32*)(b+12)) ^ *((u32*)rk[1][3]); |
| b[ 0] = S5[u.temp[0][0]]; |
| b[ 1] = S5[u.temp[3][1]]; |
| b[ 2] = S5[u.temp[2][2]]; |
| b[ 3] = S5[u.temp[1][3]]; |
| b[ 4] = S5[u.temp[1][0]]; |
| b[ 5] = S5[u.temp[0][1]]; |
| b[ 6] = S5[u.temp[3][2]]; |
| b[ 7] = S5[u.temp[2][3]]; |
| b[ 8] = S5[u.temp[2][0]]; |
| b[ 9] = S5[u.temp[1][1]]; |
| b[10] = S5[u.temp[0][2]]; |
| b[11] = S5[u.temp[3][3]]; |
| b[12] = S5[u.temp[3][0]]; |
| b[13] = S5[u.temp[2][1]]; |
| b[14] = S5[u.temp[1][2]]; |
| b[15] = S5[u.temp[0][3]]; |
| *((u32*)(b )) ^= *((u32*)rk[0][0]); |
| *((u32*)(b+ 4)) ^= *((u32*)rk[0][1]); |
| *((u32*)(b+ 8)) ^= *((u32*)rk[0][2]); |
| *((u32*)(b+12)) ^= *((u32*)rk[0][3]); |
| #undef rk |
| } |
| |
| |
| /* Decrypt one block. AX and BX may be the same. */ |
| static void |
| do_decrypt (RIJNDAEL_context *ctx, byte *bx, const byte *ax) |
| { |
| /* BX and AX are not necessary correctly aligned. Thus we need to |
| copy them here. */ |
| union |
| { |
| u32 dummy[4]; |
| byte a[16]; |
| } a; |
| union |
| { |
| u32 dummy[4]; |
| byte b[16]; |
| } b; |
| |
| if ( !ctx->decryption_prepared ) |
| { |
| prepare_decryption ( ctx ); |
| _gcry_burn_stack (64); |
| ctx->decryption_prepared = 1; |
| } |
| |
| memcpy (a.a, ax, 16); |
| do_decrypt_aligned (ctx, b.b, a.a); |
| memcpy (bx, b.b, 16); |
| #undef rk |
| } |
| |
| |
| |
| |
| static void |
| rijndael_decrypt (void *context, byte *b, const byte *a) |
| { |
| RIJNDAEL_context *ctx = context; |
| |
| #ifdef USE_PADLOCK |
| if (ctx->use_padlock) |
| { |
| do_padlock (ctx, 1, b, a); |
| _gcry_burn_stack (48 + 2*sizeof(int) /* FIXME */); |
| } |
| else |
| #endif /*USE_PADLOCK*/ |
| { |
| do_decrypt (ctx, b, a); |
| _gcry_burn_stack (48+2*sizeof(int)); |
| } |
| } |
| |
| |
| /* Bulk decryption of complete blocks in CFB mode. Caller needs to |
| make sure that IV is aligned on an unisgned lonhg boundary. This |
| function is only intended for the bulk encryption feature of |
| cipher.c. */ |
| void |
| _gcry_aes_cfb_dec (void *context, unsigned char *iv, |
| void *outbuf_arg, const void *inbuf_arg, |
| unsigned int nblocks) |
| { |
| RIJNDAEL_context *ctx = context; |
| unsigned char *outbuf = outbuf_arg; |
| const unsigned char *inbuf = inbuf_arg; |
| unsigned char *ivp; |
| unsigned char temp; |
| int i; |
| |
| #ifdef USE_PADLOCK |
| if (ctx->use_padlock) |
| { |
| /* Fixme: Let Padlock do the CFBing. */ |
| for ( ;nblocks; nblocks-- ) |
| { |
| do_padlock (ctx, 0, iv, iv); |
| for (ivp=iv,i=0; i < BLOCKSIZE; i++ ) |
| { |
| temp = *inbuf++; |
| *outbuf++ = *ivp ^ temp; |
| *ivp++ = temp; |
| } |
| } |
| } |
| else |
| #endif /*USE_PADLOCK*/ |
| { |
| for ( ;nblocks; nblocks-- ) |
| { |
| do_encrypt_aligned (ctx, iv, iv); |
| for (ivp=iv,i=0; i < BLOCKSIZE; i++ ) |
| { |
| temp = *inbuf++; |
| *outbuf++ = *ivp ^ temp; |
| *ivp++ = temp; |
| } |
| } |
| } |
| |
| _gcry_burn_stack (48 + 2*sizeof(int)); |
| } |
| |
| |
| /* Bulk decryption of complete blocks in CBC mode. Caller needs to |
| make sure that IV is aligned on an unsigned long boundary. This |
| function is only intended for the bulk encryption feature of |
| cipher.c. */ |
| void |
| _gcry_aes_cbc_dec (void *context, unsigned char *iv, |
| void *outbuf_arg, const void *inbuf_arg, |
| unsigned int nblocks) |
| { |
| RIJNDAEL_context *ctx = context; |
| unsigned char *outbuf = outbuf_arg; |
| const unsigned char *inbuf = inbuf_arg; |
| unsigned char *ivp; |
| int i; |
| unsigned char savebuf[BLOCKSIZE]; |
| |
| for ( ;nblocks; nblocks-- ) |
| { |
| /* We need to save INBUF away because it may be identical to |
| OUTBUF. */ |
| memcpy (savebuf, inbuf, BLOCKSIZE); |
| |
| #ifdef USE_PADLOCK |
| if (ctx->use_padlock) |
| do_padlock (ctx, 1, outbuf, inbuf); |
| else |
| #endif /*USE_PADLOCK*/ |
| do_decrypt (ctx, outbuf, inbuf); |
| |
| for (ivp=iv, i=0; i < BLOCKSIZE; i++ ) |
| outbuf[i] ^= *ivp++; |
| memcpy (iv, savebuf, BLOCKSIZE); |
| inbuf += BLOCKSIZE; |
| outbuf += BLOCKSIZE; |
| } |
| |
| _gcry_burn_stack (48 + 2*sizeof(int) + BLOCKSIZE + 4*sizeof (char*)); |
| } |
| |
| |
| |
| |
| /* Run the self-tests for AES 128. Returns NULL on success. */ |
| static const char* |
| selftest_basic_128 (void) |
| { |
| RIJNDAEL_context ctx; |
| unsigned char scratch[16]; |
| |
| /* The test vectors are from the AES supplied ones; more or less |
| randomly taken from ecb_tbl.txt (I=42,81,14) */ |
| static const unsigned char plaintext_128[16] = |
| { |
| 0x01,0x4B,0xAF,0x22,0x78,0xA6,0x9D,0x33, |
| 0x1D,0x51,0x80,0x10,0x36,0x43,0xE9,0x9A |
| }; |
| static const unsigned char key_128[16] = |
| { |
| 0xE8,0xE9,0xEA,0xEB,0xED,0xEE,0xEF,0xF0, |
| 0xF2,0xF3,0xF4,0xF5,0xF7,0xF8,0xF9,0xFA |
| }; |
| static const unsigned char ciphertext_128[16] = |
| { |
| 0x67,0x43,0xC3,0xD1,0x51,0x9A,0xB4,0xF2, |
| 0xCD,0x9A,0x78,0xAB,0x09,0xA5,0x11,0xBD |
| }; |
| |
| rijndael_setkey (&ctx, key_128, sizeof (key_128)); |
| rijndael_encrypt (&ctx, scratch, plaintext_128); |
| if (memcmp (scratch, ciphertext_128, sizeof (ciphertext_128))) |
| return "AES-128 test encryption failed."; |
| rijndael_decrypt (&ctx, scratch, scratch); |
| if (memcmp (scratch, plaintext_128, sizeof (plaintext_128))) |
| return "AES-128 test decryption failed."; |
| |
| return NULL; |
| } |
| |
| /* Run the self-tests for AES 192. Returns NULL on success. */ |
| static const char* |
| selftest_basic_192 (void) |
| { |
| RIJNDAEL_context ctx; |
| unsigned char scratch[16]; |
| |
| static unsigned char plaintext_192[16] = |
| { |
| 0x76,0x77,0x74,0x75,0xF1,0xF2,0xF3,0xF4, |
| 0xF8,0xF9,0xE6,0xE7,0x77,0x70,0x71,0x72 |
| }; |
| static unsigned char key_192[24] = |
| { |
| 0x04,0x05,0x06,0x07,0x09,0x0A,0x0B,0x0C, |
| 0x0E,0x0F,0x10,0x11,0x13,0x14,0x15,0x16, |
| 0x18,0x19,0x1A,0x1B,0x1D,0x1E,0x1F,0x20 |
| }; |
| static const unsigned char ciphertext_192[16] = |
| { |
| 0x5D,0x1E,0xF2,0x0D,0xCE,0xD6,0xBC,0xBC, |
| 0x12,0x13,0x1A,0xC7,0xC5,0x47,0x88,0xAA |
| }; |
| |
| rijndael_setkey (&ctx, key_192, sizeof(key_192)); |
| rijndael_encrypt (&ctx, scratch, plaintext_192); |
| if (memcmp (scratch, ciphertext_192, sizeof (ciphertext_192))) |
| return "AES-192 test encryption failed."; |
| rijndael_decrypt (&ctx, scratch, scratch); |
| if (memcmp (scratch, plaintext_192, sizeof (plaintext_192))) |
| return "AES-192 test decryption failed."; |
| |
| return NULL; |
| } |
| |
| |
| /* Run the self-tests for AES 256. Returns NULL on success. */ |
| static const char* |
| selftest_basic_256 (void) |
| { |
| RIJNDAEL_context ctx; |
| unsigned char scratch[16]; |
| |
| static unsigned char plaintext_256[16] = |
| { |
| 0x06,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F, |
| 0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x21 |
| }; |
| static unsigned char key_256[32] = |
| { |
| 0x08,0x09,0x0A,0x0B,0x0D,0x0E,0x0F,0x10, |
| 0x12,0x13,0x14,0x15,0x17,0x18,0x19,0x1A, |
| 0x1C,0x1D,0x1E,0x1F,0x21,0x22,0x23,0x24, |
| 0x26,0x27,0x28,0x29,0x2B,0x2C,0x2D,0x2E |
| }; |
| static const unsigned char ciphertext_256[16] = |
| { |
| 0x08,0x0E,0x95,0x17,0xEB,0x16,0x77,0x71, |
| 0x9A,0xCF,0x72,0x80,0x86,0x04,0x0A,0xE3 |
| }; |
| |
| rijndael_setkey (&ctx, key_256, sizeof(key_256)); |
| rijndael_encrypt (&ctx, scratch, plaintext_256); |
| if (memcmp (scratch, ciphertext_256, sizeof (ciphertext_256))) |
| return "AES-256 test encryption failed."; |
| rijndael_decrypt (&ctx, scratch, scratch); |
| if (memcmp (scratch, plaintext_256, sizeof (plaintext_256))) |
| return "AES-256 test decryption failed."; |
| |
| return NULL; |
| } |
| |
| /* Run all the self-tests and return NULL on success. This function |
| is used for the on-the-fly self-tests. */ |
| static const char * |
| selftest (void) |
| { |
| const char *r; |
| |
| if ( (r = selftest_basic_128 ()) |
| || (r = selftest_basic_192 ()) |
| || (r = selftest_basic_256 ()) ) |
| return r; |
| |
| return r; |
| } |
| |
| |
| /* SP800-38a.pdf for AES-128. */ |
| static const char * |
| selftest_fips_128_38a (int requested_mode) |
| { |
| struct tv |
| { |
| int mode; |
| const unsigned char key[16]; |
| const unsigned char iv[16]; |
| struct |
| { |
| const unsigned char input[16]; |
| const unsigned char output[16]; |
| } data[4]; |
| } tv[2] = |
| { |
| { |
| GCRY_CIPHER_MODE_CFB, /* F.3.13, CFB128-AES128 */ |
| { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, |
| 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c }, |
| { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, |
| 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, |
| { |
| { { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, |
| 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a }, |
| { 0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20, |
| 0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a } }, |
| |
| { { 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, |
| 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51 }, |
| { 0xc8, 0xa6, 0x45, 0x37, 0xa0, 0xb3, 0xa9, 0x3f, |
| 0xcd, 0xe3, 0xcd, 0xad, 0x9f, 0x1c, 0xe5, 0x8b } }, |
| |
| { { 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, |
| 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef }, |
| { 0x26, 0x75, 0x1f, 0x67, 0xa3, 0xcb, 0xb1, 0x40, |
| 0xb1, 0x80, 0x8c, 0xf1, 0x87, 0xa4, 0xf4, 0xdf } }, |
| |
| { { 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, |
| 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 }, |
| { 0xc0, 0x4b, 0x05, 0x35, 0x7c, 0x5d, 0x1c, 0x0e, |
| 0xea, 0xc4, 0xc6, 0x6f, 0x9f, 0xf7, 0xf2, 0xe6 } } |
| } |
| }, |
| { |
| GCRY_CIPHER_MODE_OFB, |
| { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, |
| 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c }, |
| { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, |
| 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, |
| { |
| { { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, |
| 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a }, |
| { 0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20, |
| 0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a } }, |
| |
| { { 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, |
| 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51 }, |
| { 0x77, 0x89, 0x50, 0x8d, 0x16, 0x91, 0x8f, 0x03, |
| 0xf5, 0x3c, 0x52, 0xda, 0xc5, 0x4e, 0xd8, 0x25 } }, |
| |
| { { 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, |
| 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef }, |
| { 0x97, 0x40, 0x05, 0x1e, 0x9c, 0x5f, 0xec, 0xf6, |
| 0x43, 0x44, 0xf7, 0xa8, 0x22, 0x60, 0xed, 0xcc } }, |
| |
| { { 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, |
| 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 }, |
| { 0x30, 0x4c, 0x65, 0x28, 0xf6, 0x59, 0xc7, 0x78, |
| 0x66, 0xa5, 0x10, 0xd9, 0xc1, 0xd6, 0xae, 0x5e } }, |
| } |
| } |
| }; |
| unsigned char scratch[16]; |
| gpg_error_t err; |
| int tvi, idx; |
| gcry_cipher_hd_t hdenc = NULL; |
| gcry_cipher_hd_t hddec = NULL; |
| |
| #define Fail(a) do { \ |
| _gcry_cipher_close (hdenc); \ |
| _gcry_cipher_close (hddec); \ |
| return a; \ |
| } while (0) |
| |
| gcry_assert (sizeof tv[0].data[0].input == sizeof scratch); |
| gcry_assert (sizeof tv[0].data[0].output == sizeof scratch); |
| |
| for (tvi=0; tvi < DIM (tv); tvi++) |
| if (tv[tvi].mode == requested_mode) |
| break; |
| if (tvi == DIM (tv)) |
| Fail ("no test data for this mode"); |
| |
| err = _gcry_cipher_open (&hdenc, GCRY_CIPHER_AES, tv[tvi].mode, 0); |
| if (err) |
| Fail ("open"); |
| err = _gcry_cipher_open (&hddec, GCRY_CIPHER_AES, tv[tvi].mode, 0); |
| if (err) |
| Fail ("open"); |
| err = _gcry_cipher_setkey (hdenc, tv[tvi].key, sizeof tv[tvi].key); |
| if (!err) |
| err = _gcry_cipher_setkey (hddec, tv[tvi].key, sizeof tv[tvi].key); |
| if (err) |
| Fail ("set key"); |
| err = _gcry_cipher_setiv (hdenc, tv[tvi].iv, sizeof tv[tvi].iv); |
| if (!err) |
| err = _gcry_cipher_setiv (hddec, tv[tvi].iv, sizeof tv[tvi].iv); |
| if (err) |
| Fail ("set IV"); |
| for (idx=0; idx < DIM (tv[tvi].data); idx++) |
| { |
| err = _gcry_cipher_encrypt (hdenc, scratch, sizeof scratch, |
| tv[tvi].data[idx].input, |
| sizeof tv[tvi].data[idx].input); |
| if (err) |
| Fail ("encrypt command"); |
| if (memcmp (scratch, tv[tvi].data[idx].output, sizeof scratch)) |
| Fail ("encrypt mismatch"); |
| err = _gcry_cipher_decrypt (hddec, scratch, sizeof scratch, |
| tv[tvi].data[idx].output, |
| sizeof tv[tvi].data[idx].output); |
| if (err) |
| Fail ("decrypt command"); |
| if (memcmp (scratch, tv[tvi].data[idx].input, sizeof scratch)) |
| Fail ("decrypt mismatch"); |
| } |
| |
| #undef Fail |
| _gcry_cipher_close (hdenc); |
| _gcry_cipher_close (hddec); |
| return NULL; |
| } |
| |
| |
| /* Complete selftest for AES-128 with all modes and driver code. */ |
| static gpg_err_code_t |
| selftest_fips_128 (int extended, selftest_report_func_t report) |
| { |
| const char *what; |
| const char *errtxt; |
| |
| what = "low-level"; |
| errtxt = selftest_basic_128 (); |
| if (errtxt) |
| goto failed; |
| |
| if (extended) |
| { |
| what = "cfb"; |
| errtxt = selftest_fips_128_38a (GCRY_CIPHER_MODE_CFB); |
| if (errtxt) |
| goto failed; |
| |
| what = "ofb"; |
| errtxt = selftest_fips_128_38a (GCRY_CIPHER_MODE_OFB); |
| if (errtxt) |
| goto failed; |
| } |
| |
| return 0; /* Succeeded. */ |
| |
| failed: |
| if (report) |
| report ("cipher", GCRY_CIPHER_AES128, what, errtxt); |
| return GPG_ERR_SELFTEST_FAILED; |
| } |
| |
| /* Complete selftest for AES-192. */ |
| static gpg_err_code_t |
| selftest_fips_192 (int extended, selftest_report_func_t report) |
| { |
| const char *what; |
| const char *errtxt; |
| |
| (void)extended; /* No extended tests available. */ |
| |
| what = "low-level"; |
| errtxt = selftest_basic_192 (); |
| if (errtxt) |
| goto failed; |
| |
| |
| return 0; /* Succeeded. */ |
| |
| failed: |
| if (report) |
| report ("cipher", GCRY_CIPHER_AES192, what, errtxt); |
| return GPG_ERR_SELFTEST_FAILED; |
| } |
| |
| |
| /* Complete selftest for AES-256. */ |
| static gpg_err_code_t |
| selftest_fips_256 (int extended, selftest_report_func_t report) |
| { |
| const char *what; |
| const char *errtxt; |
| |
| (void)extended; /* No extended tests available. */ |
| |
| what = "low-level"; |
| errtxt = selftest_basic_256 (); |
| if (errtxt) |
| goto failed; |
| |
| return 0; /* Succeeded. */ |
| |
| failed: |
| if (report) |
| report ("cipher", GCRY_CIPHER_AES256, what, errtxt); |
| return GPG_ERR_SELFTEST_FAILED; |
| } |
| |
| |
| |
| /* Run a full self-test for ALGO and return 0 on success. */ |
| static gpg_err_code_t |
| run_selftests (int algo, int extended, selftest_report_func_t report) |
| { |
| gpg_err_code_t ec; |
| |
| switch (algo) |
| { |
| case GCRY_CIPHER_AES128: |
| ec = selftest_fips_128 (extended, report); |
| break; |
| case GCRY_CIPHER_AES192: |
| ec = selftest_fips_192 (extended, report); |
| break; |
| case GCRY_CIPHER_AES256: |
| ec = selftest_fips_256 (extended, report); |
| break; |
| default: |
| ec = GPG_ERR_CIPHER_ALGO; |
| break; |
| |
| } |
| return ec; |
| } |
| |
| |
| |
| |
| static const char *rijndael_names[] = |
| { |
| "RIJNDAEL", |
| "AES128", |
| "AES-128", |
| NULL |
| }; |
| |
| static gcry_cipher_oid_spec_t rijndael_oids[] = |
| { |
| { "2.16.840.1.101.3.4.1.1", GCRY_CIPHER_MODE_ECB }, |
| { "2.16.840.1.101.3.4.1.2", GCRY_CIPHER_MODE_CBC }, |
| { "2.16.840.1.101.3.4.1.3", GCRY_CIPHER_MODE_OFB }, |
| { "2.16.840.1.101.3.4.1.4", GCRY_CIPHER_MODE_CFB }, |
| { NULL } |
| }; |
| |
| gcry_cipher_spec_t _gcry_cipher_spec_aes = |
| { |
| "AES", rijndael_names, rijndael_oids, 16, 128, sizeof (RIJNDAEL_context), |
| rijndael_setkey, rijndael_encrypt, rijndael_decrypt |
| }; |
| cipher_extra_spec_t _gcry_cipher_extraspec_aes = |
| { |
| run_selftests |
| }; |
| |
| static const char *rijndael192_names[] = |
| { |
| "RIJNDAEL192", |
| "AES-192", |
| NULL |
| }; |
| |
| static gcry_cipher_oid_spec_t rijndael192_oids[] = |
| { |
| { "2.16.840.1.101.3.4.1.21", GCRY_CIPHER_MODE_ECB }, |
| { "2.16.840.1.101.3.4.1.22", GCRY_CIPHER_MODE_CBC }, |
| { "2.16.840.1.101.3.4.1.23", GCRY_CIPHER_MODE_OFB }, |
| { "2.16.840.1.101.3.4.1.24", GCRY_CIPHER_MODE_CFB }, |
| { NULL } |
| }; |
| |
| gcry_cipher_spec_t _gcry_cipher_spec_aes192 = |
| { |
| "AES192", rijndael192_names, rijndael192_oids, 16, 192, sizeof (RIJNDAEL_context), |
| rijndael_setkey, rijndael_encrypt, rijndael_decrypt |
| }; |
| cipher_extra_spec_t _gcry_cipher_extraspec_aes192 = |
| { |
| run_selftests |
| }; |
| |
| static const char *rijndael256_names[] = |
| { |
| "RIJNDAEL256", |
| "AES-256", |
| NULL |
| }; |
| |
| static gcry_cipher_oid_spec_t rijndael256_oids[] = |
| { |
| { "2.16.840.1.101.3.4.1.41", GCRY_CIPHER_MODE_ECB }, |
| { "2.16.840.1.101.3.4.1.42", GCRY_CIPHER_MODE_CBC }, |
| { "2.16.840.1.101.3.4.1.43", GCRY_CIPHER_MODE_OFB }, |
| { "2.16.840.1.101.3.4.1.44", GCRY_CIPHER_MODE_CFB }, |
| { NULL } |
| }; |
| |
| gcry_cipher_spec_t _gcry_cipher_spec_aes256 = |
| { |
| "AES256", rijndael256_names, rijndael256_oids, 16, 256, |
| sizeof (RIJNDAEL_context), |
| rijndael_setkey, rijndael_encrypt, rijndael_decrypt |
| }; |
| |
| cipher_extra_spec_t _gcry_cipher_extraspec_aes256 = |
| { |
| run_selftests |
| }; |