/* Rijndael (AES) for GnuPG
* Copyright (C) 2000, 2001, 2002, 2003, 2007,
* 2008 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
* 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:
*
*/
#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"
/* USE_PADLOCK indicates whether to compile the padlock specific
code. */
#ifdef ENABLE_PADLOCK_SUPPORT
# define USE_PADLOCK
# endif
#endif /*ENABLE_PADLOCK_SUPPORT*/
static const char *selftest(void);
typedef struct
{
#ifdef USE_PADLOCK
/* The key as passed to the padlock engine. */
#endif
union
{
} u1;
union
{
} u2;
/* All the numbers. */
#include "rijndael-tables.h"
/* Perform the key setup. */
static gcry_err_code_t
{
static int initialized = 0;
static const char *selftest_failed=0;
int ROUNDS;
int i,j, r, t, rconpointer = 0;
int KC;
union
{
} k;
#define k k.k
union
{
} 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)
}
if (selftest_failed)
return GPG_ERR_SELFTEST_FAILED;
ctx->decryption_prepared = 0;
#ifdef USE_PADLOCK
ctx->use_padlock = 0;
#endif
{
ROUNDS = 10;
KC = 4;
#ifdef USE_PADLOCK
if ((_gcry_get_hw_features () & HWF_PADLOCK_AES))
{
}
#endif
}
{
ROUNDS = 12;
KC = 6;
}
{
ROUNDS = 14;
KC = 8;
}
else
return GPG_ERR_INV_KEYLEN;
#ifdef USE_PADLOCK
if (ctx->use_padlock)
{
/* Nothing to do as we support only hardware key generation for
now. */
}
else
#endif /*USE_PADLOCK*/
{
for (i = 0; i < keylen; i++)
{
}
for (j = KC-1; j >= 0; j--)
{
}
r = 0;
t = 0;
/* Copy values into round key array. */
{
for (; (j < KC) && (t < 4); j++, t++)
{
}
if (t == 4)
{
r++;
t = 0;
}
}
while (r < ROUNDS + 1)
{
/* While not enough round key material calculated calculate
new values. */
if (KC != 8)
{
for (j = 1; j < KC; j++)
{
}
}
else
{
{
}
{
}
}
/* Copy values into round key array. */
{
for (; (j < KC) && (t < 4); j++, t++)
{
}
if (t == 4)
{
r++;
t = 0;
}
}
}
#undef W
}
return 0;
#undef k
}
static gcry_err_code_t
{
return rc;
}
/* Make a decryption key from an encryption key. */
static void
{
int r;
union
{
byte *w;
} w;
#define w w.w
for (r=0; r < MAXROUNDS+1; r++ )
{
}
{
w = W[r][0];
w = W[r][1];
w = W[r][2];
w = W[r][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
unsigned char *b, const unsigned char *a)
{
int r;
union
{
} u;
{
}
/* Last round is special. */
}
static void
{
/* BX and AX are not necessary correctly aligned. Thus we need to
copy them here. */
union
{
byte a[16];
} a;
union
{
byte b[16];
} b;
do_encrypt_aligned (ctx, b.b, a.a);
}
/* Encrypt or decrypt one block using the padlock engine. A and B may
be the same. */
#ifdef USE_PADLOCK
static void
{
/* BX and AX are not necessary correctly aligned. Thus we need to
copy them here. */
/* 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[1] = 0;
cword[2] = 0;
cword[3] = 0;
if (decrypt_flag)
cword[0] |= 0x00000200;
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 */
: "%ecx", "cc", "memory"
);
}
#endif /*USE_PADLOCK*/
static void
{
#ifdef USE_PADLOCK
if (ctx->use_padlock)
{
do_padlock (ctx, 0, b, a);
}
else
#endif /*USE_PADLOCK*/
{
do_encrypt (ctx, b, a);
}
}
/* 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
void *outbuf_arg, const void *inbuf_arg,
unsigned int nblocks)
{
unsigned char *ivp;
int i;
#ifdef USE_PADLOCK
if (ctx->use_padlock)
{
/* Fixme: Let Padlock do the CFBing. */
{
/* Encrypt the IV. */
/* XOR the input with the IV and store input into IV. */
}
}
else
#endif /* USE_PADLOCK*/
{
{
/* Encrypt the IV. */
/* XOR the input with the IV and store input into IV. */
}
}
}
/* 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
void *outbuf_arg, const void *inbuf_arg,
{
unsigned char *ivp;
int i;
{
#ifdef USE_PADLOCK
if (ctx->use_padlock)
else
#endif /*USE_PADLOCK*/
if (!cbc_mac)
}
}
/* 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
unsigned char *b, const unsigned char *a)
{
int r;
union
{
} u;
{
}
/* Last round is special. */
}
/* Decrypt one block. AX and BX may be the same. */
static void
{
/* BX and AX are not necessary correctly aligned. Thus we need to
copy them here. */
union
{
byte a[16];
} a;
union
{
byte b[16];
} b;
if ( !ctx->decryption_prepared )
{
prepare_decryption ( ctx );
_gcry_burn_stack (64);
}
do_decrypt_aligned (ctx, b.b, a.a);
}
static void
{
#ifdef USE_PADLOCK
if (ctx->use_padlock)
{
}
else
#endif /*USE_PADLOCK*/
{
do_decrypt (ctx, b, a);
}
}
/* 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
void *outbuf_arg, const void *inbuf_arg,
unsigned int nblocks)
{
unsigned char *ivp;
unsigned char temp;
int i;
#ifdef USE_PADLOCK
if (ctx->use_padlock)
{
/* Fixme: Let Padlock do the CFBing. */
{
{
}
}
}
else
#endif /*USE_PADLOCK*/
{
{
{
}
}
}
}
/* 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
void *outbuf_arg, const void *inbuf_arg,
unsigned int nblocks)
{
unsigned char *ivp;
int i;
{
/* We need to save INBUF away because it may be identical to
OUTBUF. */
#ifdef USE_PADLOCK
if (ctx->use_padlock)
else
#endif /*USE_PADLOCK*/
}
}
/* Run the self-tests for AES 128. Returns NULL on success. */
static const char*
selftest_basic_128 (void)
{
/* The test vectors are from the AES supplied ones; more or less
randomly taken from ecb_tbl.txt (I=42,81,14) */
{
0x01,0x4B,0xAF,0x22,0x78,0xA6,0x9D,0x33,
0x1D,0x51,0x80,0x10,0x36,0x43,0xE9,0x9A
};
{
0xE8,0xE9,0xEA,0xEB,0xED,0xEE,0xEF,0xF0,
0xF2,0xF3,0xF4,0xF5,0xF7,0xF8,0xF9,0xFA
};
{
0x67,0x43,0xC3,0xD1,0x51,0x9A,0xB4,0xF2,
0xCD,0x9A,0x78,0xAB,0x09,0xA5,0x11,0xBD
};
return "AES-128 test encryption failed.";
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)
{
{
0x76,0x77,0x74,0x75,0xF1,0xF2,0xF3,0xF4,
0xF8,0xF9,0xE6,0xE7,0x77,0x70,0x71,0x72
};
{
0x04,0x05,0x06,0x07,0x09,0x0A,0x0B,0x0C,
0x0E,0x0F,0x10,0x11,0x13,0x14,0x15,0x16,
0x18,0x19,0x1A,0x1B,0x1D,0x1E,0x1F,0x20
};
{
0x5D,0x1E,0xF2,0x0D,0xCE,0xD6,0xBC,0xBC,
0x12,0x13,0x1A,0xC7,0xC5,0x47,0x88,0xAA
};
return "AES-192 test encryption failed.";
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)
{
{
0x06,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F,
0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x21
};
{
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
};
{
0x08,0x0E,0x95,0x17,0xEB,0x16,0x77,0x71,
0x9A,0xCF,0x72,0x80,0x86,0x04,0x0A,0xE3
};
return "AES-256 test encryption failed.";
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 *
{
struct tv
{
int mode;
struct
{
{
{
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 } }
}
},
{
{ 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 } },
}
}
};
#define Fail(a) do { \
_gcry_cipher_close (hdenc); \
_gcry_cipher_close (hddec); \
return a; \
} while (0)
break;
Fail ("no test data for this mode");
if (err)
Fail ("open");
if (err)
Fail ("open");
if (!err)
if (err)
Fail ("set key");
if (!err)
if (err)
Fail ("set IV");
{
if (err)
Fail ("encrypt command");
Fail ("encrypt mismatch");
if (err)
Fail ("decrypt command");
Fail ("decrypt mismatch");
}
return NULL;
}
/* Complete selftest for AES-128 with all modes and driver code. */
static gpg_err_code_t
{
const char *what;
const char *errtxt;
what = "low-level";
errtxt = selftest_basic_128 ();
if (errtxt)
goto failed;
if (extended)
{
what = "cfb";
if (errtxt)
goto failed;
what = "ofb";
if (errtxt)
goto failed;
}
return 0; /* Succeeded. */
if (report)
return GPG_ERR_SELFTEST_FAILED;
}
/* Complete selftest for AES-192. */
static gpg_err_code_t
{
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. */
if (report)
return GPG_ERR_SELFTEST_FAILED;
}
/* Complete selftest for AES-256. */
static gpg_err_code_t
{
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. */
if (report)
return GPG_ERR_SELFTEST_FAILED;
}
/* Run a full self-test for ALGO and return 0 on success. */
static gpg_err_code_t
{
switch (algo)
{
case GCRY_CIPHER_AES128:
break;
case GCRY_CIPHER_AES192:
break;
case GCRY_CIPHER_AES256:
break;
default:
break;
}
return ec;
}
static const char *rijndael_names[] =
{
"RIJNDAEL",
"AES128",
"AES-128",
};
{
{ "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 }
};
{
};
{
};
static const char *rijndael192_names[] =
{
"RIJNDAEL192",
"AES-192",
};
{
{ "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 }
};
{
};
{
};
static const char *rijndael256_names[] =
{
"RIJNDAEL256",
"AES-256",
};
{
{ "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 }
};
{
sizeof (RIJNDAEL_context),
};
{
};