Changeset View
Changeset View
Standalone View
Standalone View
cipher/rijndael.c
| Context not available. | |||||
| void *outbuf_arg, | void *outbuf_arg, | ||||
| const void *inbuf_arg, | const void *inbuf_arg, | ||||
| size_t nblocks, int encrypt); | size_t nblocks, int encrypt); | ||||
| #endif /*USE_ARM_ASM*/ | #endif /*USE_ARM_ASM*/ | ||||
| /* forward declaration */ | |||||
| static int _gcry_aes_generic_cbc_enc (const void *context, unsigned char *iv, | |||||
| void *outbuf_arg, const void *inbuf_arg, | |||||
| size_t nblocks, | |||||
| int cbc_mac); | |||||
| #ifdef USE_PPC_ASM | |||||
| /* POWER 8 AES extensions */ | |||||
| extern void aes_p8_encrypt (const unsigned char *in, | |||||
| unsigned char *out, | |||||
| const RIJNDAEL_context *ctx); | |||||
| static unsigned int _gcry_aes_ppc8_encrypt (const RIJNDAEL_context *ctx, | |||||
| unsigned char *out, | |||||
| const unsigned char *in) | |||||
| { | |||||
| /* When I tried to switch these registers in the assembly it broke. */ | |||||
| aes_p8_encrypt (in, out, ctx); | |||||
| return 0; /* does not use stack */ | |||||
| } | |||||
| /* this is the decryption key part of context */ | |||||
| extern void aes_p8_decrypt (const unsigned char *in, | |||||
| unsigned char *out, | |||||
| const void *sboxes); | |||||
| static unsigned int _gcry_aes_ppc8_decrypt (const RIJNDAEL_context *ctx, | |||||
| unsigned char *out, | |||||
| const unsigned char *in) | |||||
| { | |||||
| aes_p8_decrypt (in, out, &ctx->u2); | |||||
| return 0; /* does not use stack */ | |||||
| } | |||||
| extern int aes_p8_set_encrypt_key (const unsigned char *userKey, const int bits, | |||||
| RIJNDAEL_context *key); | |||||
| extern int aes_p8_set_decrypt_key (const unsigned char *userKey, const int bits, | |||||
| /* this is the decryption key part of context */ | |||||
| const unsigned (*)[15][4]); | |||||
| #endif /*USE_PPC_ASM*/ | |||||
| static unsigned int do_encrypt (const RIJNDAEL_context *ctx, unsigned char *bx, | static unsigned int do_encrypt (const RIJNDAEL_context *ctx, unsigned char *bx, | ||||
| const unsigned char *ax); | const unsigned char *ax); | ||||
| static unsigned int do_decrypt (const RIJNDAEL_context *ctx, unsigned char *bx, | static unsigned int do_decrypt (const RIJNDAEL_context *ctx, unsigned char *bx, | ||||
| const unsigned char *ax); | const unsigned char *ax); | ||||
| Context not available. | |||||
| static const char *selftest_failed = 0; | static const char *selftest_failed = 0; | ||||
| int rounds; | int rounds; | ||||
| int i,j, r, t, rconpointer = 0; | int i,j, r, t, rconpointer = 0; | ||||
| int KC; | int KC; | ||||
| #if defined(USE_AESNI) || defined(USE_PADLOCK) || defined(USE_SSSE3) \ | #if defined(USE_AESNI) || defined(USE_PADLOCK) || defined(USE_SSSE3) \ | ||||
| || defined(USE_ARM_CE) | || defined(USE_ARM_CE) || defined(USE_PPC_ASM) | ||||
| unsigned int hwfeatures; | unsigned int hwfeatures; | ||||
| #endif | #endif | ||||
| (void)hd; | (void)hd; | ||||
| Context not available. | |||||
| return GPG_ERR_INV_KEYLEN; | return GPG_ERR_INV_KEYLEN; | ||||
| ctx->rounds = rounds; | ctx->rounds = rounds; | ||||
| #if defined(USE_AESNI) || defined(USE_PADLOCK) || defined(USE_SSSE3) \ | #if defined(USE_AESNI) || defined(USE_PADLOCK) || defined(USE_SSSE3) \ | ||||
| || defined(USE_ARM_CE) | || defined(USE_ARM_CE) || defined(USE_PPC_ASM) | ||||
| hwfeatures = _gcry_get_hw_features (); | hwfeatures = _gcry_get_hw_features (); | ||||
| #endif | #endif | ||||
| ctx->decryption_prepared = 0; | ctx->decryption_prepared = 0; | ||||
| #ifdef USE_PADLOCK | #ifdef USE_PADLOCK | ||||
| Context not available. | |||||
| ctx->use_ssse3 = 0; | ctx->use_ssse3 = 0; | ||||
| #endif | #endif | ||||
| #ifdef USE_ARM_CE | #ifdef USE_ARM_CE | ||||
| ctx->use_arm_ce = 0; | ctx->use_arm_ce = 0; | ||||
| #endif | #endif | ||||
| #ifdef USE_PPC_ASM | |||||
| ctx->use_ppc_asm = 0; | |||||
| #endif | |||||
| if (0) | if (0) | ||||
| { | { | ||||
| ; | ; | ||||
| } | } | ||||
| Context not available. | |||||
| hd->bulk.ocb_crypt = _gcry_aes_armv8_ce_ocb_crypt; | hd->bulk.ocb_crypt = _gcry_aes_armv8_ce_ocb_crypt; | ||||
| hd->bulk.ocb_auth = _gcry_aes_armv8_ce_ocb_auth; | hd->bulk.ocb_auth = _gcry_aes_armv8_ce_ocb_auth; | ||||
| hd->bulk.xts_crypt = _gcry_aes_armv8_ce_xts_crypt; | hd->bulk.xts_crypt = _gcry_aes_armv8_ce_xts_crypt; | ||||
| } | } | ||||
| } | } | ||||
| #endif | |||||
| #ifdef USE_PPC_ASM | |||||
| else if (hwfeatures & HWF_PPC_VCRYPTO) | |||||
| { | |||||
| ctx->encrypt_fn = _gcry_aes_ppc8_encrypt; | |||||
| ctx->decrypt_fn = _gcry_aes_ppc8_decrypt; | |||||
| ctx->prefetch_enc_fn = NULL; | |||||
| ctx->prefetch_dec_fn = NULL; | |||||
| ctx->use_ppc_asm = 1; | |||||
| } | |||||
| #endif | #endif | ||||
| else | else | ||||
| { | { | ||||
| ctx->encrypt_fn = do_encrypt; | ctx->encrypt_fn = do_encrypt; | ||||
| ctx->decrypt_fn = do_decrypt; | ctx->decrypt_fn = do_decrypt; | ||||
| Context not available. | |||||
| _gcry_aes_ssse3_do_setkey (ctx, key); | _gcry_aes_ssse3_do_setkey (ctx, key); | ||||
| #endif | #endif | ||||
| #ifdef USE_ARM_CE | #ifdef USE_ARM_CE | ||||
| else if (ctx->use_arm_ce) | else if (ctx->use_arm_ce) | ||||
| _gcry_aes_armv8_ce_setkey (ctx, key); | _gcry_aes_armv8_ce_setkey (ctx, key); | ||||
| #endif | |||||
| #ifdef USE_PPC_ASM | |||||
| else if (ctx->use_ppc_asm) { | |||||
| /* These are both done here to avoid having to store the key. | |||||
| * These S-boxes are generated on-the-fly. */ | |||||
| aes_p8_set_encrypt_key (key, keylen * 8, ctx); | |||||
| aes_p8_set_decrypt_key (key, keylen * 8, &ctx->keyschdec32); | |||||
| } | |||||
| #endif | #endif | ||||
| else | else | ||||
| { | { | ||||
| const byte *sbox = ((const byte *)encT) + 1; | const byte *sbox = ((const byte *)encT) + 1; | ||||
| union | union | ||||
| Context not available. | |||||
| else if (ctx->use_padlock) | else if (ctx->use_padlock) | ||||
| { | { | ||||
| /* Padlock does not need decryption subkeys. */ | /* Padlock does not need decryption subkeys. */ | ||||
| } | } | ||||
| #endif /*USE_PADLOCK*/ | #endif /*USE_PADLOCK*/ | ||||
| #ifdef USE_PPC_ASM | |||||
| else if (ctx->use_ppc_asm) | |||||
| { | |||||
| /* done during encryption key setup, as then we have the actual | |||||
| * key available */ | |||||
| } | |||||
| #endif /*USE_PPC_ASM*/ | |||||
| else | else | ||||
| { | { | ||||
| const byte *sbox = ((const byte *)encT) + 1; | const byte *sbox = ((const byte *)encT) + 1; | ||||
| prefetch_enc(); | prefetch_enc(); | ||||
| Context not available. | |||||
| ctx->keyschdec32[r][3] = ctx->keyschenc32[r][3]; | ctx->keyschdec32[r][3] = ctx->keyschenc32[r][3]; | ||||
| } | } | ||||
| } | } | ||||
| ␌ | ␌ | ||||
| #if !defined(USE_ARM_ASM) && !defined(USE_AMD64_ASM) | #if !defined(USE_ARM_ASM) && !defined(USE_AMD64_ASM) && !defined(USE_PPC_ASM) | ||||
| /* Encrypt one block. A and B may be the same. */ | /* Encrypt one block. A and B may be the same. */ | ||||
| static unsigned int | static unsigned int | ||||
| do_encrypt_fn (const RIJNDAEL_context *ctx, unsigned char *b, | do_encrypt_fn (const RIJNDAEL_context *ctx, unsigned char *b, | ||||
| const unsigned char *a) | const unsigned char *a) | ||||
| { | { | ||||
| Context not available. | |||||
| buf_put_le32(b + 12, sa[3]); | buf_put_le32(b + 12, sa[3]); | ||||
| #undef rk | #undef rk | ||||
| return (56 + 2*sizeof(int)); | return (56 + 2*sizeof(int)); | ||||
| } | } | ||||
| #endif /*!USE_ARM_ASM && !USE_AMD64_ASM*/ | #endif /*!USE_ARM_ASM && !USE_AMD64_ASM && !USE_PPC_ASM*/ | ||||
| static unsigned int | static unsigned int | ||||
| do_encrypt (const RIJNDAEL_context *ctx, | do_encrypt (const RIJNDAEL_context *ctx, | ||||
| unsigned char *bx, const unsigned char *ax) | unsigned char *bx, const unsigned char *ax) | ||||
| Context not available. | |||||
| return _gcry_aes_amd64_encrypt_block(ctx->keyschenc, bx, ax, ctx->rounds, | return _gcry_aes_amd64_encrypt_block(ctx->keyschenc, bx, ax, ctx->rounds, | ||||
| enc_tables.T); | enc_tables.T); | ||||
| #elif defined(USE_ARM_ASM) | #elif defined(USE_ARM_ASM) | ||||
| return _gcry_aes_arm_encrypt_block(ctx->keyschenc, bx, ax, ctx->rounds, | return _gcry_aes_arm_encrypt_block(ctx->keyschenc, bx, ax, ctx->rounds, | ||||
| enc_tables.T); | enc_tables.T); | ||||
| #elif defined(USE_PPC_ASM) | |||||
| return _gcry_aes_ppc8_encrypt(ctx, bx, ax); | |||||
| #else | #else | ||||
| return do_encrypt_fn (ctx, bx, ax); | return do_encrypt_fn (ctx, bx, ax); | ||||
| #endif /* !USE_ARM_ASM && !USE_AMD64_ASM*/ | #endif /* !USE_ARM_ASM && !USE_AMD64_ASM*/ | ||||
| } | } | ||||
| Context not available. | |||||
| if (burn_depth) | if (burn_depth) | ||||
| _gcry_burn_stack (burn_depth + 4 * sizeof(void *)); | _gcry_burn_stack (burn_depth + 4 * sizeof(void *)); | ||||
| } | } | ||||
| static int _gcry_aes_generic_cbc_enc (const void *context, unsigned char *iv, | |||||
| void *outbuf_arg, const void *inbuf_arg, | |||||
| size_t nblocks, | |||||
| int cbc_mac) | |||||
| { | |||||
| const RIJNDAEL_context *ctx = context; | |||||
| unsigned char *outbuf = outbuf_arg; | |||||
| const unsigned char *inbuf = inbuf_arg; | |||||
| rijndael_cryptfn_t encrypt_fn = ctx->encrypt_fn; | |||||
| int burn_depth = 0; | |||||
| unsigned char *last_iv = iv; | |||||
| if (ctx->prefetch_enc_fn) | |||||
| ctx->prefetch_enc_fn(); | |||||
| for ( ;nblocks; nblocks-- ) | |||||
| { | |||||
| cipher_block_xor(outbuf, inbuf, last_iv, BLOCKSIZE); | |||||
| burn_depth = encrypt_fn (ctx, outbuf, outbuf); | |||||
| last_iv = outbuf; | |||||
| inbuf += BLOCKSIZE; | |||||
| if (!cbc_mac) | |||||
| outbuf += BLOCKSIZE; | |||||
| } | |||||
| if (last_iv != iv) | |||||
| cipher_block_cpy (iv, last_iv, BLOCKSIZE); | |||||
| if (burn_depth) | |||||
| _gcry_burn_stack (burn_depth + 4 * sizeof(void *)); | |||||
| return 0; | |||||
| } | |||||
| /* Bulk encryption of complete blocks in CBC mode. Caller needs to | /* Bulk encryption of complete blocks in CBC mode. Caller needs to | ||||
| make sure that IV is aligned on an unsigned long boundary. This | make sure that IV is aligned on an unsigned long boundary. This | ||||
| function is only intended for the bulk encryption feature of | function is only intended for the bulk encryption feature of | ||||
| cipher.c. */ | cipher.c. */ | ||||
| Context not available. | |||||
| size_t nblocks, int cbc_mac) | size_t nblocks, int cbc_mac) | ||||
| { | { | ||||
| RIJNDAEL_context *ctx = context; | RIJNDAEL_context *ctx = context; | ||||
| unsigned char *outbuf = outbuf_arg; | unsigned char *outbuf = outbuf_arg; | ||||
| const unsigned char *inbuf = inbuf_arg; | const unsigned char *inbuf = inbuf_arg; | ||||
| unsigned char *last_iv; | |||||
| unsigned int burn_depth = 0; | unsigned int burn_depth = 0; | ||||
| if (0) | if (0) | ||||
| ; | ; | ||||
| #ifdef USE_AESNI | #ifdef USE_AESNI | ||||
| Context not available. | |||||
| return; | return; | ||||
| } | } | ||||
| #endif /*USE_ARM_CE*/ | #endif /*USE_ARM_CE*/ | ||||
| else | else | ||||
| { | { | ||||
| rijndael_cryptfn_t encrypt_fn = ctx->encrypt_fn; | _gcry_aes_generic_cbc_enc (ctx, iv, outbuf, inbuf, nblocks, cbc_mac); | ||||
| return; | |||||
| if (ctx->prefetch_enc_fn) | |||||
| ctx->prefetch_enc_fn(); | |||||
| last_iv = iv; | |||||
| for ( ;nblocks; nblocks-- ) | |||||
| { | |||||
| cipher_block_xor(outbuf, inbuf, last_iv, BLOCKSIZE); | |||||
| burn_depth = encrypt_fn (ctx, outbuf, outbuf); | |||||
| last_iv = outbuf; | |||||
| inbuf += BLOCKSIZE; | |||||
| if (!cbc_mac) | |||||
| outbuf += BLOCKSIZE; | |||||
| } | |||||
| if (last_iv != iv) | |||||
| cipher_block_cpy (iv, last_iv, BLOCKSIZE); | |||||
| } | } | ||||
| if (burn_depth) | if (burn_depth) | ||||
| _gcry_burn_stack (burn_depth + 4 * sizeof(void *)); | _gcry_burn_stack (burn_depth + 4 * sizeof(void *)); | ||||
| } | } | ||||
| Context not available. | |||||
| _gcry_burn_stack (burn_depth + 4 * sizeof(void *)); | _gcry_burn_stack (burn_depth + 4 * sizeof(void *)); | ||||
| } | } | ||||
| ␌ | ␌ | ||||
| #if !defined(USE_ARM_ASM) && !defined(USE_AMD64_ASM) | #if !defined(USE_ARM_ASM) && !defined(USE_AMD64_ASM) && !defined(USE_PPC_ASM) | ||||
| /* Decrypt one block. A and B may be the same. */ | /* Decrypt one block. A and B may be the same. */ | ||||
| static unsigned int | static unsigned int | ||||
| do_decrypt_fn (const RIJNDAEL_context *ctx, unsigned char *b, | do_decrypt_fn (const RIJNDAEL_context *ctx, unsigned char *b, | ||||
| const unsigned char *a) | const unsigned char *a) | ||||
| { | { | ||||
| Context not available. | |||||
| buf_put_le32(b + 12, sa[3]); | buf_put_le32(b + 12, sa[3]); | ||||
| #undef rk | #undef rk | ||||
| return (56+2*sizeof(int)); | return (56+2*sizeof(int)); | ||||
| } | } | ||||
| #endif /*!USE_ARM_ASM && !USE_AMD64_ASM*/ | #endif /*!USE_ARM_ASM && !USE_AMD64_ASM && !USE_PPC_ASM*/ | ||||
| /* Decrypt one block. AX and BX may be the same. */ | /* Decrypt one block. AX and BX may be the same. */ | ||||
| static unsigned int | static unsigned int | ||||
| do_decrypt (const RIJNDAEL_context *ctx, unsigned char *bx, | do_decrypt (const RIJNDAEL_context *ctx, unsigned char *bx, | ||||
| Context not available. | |||||
| return _gcry_aes_amd64_decrypt_block(ctx->keyschdec, bx, ax, ctx->rounds, | return _gcry_aes_amd64_decrypt_block(ctx->keyschdec, bx, ax, ctx->rounds, | ||||
| dec_tables.T); | dec_tables.T); | ||||
| #elif defined(USE_ARM_ASM) | #elif defined(USE_ARM_ASM) | ||||
| return _gcry_aes_arm_decrypt_block(ctx->keyschdec, bx, ax, ctx->rounds, | return _gcry_aes_arm_decrypt_block(ctx->keyschdec, bx, ax, ctx->rounds, | ||||
| dec_tables.T); | dec_tables.T); | ||||
| #elif defined(USE_PPC_ASM) | |||||
| return _gcry_aes_ppc8_decrypt(ctx, bx, ax); | |||||
| #else | #else | ||||
| return do_decrypt_fn (ctx, bx, ax); | return do_decrypt_fn (ctx, bx, ax); | ||||
| #endif /*!USE_ARM_ASM && !USE_AMD64_ASM*/ | #endif | ||||
| } | } | ||||
| static inline void | static inline void | ||||
| check_decryption_preparation (RIJNDAEL_context *ctx) | check_decryption_preparation (RIJNDAEL_context *ctx) | ||||
| Context not available. | |||||
| }; | }; | ||||
| static const unsigned char key_128[16] = | static const unsigned char key_128[16] = | ||||
| { | { | ||||
| 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, | 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, | ||||
| 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f | 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f | ||||
| /* 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, */ | |||||
| /* 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c */ | |||||
| }; | }; | ||||
| static const unsigned char ciphertext_128[16] = | static const unsigned char ciphertext_128[16] = | ||||
| { | { | ||||
| 0x69,0xc4,0xe0,0xd8,0x6a,0x7b,0x04,0x30, | 0x69,0xc4,0xe0,0xd8,0x6a,0x7b,0x04,0x30, | ||||
| 0xd8,0xcd,0xb7,0x80,0x70,0xb4,0xc5,0x5a | 0xd8,0xcd,0xb7,0x80,0x70,0xb4,0xc5,0x5a | ||||
| }; | }; | ||||
| static const unsigned char key_test_expansion_128[16] = | |||||
| { | |||||
| 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, | |||||
| 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c | |||||
| }; | |||||
| RIJNDAEL_context exp_ctx; | |||||
| rijndael_setkey (&exp_ctx, key_test_expansion_128, sizeof (key_128), NULL); | |||||
| #endif | #endif | ||||
| /* Because gcc/ld can only align the CTX struct on 8 bytes on the | /* Because gcc/ld can only align the CTX struct on 8 bytes on the | ||||
| stack, we need to allocate that context on the heap. */ | stack, we need to allocate that context on the heap. */ | ||||
| ctx = _gcry_cipher_selftest_alloc_ctx (sizeof *ctx, &ctxmem); | ctx = _gcry_cipher_selftest_alloc_ctx (sizeof *ctx, &ctxmem); | ||||
| Context not available. | |||||
| if (memcmp (scratch, ciphertext_128, sizeof (ciphertext_128))) | if (memcmp (scratch, ciphertext_128, sizeof (ciphertext_128))) | ||||
| { | { | ||||
| xfree (ctxmem); | xfree (ctxmem); | ||||
| return "AES-128 test encryption failed."; | return "AES-128 test encryption failed."; | ||||
| } | } | ||||
| rijndael_decrypt (ctx, scratch, scratch); | rijndael_decrypt (ctx, scratch, ciphertext_128); | ||||
| xfree (ctxmem); | xfree (ctxmem); | ||||
| if (memcmp (scratch, plaintext_128, sizeof (plaintext_128))) | if (memcmp (scratch, plaintext_128, sizeof (plaintext_128))) | ||||
| return "AES-128 test decryption failed."; | return "AES-128 test decryption failed."; | ||||
| return NULL; | return NULL; | ||||
| Context not available. | |||||