blob: 3f1e061fe60669c3a34a6a4eb2e7913b75ca1e9e [file]
/*
* AESNI.c: AES using AES-NI instructions
*
* Written in 2013 by Sebastian Ramacher <sebastian@ramacher.at>
*
* ===================================================================
* The contents of this file are dedicated to the public domain. To
* the extent that dedication to the public domain is not available,
* everyone is granted a worldwide, perpetual, royalty-free,
* non-exclusive license to exercise all rights associated with the
* contents of this file for any purpose whatsoever.
* No rights are reserved.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
* ===================================================================
*/
#include "pycrypto_common.h"
#include <wmmintrin.h>
#include <stdlib.h>
#if defined(HAVE__ALIGNED_MALLOC)
#include <malloc.h>
#endif
#define MODULE_NAME _AESNI
#define BLOCK_SIZE 16
#define KEY_SIZE 0
#define MAXKC (256/32)
#define MAXKB (256/8)
#define MAXNR 14
typedef unsigned char u8;
typedef struct {
__m128i* ek;
__m128i* dk;
int rounds;
} block_state;
/* Wrapper functions for malloc and free with memory alignment */
#if defined(HAVE_ALIGNED_ALLOC) /* aligned_alloc is defined by C11 */
# define aligned_malloc_wrapper aligned_alloc
# define aligned_free_wrapper free
#elif defined(HAVE_POSIX_MEMALIGN) /* posix_memalign is defined by POSIX */
static void* aligned_malloc_wrapper(size_t alignment, size_t size)
{
void* tmp = NULL;
int err = posix_memalign(&tmp, alignment, size);
if (err != 0) {
/* posix_memalign does NOT set errno on failure; the error is returned */
errno = err;
return NULL;
}
return tmp;
}
# define aligned_free_wrapper free
#elif defined(HAVE__ALIGNED_MALLOC) /* _aligned_malloc is available on Windows */
static void* aligned_malloc_wrapper(size_t alignment, size_t size)
{
/* NB: _aligned_malloc takes its args in the opposite order from aligned_alloc */
return _aligned_malloc(size, alignment);
}
# define aligned_free_wrapper _aligned_free
#else
# error "No function to allocate/free aligned memory is available."
#endif
/* Helper functions to expand keys */
static __m128i aes128_keyexpand(__m128i key)
{
key = _mm_xor_si128(key, _mm_slli_si128(key, 4));
key = _mm_xor_si128(key, _mm_slli_si128(key, 4));
return _mm_xor_si128(key, _mm_slli_si128(key, 4));
}
static __m128i aes192_keyexpand_2(__m128i key, __m128i key2)
{
key = _mm_shuffle_epi32(key, 0xff);
key2 = _mm_xor_si128(key2, _mm_slli_si128(key2, 4));
return _mm_xor_si128(key, key2);
}
#define KEYEXP128_H(K1, K2, I, S) _mm_xor_si128(aes128_keyexpand(K1), \
_mm_shuffle_epi32(_mm_aeskeygenassist_si128(K2, I), S))
#define KEYEXP128(K, I) KEYEXP128_H(K, K, I, 0xff)
#define KEYEXP192(K1, K2, I) KEYEXP128_H(K1, K2, I, 0x55)
#define KEYEXP192_2(K1, K2) aes192_keyexpand_2(K1, K2)
#define KEYEXP256(K1, K2, I) KEYEXP128_H(K1, K2, I, 0xff)
#define KEYEXP256_2(K1, K2) KEYEXP128_H(K1, K2, 0x00, 0xaa)
/* Encryption key setup */
static void aes_key_setup_enc(__m128i rk[], const u8* cipherKey, int keylen)
{
switch (keylen) {
case 16:
{
/* 128 bit key setup */
rk[0] = _mm_loadu_si128((const __m128i*) cipherKey);
rk[1] = KEYEXP128(rk[0], 0x01);
rk[2] = KEYEXP128(rk[1], 0x02);
rk[3] = KEYEXP128(rk[2], 0x04);
rk[4] = KEYEXP128(rk[3], 0x08);
rk[5] = KEYEXP128(rk[4], 0x10);
rk[6] = KEYEXP128(rk[5], 0x20);
rk[7] = KEYEXP128(rk[6], 0x40);
rk[8] = KEYEXP128(rk[7], 0x80);
rk[9] = KEYEXP128(rk[8], 0x1B);
rk[10] = KEYEXP128(rk[9], 0x36);
break;
}
case 24:
{
/* 192 bit key setup */
__m128i temp[2];
rk[0] = _mm_loadu_si128((const __m128i*) cipherKey);
rk[1] = _mm_loadu_si128((const __m128i*) (cipherKey+16));
temp[0] = KEYEXP192(rk[0], rk[1], 0x01);
temp[1] = KEYEXP192_2(temp[0], rk[1]);
rk[1] = (__m128i)_mm_shuffle_pd((__m128d)rk[1], (__m128d)temp[0], 0);
rk[2] = (__m128i)_mm_shuffle_pd((__m128d)temp[0], (__m128d)temp[1], 1);
rk[3] = KEYEXP192(temp[0], temp[1], 0x02);
rk[4] = KEYEXP192_2(rk[3], temp[1]);
temp[0] = KEYEXP192(rk[3], rk[4], 0x04);
temp[1] = KEYEXP192_2(temp[0], rk[4]);
rk[4] = (__m128i)_mm_shuffle_pd((__m128d)rk[4], (__m128d)temp[0], 0);
rk[5] = (__m128i)_mm_shuffle_pd((__m128d)temp[0], (__m128d)temp[1], 1);
rk[6] = KEYEXP192(temp[0], temp[1], 0x08);
rk[7] = KEYEXP192_2(rk[6], temp[1]);
temp[0] = KEYEXP192(rk[6], rk[7], 0x10);
temp[1] = KEYEXP192_2(temp[0], rk[7]);
rk[7] = (__m128i)_mm_shuffle_pd((__m128d)rk[7], (__m128d)temp[0], 0);
rk[8] = (__m128i)_mm_shuffle_pd((__m128d)temp[0], (__m128d)temp[1], 1);
rk[9] = KEYEXP192(temp[0], temp[1], 0x20);
rk[10] = KEYEXP192_2(rk[9], temp[1]);
temp[0] = KEYEXP192(rk[9], rk[10], 0x40);
temp[1] = KEYEXP192_2(temp[0], rk[10]);
rk[10] = (__m128i)_mm_shuffle_pd((__m128d)rk[10], (__m128d) temp[0], 0);
rk[11] = (__m128i)_mm_shuffle_pd((__m128d)temp[0],(__m128d) temp[1], 1);
rk[12] = KEYEXP192(temp[0], temp[1], 0x80);
break;
}
case 32:
{
/* 256 bit key setup */
rk[0] = _mm_loadu_si128((const __m128i*) cipherKey);
rk[1] = _mm_loadu_si128((const __m128i*) (cipherKey+16));
rk[2] = KEYEXP256(rk[0], rk[1], 0x01);
rk[3] = KEYEXP256_2(rk[1], rk[2]);
rk[4] = KEYEXP256(rk[2], rk[3], 0x02);
rk[5] = KEYEXP256_2(rk[3], rk[4]);
rk[6] = KEYEXP256(rk[4], rk[5], 0x04);
rk[7] = KEYEXP256_2(rk[5], rk[6]);
rk[8] = KEYEXP256(rk[6], rk[7], 0x08);
rk[9] = KEYEXP256_2(rk[7], rk[8]);
rk[10] = KEYEXP256(rk[8], rk[9], 0x10);
rk[11] = KEYEXP256_2(rk[9], rk[10]);
rk[12] = KEYEXP256(rk[10], rk[11], 0x20);
rk[13] = KEYEXP256_2(rk[11], rk[12]);
rk[14] = KEYEXP256(rk[12], rk[13], 0x40);
break;
}
}
}
/* Decryption key setup */
static void aes_key_setup_dec(__m128i dk[], const __m128i ek[], int rounds)
{
dk[rounds] = ek[0];
for (int i = 1; i < rounds; ++i) {
dk[rounds - i] = _mm_aesimc_si128(ek[i]);
}
dk[0] = ek[rounds];
}
static void block_init(block_state* self, unsigned char* key, int keylen)
{
int nr = 0;
switch (keylen) {
case 16: nr = 10; break;
case 24: nr = 12; break;
case 32: nr = 14; break;
default:
PyErr_SetString(PyExc_ValueError,
"AES key must be either 16, 24, or 32 bytes long");
return;
}
/* ensure that self->ek and self->dk are aligned to 16 byte boundaries */
void* tek = aligned_malloc_wrapper(16, (nr + 1) * sizeof(__m128i));
void* tdk = aligned_malloc_wrapper(16, (nr + 1) * sizeof(__m128i));
if (!tek || !tdk) {
aligned_free_wrapper(tek);
aligned_free_wrapper(tdk);
PyErr_SetString(PyExc_MemoryError,
"failed to allocate memory for keys");
return;
}
self->ek = tek;
self->dk = tdk;
self->rounds = nr;
aes_key_setup_enc(self->ek, key, keylen);
aes_key_setup_dec(self->dk, self->ek, nr);
}
static void block_finalize(block_state* self)
{
/* overwrite contents of ek and dk */
memset(self->ek, 0, (self->rounds + 1) * sizeof(__m128i));
memset(self->dk, 0, (self->rounds + 1) * sizeof(__m128i));
aligned_free_wrapper(self->ek);
aligned_free_wrapper(self->dk);
}
static void block_encrypt(block_state* self, const u8* in, u8* out)
{
__m128i m = _mm_loadu_si128((const __m128i*) in);
/* first 9 rounds */
m = _mm_xor_si128(m, self->ek[0]);
m = _mm_aesenc_si128(m, self->ek[1]);
m = _mm_aesenc_si128(m, self->ek[2]);
m = _mm_aesenc_si128(m, self->ek[3]);
m = _mm_aesenc_si128(m, self->ek[4]);
m = _mm_aesenc_si128(m, self->ek[5]);
m = _mm_aesenc_si128(m, self->ek[6]);
m = _mm_aesenc_si128(m, self->ek[7]);
m = _mm_aesenc_si128(m, self->ek[8]);
m = _mm_aesenc_si128(m, self->ek[9]);
if (self->rounds != 10) {
/* two additional rounds for AES-192/256 */
m = _mm_aesenc_si128(m, self->ek[10]);
m = _mm_aesenc_si128(m, self->ek[11]);
if (self->rounds == 14) {
/* another two additional rounds for AES-256 */
m = _mm_aesenc_si128(m, self->ek[12]);
m = _mm_aesenc_si128(m, self->ek[13]);
}
}
m = _mm_aesenclast_si128(m, self->ek[self->rounds]);
_mm_storeu_si128((__m128i*) out, m);
}
static void block_decrypt(block_state* self, const u8* in, u8* out)
{
__m128i m = _mm_loadu_si128((const __m128i*) in);
/* first 9 rounds */
m = _mm_xor_si128(m, self->dk[0]);
m = _mm_aesdec_si128(m, self->dk[1]);
m = _mm_aesdec_si128(m, self->dk[2]);
m = _mm_aesdec_si128(m, self->dk[3]);
m = _mm_aesdec_si128(m, self->dk[4]);
m = _mm_aesdec_si128(m, self->dk[5]);
m = _mm_aesdec_si128(m, self->dk[6]);
m = _mm_aesdec_si128(m, self->dk[7]);
m = _mm_aesdec_si128(m, self->dk[8]);
m = _mm_aesdec_si128(m, self->dk[9]);
if (self->rounds != 10) {
/* two additional rounds for AES-192/256 */
m = _mm_aesdec_si128(m, self->dk[10]);
m = _mm_aesdec_si128(m, self->dk[11]);
if (self->rounds == 14) {
/* another two additional rounds for AES-256 */
m = _mm_aesdec_si128(m, self->dk[12]);
m = _mm_aesdec_si128(m, self->dk[13]);
}
}
m = _mm_aesdeclast_si128(m, self->dk[self->rounds]);
_mm_storeu_si128((__m128i*) out, m);
}
#include "block_template.c"