/* * Copyright (C) 2008 Thomas Kallenberg * Copyright (C) 2008 Martin Willi * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. See . * * This program 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. */ #include "padlock_aes_crypter.h" #include #define AES_BLOCK_SIZE 16 #define PADLOCK_ALIGN __attribute__ ((__aligned__(16))) typedef struct private_padlock_aes_crypter_t private_padlock_aes_crypter_t; /** * Private data of padlock_aes_crypter_t */ struct private_padlock_aes_crypter_t { /** * Public part of this class. */ padlock_aes_crypter_t public; /* * the key */ chunk_t key; }; /** * Control word structure to pass to crypt operations */ typedef struct { u_int __attribute__ ((__packed__)) rounds:4, algo:3, keygen:1, interm:1, encdec:1, ksize:2; /* microcode needs additional bytes for calculation */ u_char buf[124]; } cword; /** * Invoke the actual de/encryption */ static void padlock_crypt(void *key, void *ctrl, void *src, void *dst, int count, void *iv) { asm volatile( "pushl %%eax\n pushl %%ebx\n pushl %%ecx\n" "pushl %%edx\n pushl %%esi\n pushl %%edi\n" "pushfl\n popfl\n" "movl %0, %%eax\n" "movl %1, %%ebx\n" "movl %2, %%ecx\n" "movl %3, %%edx\n" "movl %4, %%esi\n" "movl %5, %%edi\n" "rep\n" ".byte 0x0f, 0xa7, 0xd0\n" "popl %%edi\n popl %%esi\n popl %%edx\n" "popl %%ecx\n popl %%ebx\n popl %%eax\n" : : "m"(iv),"m"(key), "m"(count), "m"(ctrl), "m"(src), "m"(dst) : "eax", "ecx", "edx", "esi", "edi"); } /** * Do encryption/decryption operation using Padlock control word */ static void crypt(private_padlock_aes_crypter_t *this, char *iv, chunk_t src, chunk_t *dst, bool enc) { cword cword PADLOCK_ALIGN; u_char key_aligned[256] PADLOCK_ALIGN; u_char iv_aligned[16] PADLOCK_ALIGN; memset(&cword, 0, sizeof(cword)); /* set encryption/decryption flag */ cword.encdec = enc; /* calculate rounds and key size */ cword.rounds = 10 + (this->key.len - 16) / 4; cword.ksize = (this->key.len - 16) / 8; /* enable autoalign */ cword.algo |= 2; /* move data to aligned buffers */ memcpy(iv_aligned, iv, sizeof(iv_aligned)); memcpy(key_aligned, this->key.ptr, this->key.len); *dst = chunk_alloc(src.len); padlock_crypt(key_aligned, &cword, src.ptr, dst->ptr, src.len / AES_BLOCK_SIZE, iv_aligned); memwipe(key_aligned, sizeof(key_aligned)); } METHOD(crypter_t, decrypt, bool, private_padlock_aes_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *dst) { crypt(this, iv.ptr, data, dst, TRUE); return TRUE; } METHOD(crypter_t, encrypt, bool, private_padlock_aes_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *dst) { crypt(this, iv.ptr, data, dst, FALSE); return TRUE; } METHOD(crypter_t, get_block_size, size_t, private_padlock_aes_crypter_t *this) { return AES_BLOCK_SIZE; } METHOD(crypter_t, get_iv_size, size_t, private_padlock_aes_crypter_t *this) { return AES_BLOCK_SIZE; } METHOD(crypter_t, get_key_size, size_t, private_padlock_aes_crypter_t *this) { return this->key.len; } METHOD(crypter_t, set_key, bool, private_padlock_aes_crypter_t *this, chunk_t key) { memcpy(this->key.ptr, key.ptr, min(key.len, this->key.len)); return TRUE; } METHOD(crypter_t, destroy, void, private_padlock_aes_crypter_t *this) { chunk_clear(&this->key); free(this); } /* * Described in header */ padlock_aes_crypter_t *padlock_aes_crypter_create(encryption_algorithm_t algo, size_t key_size) { private_padlock_aes_crypter_t *this; if (algo != ENCR_AES_CBC) { return NULL; } switch (key_size) { case 0: key_size = 16; /* FALL */ case 16: /* AES 128 */ break; case 24: /* AES-192 */ case 32: /* AES-256 */ /* These need an expanded key, currently not supported, FALL */ default: return NULL; } INIT(this, .public = { .crypter = { .encrypt = _encrypt, .decrypt = _decrypt, .get_block_size = _get_block_size, .get_iv_size = _get_iv_size, .get_key_size = _get_key_size, .set_key = _set_key, .destroy = _destroy, }, }, .key = chunk_alloc(key_size), ); return &this->public; }