diff options
Diffstat (limited to 'comm/third_party/libgcrypt/cipher/camellia-glue.c')
-rw-r--r-- | comm/third_party/libgcrypt/cipher/camellia-glue.c | 1097 |
1 files changed, 1097 insertions, 0 deletions
diff --git a/comm/third_party/libgcrypt/cipher/camellia-glue.c b/comm/third_party/libgcrypt/cipher/camellia-glue.c new file mode 100644 index 0000000000..6577b6516a --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/camellia-glue.c @@ -0,0 +1,1097 @@ +/* camellia-glue.c - Glue for the Camellia cipher + * Copyright (C) 2007 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 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/* I put all the libgcrypt-specific stuff in this file to keep the + camellia.c/camellia.h files exactly as provided by NTT. If they + update their code, this should make it easier to bring the changes + in. - dshaw + + There is one small change which needs to be done: Include the + following code at the top of camellia.h: */ +#if 0 + +/* To use Camellia with libraries it is often useful to keep the name + * space of the library clean. The following macro is thus useful: + * + * #define CAMELLIA_EXT_SYM_PREFIX foo_ + * + * This prefixes all external symbols with "foo_". + */ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#ifdef CAMELLIA_EXT_SYM_PREFIX +#define CAMELLIA_PREFIX1(x,y) x ## y +#define CAMELLIA_PREFIX2(x,y) CAMELLIA_PREFIX1(x,y) +#define CAMELLIA_PREFIX(x) CAMELLIA_PREFIX2(CAMELLIA_EXT_SYM_PREFIX,x) +#define Camellia_Ekeygen CAMELLIA_PREFIX(Camellia_Ekeygen) +#define Camellia_EncryptBlock CAMELLIA_PREFIX(Camellia_EncryptBlock) +#define Camellia_DecryptBlock CAMELLIA_PREFIX(Camellia_DecryptBlock) +#define camellia_decrypt128 CAMELLIA_PREFIX(camellia_decrypt128) +#define camellia_decrypt256 CAMELLIA_PREFIX(camellia_decrypt256) +#define camellia_encrypt128 CAMELLIA_PREFIX(camellia_encrypt128) +#define camellia_encrypt256 CAMELLIA_PREFIX(camellia_encrypt256) +#define camellia_setup128 CAMELLIA_PREFIX(camellia_setup128) +#define camellia_setup192 CAMELLIA_PREFIX(camellia_setup192) +#define camellia_setup256 CAMELLIA_PREFIX(camellia_setup256) +#endif /*CAMELLIA_EXT_SYM_PREFIX*/ + +#endif /* Code sample. */ + + +#include <config.h> +#include "types.h" +#include "g10lib.h" +#include "cipher.h" +#include "camellia.h" +#include "bufhelp.h" +#include "cipher-internal.h" +#include "cipher-selftest.h" + +/* Helper macro to force alignment to 16 bytes. */ +#ifdef HAVE_GCC_ATTRIBUTE_ALIGNED +# define ATTR_ALIGNED_16 __attribute__ ((aligned (16))) +#else +# define ATTR_ALIGNED_16 +#endif + +/* USE_AESNI inidicates whether to compile with Intel AES-NI/AVX code. */ +#undef USE_AESNI_AVX +#if defined(ENABLE_AESNI_SUPPORT) && defined(ENABLE_AVX_SUPPORT) +# if defined(__x86_64__) && (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \ + defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)) +# define USE_AESNI_AVX 1 +# endif +#endif + +/* USE_AESNI_AVX2 inidicates whether to compile with Intel AES-NI/AVX2 code. */ +#undef USE_AESNI_AVX2 +#if defined(ENABLE_AESNI_SUPPORT) && defined(ENABLE_AVX2_SUPPORT) +# if defined(__x86_64__) && (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \ + defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)) +# define USE_AESNI_AVX2 1 +# endif +#endif + +typedef struct +{ + KEY_TABLE_TYPE keytable; + int keybitlength; +#ifdef USE_AESNI_AVX + unsigned int use_aesni_avx:1; /* AES-NI/AVX implementation shall be used. */ +#endif /*USE_AESNI_AVX*/ +#ifdef USE_AESNI_AVX2 + unsigned int use_aesni_avx2:1;/* AES-NI/AVX2 implementation shall be used. */ +#endif /*USE_AESNI_AVX2*/ +} CAMELLIA_context; + +/* Assembly implementations use SystemV ABI, ABI conversion and additional + * stack to store XMM6-XMM15 needed on Win64. */ +#undef ASM_FUNC_ABI +#undef ASM_EXTRA_STACK +#if defined(USE_AESNI_AVX) || defined(USE_AESNI_AVX2) +# ifdef HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS +# define ASM_FUNC_ABI __attribute__((sysv_abi)) +# define ASM_EXTRA_STACK (10 * 16) +# else +# define ASM_FUNC_ABI +# define ASM_EXTRA_STACK 0 +# endif +#endif + +#ifdef USE_AESNI_AVX +/* Assembler implementations of Camellia using AES-NI and AVX. Process data + in 16 block same time. + */ +extern void _gcry_camellia_aesni_avx_ctr_enc(CAMELLIA_context *ctx, + unsigned char *out, + const unsigned char *in, + unsigned char *ctr) ASM_FUNC_ABI; + +extern void _gcry_camellia_aesni_avx_cbc_dec(CAMELLIA_context *ctx, + unsigned char *out, + const unsigned char *in, + unsigned char *iv) ASM_FUNC_ABI; + +extern void _gcry_camellia_aesni_avx_cfb_dec(CAMELLIA_context *ctx, + unsigned char *out, + const unsigned char *in, + unsigned char *iv) ASM_FUNC_ABI; + +extern void _gcry_camellia_aesni_avx_ocb_enc(CAMELLIA_context *ctx, + unsigned char *out, + const unsigned char *in, + unsigned char *offset, + unsigned char *checksum, + const u64 Ls[16]) ASM_FUNC_ABI; + +extern void _gcry_camellia_aesni_avx_ocb_dec(CAMELLIA_context *ctx, + unsigned char *out, + const unsigned char *in, + unsigned char *offset, + unsigned char *checksum, + const u64 Ls[16]) ASM_FUNC_ABI; + +extern void _gcry_camellia_aesni_avx_ocb_auth(CAMELLIA_context *ctx, + const unsigned char *abuf, + unsigned char *offset, + unsigned char *checksum, + const u64 Ls[16]) ASM_FUNC_ABI; + +extern void _gcry_camellia_aesni_avx_keygen(CAMELLIA_context *ctx, + const unsigned char *key, + unsigned int keylen) ASM_FUNC_ABI; +#endif + +#ifdef USE_AESNI_AVX2 +/* Assembler implementations of Camellia using AES-NI and AVX2. Process data + in 32 block same time. + */ +extern void _gcry_camellia_aesni_avx2_ctr_enc(CAMELLIA_context *ctx, + unsigned char *out, + const unsigned char *in, + unsigned char *ctr) ASM_FUNC_ABI; + +extern void _gcry_camellia_aesni_avx2_cbc_dec(CAMELLIA_context *ctx, + unsigned char *out, + const unsigned char *in, + unsigned char *iv) ASM_FUNC_ABI; + +extern void _gcry_camellia_aesni_avx2_cfb_dec(CAMELLIA_context *ctx, + unsigned char *out, + const unsigned char *in, + unsigned char *iv) ASM_FUNC_ABI; + +extern void _gcry_camellia_aesni_avx2_ocb_enc(CAMELLIA_context *ctx, + unsigned char *out, + const unsigned char *in, + unsigned char *offset, + unsigned char *checksum, + const u64 Ls[32]) ASM_FUNC_ABI; + +extern void _gcry_camellia_aesni_avx2_ocb_dec(CAMELLIA_context *ctx, + unsigned char *out, + const unsigned char *in, + unsigned char *offset, + unsigned char *checksum, + const u64 Ls[32]) ASM_FUNC_ABI; + +extern void _gcry_camellia_aesni_avx2_ocb_auth(CAMELLIA_context *ctx, + const unsigned char *abuf, + unsigned char *offset, + unsigned char *checksum, + const u64 Ls[32]) ASM_FUNC_ABI; +#endif + +static const char *selftest(void); + +static void _gcry_camellia_ctr_enc (void *context, unsigned char *ctr, + void *outbuf_arg, const void *inbuf_arg, + size_t nblocks); +static void _gcry_camellia_cbc_dec (void *context, unsigned char *iv, + void *outbuf_arg, const void *inbuf_arg, + size_t nblocks); +static void _gcry_camellia_cfb_dec (void *context, unsigned char *iv, + void *outbuf_arg, const void *inbuf_arg, + size_t nblocks); +static size_t _gcry_camellia_ocb_crypt (gcry_cipher_hd_t c, void *outbuf_arg, + const void *inbuf_arg, size_t nblocks, + int encrypt); +static size_t _gcry_camellia_ocb_auth (gcry_cipher_hd_t c, const void *abuf_arg, + size_t nblocks); + +static gcry_err_code_t +camellia_setkey(void *c, const byte *key, unsigned keylen, + cipher_bulk_ops_t *bulk_ops) +{ + CAMELLIA_context *ctx=c; + static int initialized=0; + static const char *selftest_failed=NULL; +#if defined(USE_AESNI_AVX) || defined(USE_AESNI_AVX2) + unsigned int hwf = _gcry_get_hw_features (); +#endif + + if(keylen!=16 && keylen!=24 && keylen!=32) + return GPG_ERR_INV_KEYLEN; + + if(!initialized) + { + initialized=1; + selftest_failed=selftest(); + if(selftest_failed) + log_error("%s\n",selftest_failed); + } + + if(selftest_failed) + return GPG_ERR_SELFTEST_FAILED; + +#ifdef USE_AESNI_AVX + ctx->use_aesni_avx = (hwf & HWF_INTEL_AESNI) && (hwf & HWF_INTEL_AVX); +#endif +#ifdef USE_AESNI_AVX2 + ctx->use_aesni_avx2 = (hwf & HWF_INTEL_AESNI) && (hwf & HWF_INTEL_AVX2); +#endif + + ctx->keybitlength=keylen*8; + + /* Setup bulk encryption routines. */ + memset (bulk_ops, 0, sizeof(*bulk_ops)); + bulk_ops->cbc_dec = _gcry_camellia_cbc_dec; + bulk_ops->cfb_dec = _gcry_camellia_cfb_dec; + bulk_ops->ctr_enc = _gcry_camellia_ctr_enc; + bulk_ops->ocb_crypt = _gcry_camellia_ocb_crypt; + bulk_ops->ocb_auth = _gcry_camellia_ocb_auth; + + if (0) + { } +#ifdef USE_AESNI_AVX + else if (ctx->use_aesni_avx) + _gcry_camellia_aesni_avx_keygen(ctx, key, keylen); + else +#endif + { + Camellia_Ekeygen(ctx->keybitlength,key,ctx->keytable); + _gcry_burn_stack + ((19+34+34)*sizeof(u32)+2*sizeof(void*) /* camellia_setup256 */ + +(4+32)*sizeof(u32)+2*sizeof(void*) /* camellia_setup192 */ + +0+sizeof(int)+2*sizeof(void*) /* Camellia_Ekeygen */ + +3*2*sizeof(void*) /* Function calls. */ + ); + } + + return 0; +} + +#ifdef USE_ARM_ASM + +/* Assembly implementations of Camellia. */ +extern void _gcry_camellia_arm_encrypt_block(const KEY_TABLE_TYPE keyTable, + byte *outbuf, const byte *inbuf, + const int keybits); + +extern void _gcry_camellia_arm_decrypt_block(const KEY_TABLE_TYPE keyTable, + byte *outbuf, const byte *inbuf, + const int keybits); + +static void Camellia_EncryptBlock(const int keyBitLength, + const unsigned char *plaintext, + const KEY_TABLE_TYPE keyTable, + unsigned char *cipherText) +{ + _gcry_camellia_arm_encrypt_block(keyTable, cipherText, plaintext, + keyBitLength); +} + +static void Camellia_DecryptBlock(const int keyBitLength, + const unsigned char *cipherText, + const KEY_TABLE_TYPE keyTable, + unsigned char *plaintext) +{ + _gcry_camellia_arm_decrypt_block(keyTable, plaintext, cipherText, + keyBitLength); +} + +#ifdef __aarch64__ +# define CAMELLIA_encrypt_stack_burn_size (0) +# define CAMELLIA_decrypt_stack_burn_size (0) +#else +# define CAMELLIA_encrypt_stack_burn_size (15*4) +# define CAMELLIA_decrypt_stack_burn_size (15*4) +#endif + +static unsigned int +camellia_encrypt(void *c, byte *outbuf, const byte *inbuf) +{ + CAMELLIA_context *ctx = c; + Camellia_EncryptBlock(ctx->keybitlength,inbuf,ctx->keytable,outbuf); + return /*burn_stack*/ (CAMELLIA_encrypt_stack_burn_size); +} + +static unsigned int +camellia_decrypt(void *c, byte *outbuf, const byte *inbuf) +{ + CAMELLIA_context *ctx=c; + Camellia_DecryptBlock(ctx->keybitlength,inbuf,ctx->keytable,outbuf); + return /*burn_stack*/ (CAMELLIA_decrypt_stack_burn_size); +} + +#else /*USE_ARM_ASM*/ + +static unsigned int +camellia_encrypt(void *c, byte *outbuf, const byte *inbuf) +{ + CAMELLIA_context *ctx=c; + + Camellia_EncryptBlock(ctx->keybitlength,inbuf,ctx->keytable,outbuf); + +#define CAMELLIA_encrypt_stack_burn_size \ + (sizeof(int)+2*sizeof(unsigned char *)+sizeof(void*/*KEY_TABLE_TYPE*/) \ + +4*sizeof(u32)+4*sizeof(u32) \ + +2*sizeof(u32*)+4*sizeof(u32) \ + +2*2*sizeof(void*) /* Function calls. */ \ + ) + + return /*burn_stack*/ (CAMELLIA_encrypt_stack_burn_size); +} + +static unsigned int +camellia_decrypt(void *c, byte *outbuf, const byte *inbuf) +{ + CAMELLIA_context *ctx=c; + + Camellia_DecryptBlock(ctx->keybitlength,inbuf,ctx->keytable,outbuf); + +#define CAMELLIA_decrypt_stack_burn_size \ + (sizeof(int)+2*sizeof(unsigned char *)+sizeof(void*/*KEY_TABLE_TYPE*/) \ + +4*sizeof(u32)+4*sizeof(u32) \ + +2*sizeof(u32*)+4*sizeof(u32) \ + +2*2*sizeof(void*) /* Function calls. */ \ + ) + + return /*burn_stack*/ (CAMELLIA_decrypt_stack_burn_size); +} + +#endif /*!USE_ARM_ASM*/ + +/* Bulk encryption of complete blocks in CTR mode. This function is only + intended for the bulk encryption feature of cipher.c. CTR is expected to be + of size CAMELLIA_BLOCK_SIZE. */ +static void +_gcry_camellia_ctr_enc(void *context, unsigned char *ctr, + void *outbuf_arg, const void *inbuf_arg, + size_t nblocks) +{ + CAMELLIA_context *ctx = context; + unsigned char *outbuf = outbuf_arg; + const unsigned char *inbuf = inbuf_arg; + unsigned char tmpbuf[CAMELLIA_BLOCK_SIZE]; + int burn_stack_depth = CAMELLIA_encrypt_stack_burn_size; + +#ifdef USE_AESNI_AVX2 + if (ctx->use_aesni_avx2) + { + int did_use_aesni_avx2 = 0; + + /* Process data in 32 block chunks. */ + while (nblocks >= 32) + { + _gcry_camellia_aesni_avx2_ctr_enc(ctx, outbuf, inbuf, ctr); + + nblocks -= 32; + outbuf += 32 * CAMELLIA_BLOCK_SIZE; + inbuf += 32 * CAMELLIA_BLOCK_SIZE; + did_use_aesni_avx2 = 1; + } + + if (did_use_aesni_avx2) + { + int avx2_burn_stack_depth = 32 * CAMELLIA_BLOCK_SIZE + 16 + + 2 * sizeof(void *) + ASM_EXTRA_STACK; + + if (burn_stack_depth < avx2_burn_stack_depth) + burn_stack_depth = avx2_burn_stack_depth; + } + + /* Use generic code to handle smaller chunks... */ + /* TODO: use caching instead? */ + } +#endif + +#ifdef USE_AESNI_AVX + if (ctx->use_aesni_avx) + { + int did_use_aesni_avx = 0; + + /* Process data in 16 block chunks. */ + while (nblocks >= 16) + { + _gcry_camellia_aesni_avx_ctr_enc(ctx, outbuf, inbuf, ctr); + + nblocks -= 16; + outbuf += 16 * CAMELLIA_BLOCK_SIZE; + inbuf += 16 * CAMELLIA_BLOCK_SIZE; + did_use_aesni_avx = 1; + } + + if (did_use_aesni_avx) + { + int avx_burn_stack_depth = 16 * CAMELLIA_BLOCK_SIZE + + 2 * sizeof(void *) + ASM_EXTRA_STACK; + + if (burn_stack_depth < avx_burn_stack_depth) + burn_stack_depth = avx_burn_stack_depth; + } + + /* Use generic code to handle smaller chunks... */ + /* TODO: use caching instead? */ + } +#endif + + for ( ;nblocks; nblocks-- ) + { + /* Encrypt the counter. */ + Camellia_EncryptBlock(ctx->keybitlength, ctr, ctx->keytable, tmpbuf); + /* XOR the input with the encrypted counter and store in output. */ + cipher_block_xor(outbuf, tmpbuf, inbuf, CAMELLIA_BLOCK_SIZE); + outbuf += CAMELLIA_BLOCK_SIZE; + inbuf += CAMELLIA_BLOCK_SIZE; + /* Increment the counter. */ + cipher_block_add(ctr, 1, CAMELLIA_BLOCK_SIZE); + } + + wipememory(tmpbuf, sizeof(tmpbuf)); + _gcry_burn_stack(burn_stack_depth); +} + +/* Bulk decryption of complete blocks in CBC mode. This function is only + intended for the bulk encryption feature of cipher.c. */ +static void +_gcry_camellia_cbc_dec(void *context, unsigned char *iv, + void *outbuf_arg, const void *inbuf_arg, + size_t nblocks) +{ + CAMELLIA_context *ctx = context; + unsigned char *outbuf = outbuf_arg; + const unsigned char *inbuf = inbuf_arg; + unsigned char savebuf[CAMELLIA_BLOCK_SIZE]; + int burn_stack_depth = CAMELLIA_decrypt_stack_burn_size; + +#ifdef USE_AESNI_AVX2 + if (ctx->use_aesni_avx2) + { + int did_use_aesni_avx2 = 0; + + /* Process data in 32 block chunks. */ + while (nblocks >= 32) + { + _gcry_camellia_aesni_avx2_cbc_dec(ctx, outbuf, inbuf, iv); + + nblocks -= 32; + outbuf += 32 * CAMELLIA_BLOCK_SIZE; + inbuf += 32 * CAMELLIA_BLOCK_SIZE; + did_use_aesni_avx2 = 1; + } + + if (did_use_aesni_avx2) + { + int avx2_burn_stack_depth = 32 * CAMELLIA_BLOCK_SIZE + 16 + + 2 * sizeof(void *) + ASM_EXTRA_STACK;; + + if (burn_stack_depth < avx2_burn_stack_depth) + burn_stack_depth = avx2_burn_stack_depth; + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + +#ifdef USE_AESNI_AVX + if (ctx->use_aesni_avx) + { + int did_use_aesni_avx = 0; + + /* Process data in 16 block chunks. */ + while (nblocks >= 16) + { + _gcry_camellia_aesni_avx_cbc_dec(ctx, outbuf, inbuf, iv); + + nblocks -= 16; + outbuf += 16 * CAMELLIA_BLOCK_SIZE; + inbuf += 16 * CAMELLIA_BLOCK_SIZE; + did_use_aesni_avx = 1; + } + + if (did_use_aesni_avx) + { + int avx_burn_stack_depth = 16 * CAMELLIA_BLOCK_SIZE + + 2 * sizeof(void *) + ASM_EXTRA_STACK; + + if (burn_stack_depth < avx_burn_stack_depth) + burn_stack_depth = avx_burn_stack_depth; + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + + for ( ;nblocks; nblocks-- ) + { + /* INBUF is needed later and it may be identical to OUTBUF, so store + the intermediate result to SAVEBUF. */ + Camellia_DecryptBlock(ctx->keybitlength, inbuf, ctx->keytable, savebuf); + + cipher_block_xor_n_copy_2(outbuf, savebuf, iv, inbuf, + CAMELLIA_BLOCK_SIZE); + inbuf += CAMELLIA_BLOCK_SIZE; + outbuf += CAMELLIA_BLOCK_SIZE; + } + + wipememory(savebuf, sizeof(savebuf)); + _gcry_burn_stack(burn_stack_depth); +} + +/* Bulk decryption of complete blocks in CFB mode. This function is only + intended for the bulk encryption feature of cipher.c. */ +static void +_gcry_camellia_cfb_dec(void *context, unsigned char *iv, + void *outbuf_arg, const void *inbuf_arg, + size_t nblocks) +{ + CAMELLIA_context *ctx = context; + unsigned char *outbuf = outbuf_arg; + const unsigned char *inbuf = inbuf_arg; + int burn_stack_depth = CAMELLIA_decrypt_stack_burn_size; + +#ifdef USE_AESNI_AVX2 + if (ctx->use_aesni_avx2) + { + int did_use_aesni_avx2 = 0; + + /* Process data in 32 block chunks. */ + while (nblocks >= 32) + { + _gcry_camellia_aesni_avx2_cfb_dec(ctx, outbuf, inbuf, iv); + + nblocks -= 32; + outbuf += 32 * CAMELLIA_BLOCK_SIZE; + inbuf += 32 * CAMELLIA_BLOCK_SIZE; + did_use_aesni_avx2 = 1; + } + + if (did_use_aesni_avx2) + { + int avx2_burn_stack_depth = 32 * CAMELLIA_BLOCK_SIZE + 16 + + 2 * sizeof(void *) + ASM_EXTRA_STACK; + + if (burn_stack_depth < avx2_burn_stack_depth) + burn_stack_depth = avx2_burn_stack_depth; + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + +#ifdef USE_AESNI_AVX + if (ctx->use_aesni_avx) + { + int did_use_aesni_avx = 0; + + /* Process data in 16 block chunks. */ + while (nblocks >= 16) + { + _gcry_camellia_aesni_avx_cfb_dec(ctx, outbuf, inbuf, iv); + + nblocks -= 16; + outbuf += 16 * CAMELLIA_BLOCK_SIZE; + inbuf += 16 * CAMELLIA_BLOCK_SIZE; + did_use_aesni_avx = 1; + } + + if (did_use_aesni_avx) + { + int avx_burn_stack_depth = 16 * CAMELLIA_BLOCK_SIZE + + 2 * sizeof(void *) + ASM_EXTRA_STACK; + + if (burn_stack_depth < avx_burn_stack_depth) + burn_stack_depth = avx_burn_stack_depth; + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + + for ( ;nblocks; nblocks-- ) + { + Camellia_EncryptBlock(ctx->keybitlength, iv, ctx->keytable, iv); + cipher_block_xor_n_copy(outbuf, iv, inbuf, CAMELLIA_BLOCK_SIZE); + outbuf += CAMELLIA_BLOCK_SIZE; + inbuf += CAMELLIA_BLOCK_SIZE; + } + + _gcry_burn_stack(burn_stack_depth); +} + +/* Bulk encryption/decryption of complete blocks in OCB mode. */ +static size_t +_gcry_camellia_ocb_crypt (gcry_cipher_hd_t c, void *outbuf_arg, + const void *inbuf_arg, size_t nblocks, int encrypt) +{ +#if defined(USE_AESNI_AVX) || defined(USE_AESNI_AVX2) + CAMELLIA_context *ctx = (void *)&c->context.c; + unsigned char *outbuf = outbuf_arg; + const unsigned char *inbuf = inbuf_arg; + int burn_stack_depth; + u64 blkn = c->u_mode.ocb.data_nblocks; + + burn_stack_depth = encrypt ? CAMELLIA_encrypt_stack_burn_size : + CAMELLIA_decrypt_stack_burn_size; +#else + (void)c; + (void)outbuf_arg; + (void)inbuf_arg; + (void)encrypt; +#endif + +#ifdef USE_AESNI_AVX2 + if (ctx->use_aesni_avx2) + { + int did_use_aesni_avx2 = 0; + u64 Ls[32]; + unsigned int n = 32 - (blkn % 32); + u64 *l; + int i; + + if (nblocks >= 32) + { + for (i = 0; i < 32; i += 8) + { + /* Use u64 to store pointers for x32 support (assembly function + * assumes 64-bit pointers). */ + Ls[(i + 0 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[0]; + Ls[(i + 1 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[1]; + Ls[(i + 2 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[0]; + Ls[(i + 3 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[2]; + Ls[(i + 4 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[0]; + Ls[(i + 5 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[1]; + Ls[(i + 6 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[0]; + } + + Ls[(7 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[3]; + Ls[(15 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[4]; + Ls[(23 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[3]; + l = &Ls[(31 + n) % 32]; + + /* Process data in 32 block chunks. */ + while (nblocks >= 32) + { + blkn += 32; + *l = (uintptr_t)(void *)ocb_get_l(c, blkn - blkn % 32); + + if (encrypt) + _gcry_camellia_aesni_avx2_ocb_enc(ctx, outbuf, inbuf, c->u_iv.iv, + c->u_ctr.ctr, Ls); + else + _gcry_camellia_aesni_avx2_ocb_dec(ctx, outbuf, inbuf, c->u_iv.iv, + c->u_ctr.ctr, Ls); + + nblocks -= 32; + outbuf += 32 * CAMELLIA_BLOCK_SIZE; + inbuf += 32 * CAMELLIA_BLOCK_SIZE; + did_use_aesni_avx2 = 1; + } + } + + if (did_use_aesni_avx2) + { + int avx2_burn_stack_depth = 32 * CAMELLIA_BLOCK_SIZE + + 2 * sizeof(void *) + ASM_EXTRA_STACK; + + if (burn_stack_depth < avx2_burn_stack_depth) + burn_stack_depth = avx2_burn_stack_depth; + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + +#ifdef USE_AESNI_AVX + if (ctx->use_aesni_avx) + { + int did_use_aesni_avx = 0; + u64 Ls[16]; + unsigned int n = 16 - (blkn % 16); + u64 *l; + int i; + + if (nblocks >= 16) + { + for (i = 0; i < 16; i += 8) + { + /* Use u64 to store pointers for x32 support (assembly function + * assumes 64-bit pointers). */ + Ls[(i + 0 + n) % 16] = (uintptr_t)(void *)c->u_mode.ocb.L[0]; + Ls[(i + 1 + n) % 16] = (uintptr_t)(void *)c->u_mode.ocb.L[1]; + Ls[(i + 2 + n) % 16] = (uintptr_t)(void *)c->u_mode.ocb.L[0]; + Ls[(i + 3 + n) % 16] = (uintptr_t)(void *)c->u_mode.ocb.L[2]; + Ls[(i + 4 + n) % 16] = (uintptr_t)(void *)c->u_mode.ocb.L[0]; + Ls[(i + 5 + n) % 16] = (uintptr_t)(void *)c->u_mode.ocb.L[1]; + Ls[(i + 6 + n) % 16] = (uintptr_t)(void *)c->u_mode.ocb.L[0]; + } + + Ls[(7 + n) % 16] = (uintptr_t)(void *)c->u_mode.ocb.L[3]; + l = &Ls[(15 + n) % 16]; + + /* Process data in 16 block chunks. */ + while (nblocks >= 16) + { + blkn += 16; + *l = (uintptr_t)(void *)ocb_get_l(c, blkn - blkn % 16); + + if (encrypt) + _gcry_camellia_aesni_avx_ocb_enc(ctx, outbuf, inbuf, c->u_iv.iv, + c->u_ctr.ctr, Ls); + else + _gcry_camellia_aesni_avx_ocb_dec(ctx, outbuf, inbuf, c->u_iv.iv, + c->u_ctr.ctr, Ls); + + nblocks -= 16; + outbuf += 16 * CAMELLIA_BLOCK_SIZE; + inbuf += 16 * CAMELLIA_BLOCK_SIZE; + did_use_aesni_avx = 1; + } + } + + if (did_use_aesni_avx) + { + int avx_burn_stack_depth = 16 * CAMELLIA_BLOCK_SIZE + + 2 * sizeof(void *) + ASM_EXTRA_STACK; + + if (burn_stack_depth < avx_burn_stack_depth) + burn_stack_depth = avx_burn_stack_depth; + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + +#if defined(USE_AESNI_AVX) || defined(USE_AESNI_AVX2) + c->u_mode.ocb.data_nblocks = blkn; + + if (burn_stack_depth) + _gcry_burn_stack (burn_stack_depth + 4 * sizeof(void *)); +#endif + + return nblocks; +} + +/* Bulk authentication of complete blocks in OCB mode. */ +static size_t +_gcry_camellia_ocb_auth (gcry_cipher_hd_t c, const void *abuf_arg, + size_t nblocks) +{ +#if defined(USE_AESNI_AVX) || defined(USE_AESNI_AVX2) + CAMELLIA_context *ctx = (void *)&c->context.c; + const unsigned char *abuf = abuf_arg; + int burn_stack_depth; + u64 blkn = c->u_mode.ocb.aad_nblocks; + + burn_stack_depth = CAMELLIA_encrypt_stack_burn_size; +#else + (void)c; + (void)abuf_arg; +#endif + +#ifdef USE_AESNI_AVX2 + if (ctx->use_aesni_avx2) + { + int did_use_aesni_avx2 = 0; + u64 Ls[32]; + unsigned int n = 32 - (blkn % 32); + u64 *l; + int i; + + if (nblocks >= 32) + { + for (i = 0; i < 32; i += 8) + { + /* Use u64 to store pointers for x32 support (assembly function + * assumes 64-bit pointers). */ + Ls[(i + 0 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[0]; + Ls[(i + 1 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[1]; + Ls[(i + 2 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[0]; + Ls[(i + 3 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[2]; + Ls[(i + 4 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[0]; + Ls[(i + 5 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[1]; + Ls[(i + 6 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[0]; + } + + Ls[(7 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[3]; + Ls[(15 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[4]; + Ls[(23 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[3]; + l = &Ls[(31 + n) % 32]; + + /* Process data in 32 block chunks. */ + while (nblocks >= 32) + { + blkn += 32; + *l = (uintptr_t)(void *)ocb_get_l(c, blkn - blkn % 32); + + _gcry_camellia_aesni_avx2_ocb_auth(ctx, abuf, + c->u_mode.ocb.aad_offset, + c->u_mode.ocb.aad_sum, Ls); + + nblocks -= 32; + abuf += 32 * CAMELLIA_BLOCK_SIZE; + did_use_aesni_avx2 = 1; + } + } + + if (did_use_aesni_avx2) + { + int avx2_burn_stack_depth = 32 * CAMELLIA_BLOCK_SIZE + + 2 * sizeof(void *) + ASM_EXTRA_STACK; + + if (burn_stack_depth < avx2_burn_stack_depth) + burn_stack_depth = avx2_burn_stack_depth; + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + +#ifdef USE_AESNI_AVX + if (ctx->use_aesni_avx) + { + int did_use_aesni_avx = 0; + u64 Ls[16]; + unsigned int n = 16 - (blkn % 16); + u64 *l; + int i; + + if (nblocks >= 16) + { + for (i = 0; i < 16; i += 8) + { + /* Use u64 to store pointers for x32 support (assembly function + * assumes 64-bit pointers). */ + Ls[(i + 0 + n) % 16] = (uintptr_t)(void *)c->u_mode.ocb.L[0]; + Ls[(i + 1 + n) % 16] = (uintptr_t)(void *)c->u_mode.ocb.L[1]; + Ls[(i + 2 + n) % 16] = (uintptr_t)(void *)c->u_mode.ocb.L[0]; + Ls[(i + 3 + n) % 16] = (uintptr_t)(void *)c->u_mode.ocb.L[2]; + Ls[(i + 4 + n) % 16] = (uintptr_t)(void *)c->u_mode.ocb.L[0]; + Ls[(i + 5 + n) % 16] = (uintptr_t)(void *)c->u_mode.ocb.L[1]; + Ls[(i + 6 + n) % 16] = (uintptr_t)(void *)c->u_mode.ocb.L[0]; + } + + Ls[(7 + n) % 16] = (uintptr_t)(void *)c->u_mode.ocb.L[3]; + l = &Ls[(15 + n) % 16]; + + /* Process data in 16 block chunks. */ + while (nblocks >= 16) + { + blkn += 16; + *l = (uintptr_t)(void *)ocb_get_l(c, blkn - blkn % 16); + + _gcry_camellia_aesni_avx_ocb_auth(ctx, abuf, + c->u_mode.ocb.aad_offset, + c->u_mode.ocb.aad_sum, Ls); + + nblocks -= 16; + abuf += 16 * CAMELLIA_BLOCK_SIZE; + did_use_aesni_avx = 1; + } + } + + if (did_use_aesni_avx) + { + int avx_burn_stack_depth = 16 * CAMELLIA_BLOCK_SIZE + + 2 * sizeof(void *) + ASM_EXTRA_STACK; + + if (burn_stack_depth < avx_burn_stack_depth) + burn_stack_depth = avx_burn_stack_depth; + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + +#if defined(USE_AESNI_AVX) || defined(USE_AESNI_AVX2) + c->u_mode.ocb.aad_nblocks = blkn; + + if (burn_stack_depth) + _gcry_burn_stack (burn_stack_depth + 4 * sizeof(void *)); +#endif + + return nblocks; +} + +/* Run the self-tests for CAMELLIA-CTR-128, tests IV increment of bulk CTR + encryption. Returns NULL on success. */ +static const char* +selftest_ctr_128 (void) +{ + const int nblocks = 32+16+1; + const int blocksize = CAMELLIA_BLOCK_SIZE; + const int context_size = sizeof(CAMELLIA_context); + + return _gcry_selftest_helper_ctr("CAMELLIA", &camellia_setkey, + &camellia_encrypt, nblocks, blocksize, context_size); +} + +/* Run the self-tests for CAMELLIA-CBC-128, tests bulk CBC decryption. + Returns NULL on success. */ +static const char* +selftest_cbc_128 (void) +{ + const int nblocks = 32+16+2; + const int blocksize = CAMELLIA_BLOCK_SIZE; + const int context_size = sizeof(CAMELLIA_context); + + return _gcry_selftest_helper_cbc("CAMELLIA", &camellia_setkey, + &camellia_encrypt, nblocks, blocksize, context_size); +} + +/* Run the self-tests for CAMELLIA-CFB-128, tests bulk CFB decryption. + Returns NULL on success. */ +static const char* +selftest_cfb_128 (void) +{ + const int nblocks = 32+16+2; + const int blocksize = CAMELLIA_BLOCK_SIZE; + const int context_size = sizeof(CAMELLIA_context); + + return _gcry_selftest_helper_cfb("CAMELLIA", &camellia_setkey, + &camellia_encrypt, nblocks, blocksize, context_size); +} + +static const char * +selftest(void) +{ + CAMELLIA_context ctx; + byte scratch[16]; + cipher_bulk_ops_t bulk_ops; + const char *r; + + /* These test vectors are from RFC-3713 */ + static const byte plaintext[]= + { + 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef, + 0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10 + }; + static const byte key_128[]= + { + 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef, + 0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10 + }; + static const byte ciphertext_128[]= + { + 0x67,0x67,0x31,0x38,0x54,0x96,0x69,0x73, + 0x08,0x57,0x06,0x56,0x48,0xea,0xbe,0x43 + }; + static const byte key_192[]= + { + 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98, + 0x76,0x54,0x32,0x10,0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77 + }; + static const byte ciphertext_192[]= + { + 0xb4,0x99,0x34,0x01,0xb3,0xe9,0x96,0xf8, + 0x4e,0xe5,0xce,0xe7,0xd7,0x9b,0x09,0xb9 + }; + static const byte key_256[]= + { + 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba, + 0x98,0x76,0x54,0x32,0x10,0x00,0x11,0x22,0x33,0x44,0x55, + 0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff + }; + static const byte ciphertext_256[]= + { + 0x9a,0xcc,0x23,0x7d,0xff,0x16,0xd7,0x6c, + 0x20,0xef,0x7c,0x91,0x9e,0x3a,0x75,0x09 + }; + + camellia_setkey(&ctx,key_128,sizeof(key_128),&bulk_ops); + camellia_encrypt(&ctx,scratch,plaintext); + if(memcmp(scratch,ciphertext_128,sizeof(ciphertext_128))!=0) + return "CAMELLIA-128 test encryption failed."; + camellia_decrypt(&ctx,scratch,scratch); + if(memcmp(scratch,plaintext,sizeof(plaintext))!=0) + return "CAMELLIA-128 test decryption failed."; + + camellia_setkey(&ctx,key_192,sizeof(key_192),&bulk_ops); + camellia_encrypt(&ctx,scratch,plaintext); + if(memcmp(scratch,ciphertext_192,sizeof(ciphertext_192))!=0) + return "CAMELLIA-192 test encryption failed."; + camellia_decrypt(&ctx,scratch,scratch); + if(memcmp(scratch,plaintext,sizeof(plaintext))!=0) + return "CAMELLIA-192 test decryption failed."; + + camellia_setkey(&ctx,key_256,sizeof(key_256),&bulk_ops); + camellia_encrypt(&ctx,scratch,plaintext); + if(memcmp(scratch,ciphertext_256,sizeof(ciphertext_256))!=0) + return "CAMELLIA-256 test encryption failed."; + camellia_decrypt(&ctx,scratch,scratch); + if(memcmp(scratch,plaintext,sizeof(plaintext))!=0) + return "CAMELLIA-256 test decryption failed."; + + if ( (r = selftest_ctr_128 ()) ) + return r; + + if ( (r = selftest_cbc_128 ()) ) + return r; + + if ( (r = selftest_cfb_128 ()) ) + return r; + + return NULL; +} + +/* These oids are from + <http://info.isl.ntt.co.jp/crypt/eng/camellia/specifications_oid.html>, + retrieved May 1, 2007. */ + +static gcry_cipher_oid_spec_t camellia128_oids[] = + { + {"1.2.392.200011.61.1.1.1.2", GCRY_CIPHER_MODE_CBC}, + {"0.3.4401.5.3.1.9.1", GCRY_CIPHER_MODE_ECB}, + {"0.3.4401.5.3.1.9.3", GCRY_CIPHER_MODE_OFB}, + {"0.3.4401.5.3.1.9.4", GCRY_CIPHER_MODE_CFB}, + { NULL } + }; + +static gcry_cipher_oid_spec_t camellia192_oids[] = + { + {"1.2.392.200011.61.1.1.1.3", GCRY_CIPHER_MODE_CBC}, + {"0.3.4401.5.3.1.9.21", GCRY_CIPHER_MODE_ECB}, + {"0.3.4401.5.3.1.9.23", GCRY_CIPHER_MODE_OFB}, + {"0.3.4401.5.3.1.9.24", GCRY_CIPHER_MODE_CFB}, + { NULL } + }; + +static gcry_cipher_oid_spec_t camellia256_oids[] = + { + {"1.2.392.200011.61.1.1.1.4", GCRY_CIPHER_MODE_CBC}, + {"0.3.4401.5.3.1.9.41", GCRY_CIPHER_MODE_ECB}, + {"0.3.4401.5.3.1.9.43", GCRY_CIPHER_MODE_OFB}, + {"0.3.4401.5.3.1.9.44", GCRY_CIPHER_MODE_CFB}, + { NULL } + }; + +gcry_cipher_spec_t _gcry_cipher_spec_camellia128 = + { + GCRY_CIPHER_CAMELLIA128, {0, 0}, + "CAMELLIA128",NULL,camellia128_oids,CAMELLIA_BLOCK_SIZE,128, + sizeof(CAMELLIA_context),camellia_setkey,camellia_encrypt,camellia_decrypt + }; + +gcry_cipher_spec_t _gcry_cipher_spec_camellia192 = + { + GCRY_CIPHER_CAMELLIA192, {0, 0}, + "CAMELLIA192",NULL,camellia192_oids,CAMELLIA_BLOCK_SIZE,192, + sizeof(CAMELLIA_context),camellia_setkey,camellia_encrypt,camellia_decrypt + }; + +gcry_cipher_spec_t _gcry_cipher_spec_camellia256 = + { + GCRY_CIPHER_CAMELLIA256, {0, 0}, + "CAMELLIA256",NULL,camellia256_oids,CAMELLIA_BLOCK_SIZE,256, + sizeof(CAMELLIA_context),camellia_setkey,camellia_encrypt,camellia_decrypt + }; |