From: Nikos Mavrogiannopoulos Date: Sat, 1 Oct 2011 18:04:56 +0000 (+0200) Subject: Added ability to hash and hmac with VIA padlock. X-Git-Tag: gnutls_3_0_4~47 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6731bedf011610c6b40512ba62feb68edb65067a;p=thirdparty%2Fgnutls.git Added ability to hash and hmac with VIA padlock. --- diff --git a/lib/accelerated/intel/Makefile.am b/lib/accelerated/intel/Makefile.am index cbb00e95c8..315c2775a1 100644 --- a/lib/accelerated/intel/Makefile.am +++ b/lib/accelerated/intel/Makefile.am @@ -34,7 +34,7 @@ EXTRA_DIST = README license.txt noinst_LTLIBRARIES = libintel.la -libintel_la_SOURCES = aes-x86.c aes-padlock.c aes-gcm-padlock.c aes-padlock.h aes-x86.h x86.h +libintel_la_SOURCES = sha-padlock.c aes-x86.c aes-padlock.c aes-gcm-padlock.c aes-padlock.h aes-x86.h x86.h if ASM_X86_64 AM_CPPFLAGS += -DASM_X86_64 diff --git a/lib/accelerated/intel/aes-padlock.c b/lib/accelerated/intel/aes-padlock.c index 881ab280ff..4e7b8cc2a0 100644 --- a/lib/accelerated/intel/aes-padlock.c +++ b/lib/accelerated/intel/aes-padlock.c @@ -37,200 +37,259 @@ #include static int -aes_cipher_init(gnutls_cipher_algorithm_t algorithm, void **_ctx, int enc) +aes_cipher_init (gnutls_cipher_algorithm_t algorithm, void **_ctx, int enc) { - /* we use key size to distinguish */ - if (algorithm != GNUTLS_CIPHER_AES_128_CBC - && algorithm != GNUTLS_CIPHER_AES_192_CBC - && algorithm != GNUTLS_CIPHER_AES_256_CBC) - return GNUTLS_E_INVALID_REQUEST; - - *_ctx = gnutls_calloc(1, sizeof(struct padlock_ctx)); - if (*_ctx == NULL) { - gnutls_assert(); - return GNUTLS_E_MEMORY_ERROR; + /* we use key size to distinguish */ + if (algorithm != GNUTLS_CIPHER_AES_128_CBC + && algorithm != GNUTLS_CIPHER_AES_192_CBC + && algorithm != GNUTLS_CIPHER_AES_256_CBC) + return GNUTLS_E_INVALID_REQUEST; + + *_ctx = gnutls_calloc (1, sizeof (struct padlock_ctx)); + if (*_ctx == NULL) + { + gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; } - ((struct padlock_ctx *) (*_ctx))->enc = enc; - return 0; + ((struct padlock_ctx *) (*_ctx))->enc = enc; + return 0; } -int padlock_aes_cipher_setkey(void *_ctx, const void *userkey, size_t keysize) +int +padlock_aes_cipher_setkey (void *_ctx, const void *userkey, size_t keysize) { - struct padlock_ctx *ctx = _ctx; - struct padlock_cipher_data *pce; + struct padlock_ctx *ctx = _ctx; + struct padlock_cipher_data *pce; #ifdef HAVE_LIBNETTLE - struct aes_ctx nc; + struct aes_ctx nc; #endif - memset(_ctx, 0, sizeof(struct padlock_cipher_data)); + memset (_ctx, 0, sizeof (struct padlock_cipher_data)); - pce = ALIGN16(&ctx->expanded_key); + pce = ALIGN16 (&ctx->expanded_key); - pce->cword.b.encdec = (ctx->enc == 0); + pce->cword.b.encdec = (ctx->enc == 0); - switch (keysize) { + switch (keysize) + { case 16: - pce->cword.b.ksize = 0; - pce->cword.b.rounds = 10; - memcpy(pce->ks.rd_key, userkey, 16); - pce->cword.b.keygen = 0; - break; + pce->cword.b.ksize = 0; + pce->cword.b.rounds = 10; + memcpy (pce->ks.rd_key, userkey, 16); + pce->cword.b.keygen = 0; + break; #ifdef HAVE_LIBNETTLE case 24: - pce->cword.b.ksize = 1; - pce->cword.b.rounds = 12; - goto common_24_32; + pce->cword.b.ksize = 1; + pce->cword.b.rounds = 12; + goto common_24_32; case 32: - pce->cword.b.ksize = 2; - pce->cword.b.rounds = 14; - common_24_32: - /* expand key using nettle */ - if (ctx->enc) - aes_set_encrypt_key(&nc, keysize, userkey); - else - aes_set_decrypt_key(&nc, keysize, userkey); - - memcpy(pce->ks.rd_key, nc.keys, sizeof(nc.keys)); - pce->ks.rounds = nc.nrounds; - - pce->cword.b.keygen = 1; - break; + pce->cword.b.ksize = 2; + pce->cword.b.rounds = 14; + common_24_32: + /* expand key using nettle */ + if (ctx->enc) + aes_set_encrypt_key (&nc, keysize, userkey); + else + aes_set_decrypt_key (&nc, keysize, userkey); + + memcpy (pce->ks.rd_key, nc.keys, sizeof (nc.keys)); + pce->ks.rounds = nc.nrounds; + + pce->cword.b.keygen = 1; + break; #endif default: - return gnutls_assert_val(GNUTLS_E_ENCRYPTION_FAILED); + return gnutls_assert_val (GNUTLS_E_ENCRYPTION_FAILED); } - padlock_reload_key(); + padlock_reload_key (); - return 0; + return 0; } -static int aes_setiv(void *_ctx, const void *iv, size_t iv_size) +static int +aes_setiv (void *_ctx, const void *iv, size_t iv_size) { - struct padlock_ctx *ctx = _ctx; - struct padlock_cipher_data *pce; + struct padlock_ctx *ctx = _ctx; + struct padlock_cipher_data *pce; - pce = ALIGN16(&ctx->expanded_key); + pce = ALIGN16 (&ctx->expanded_key); - memcpy(pce->iv, iv, 16); + memcpy (pce->iv, iv, 16); - return 0; + return 0; } static int -padlock_aes_cbc_encrypt(void *_ctx, const void *src, size_t src_size, - void *dst, size_t dst_size) +padlock_aes_cbc_encrypt (void *_ctx, const void *src, size_t src_size, + void *dst, size_t dst_size) { - struct padlock_ctx *ctx = _ctx; - struct padlock_cipher_data *pce; + struct padlock_ctx *ctx = _ctx; + struct padlock_cipher_data *pce; - pce = ALIGN16(&ctx->expanded_key); + pce = ALIGN16 (&ctx->expanded_key); - padlock_cbc_encrypt(dst, src, pce, src_size); + padlock_cbc_encrypt (dst, src, pce, src_size); - return 0; + return 0; } static int -padlock_aes_cbc_decrypt(void *_ctx, const void *src, size_t src_size, - void *dst, size_t dst_size) +padlock_aes_cbc_decrypt (void *_ctx, const void *src, size_t src_size, + void *dst, size_t dst_size) { - struct padlock_ctx *ctx = _ctx; - struct padlock_cipher_data *pcd; + struct padlock_ctx *ctx = _ctx; + struct padlock_cipher_data *pcd; - pcd = ALIGN16(&ctx->expanded_key); + pcd = ALIGN16 (&ctx->expanded_key); - padlock_cbc_encrypt(dst, src, pcd, src_size); + padlock_cbc_encrypt (dst, src, pcd, src_size); - return 0; + return 0; } -static void aes_deinit(void *_ctx) +static void +aes_deinit (void *_ctx) { - gnutls_free(_ctx); + gnutls_free (_ctx); } static const gnutls_crypto_cipher_st aes_padlock_struct = { - .init = aes_cipher_init, - .setkey = padlock_aes_cipher_setkey, - .setiv = aes_setiv, - .encrypt = padlock_aes_cbc_encrypt, - .decrypt = padlock_aes_cbc_decrypt, - .deinit = aes_deinit, + .init = aes_cipher_init, + .setkey = padlock_aes_cipher_setkey, + .setiv = aes_setiv, + .encrypt = padlock_aes_cbc_encrypt, + .decrypt = padlock_aes_cbc_decrypt, + .deinit = aes_deinit, }; -static int check_padlock(void) +static int +check_padlock (void) +{ + unsigned int edx = padlock_capability (); + + return ((edx & (0x3 << 6)) == (0x3 << 6)); +} + +static int +check_phe (void) { - unsigned int edx = padlock_capability(); + unsigned int edx = padlock_capability (); - return ((edx & (0x3 << 6)) == (0x3 << 6)); + return ((edx & (0x3 << 10)) == (0x3 << 10)); } -static unsigned check_via(void) +static unsigned +check_via (void) { - unsigned int a, b, c, d; - _gnutls_cpuid(0, &a, &b, &c, &d); + unsigned int a, b, c, d; + _gnutls_cpuid (0, &a, &b, &c, &d); - if ((memcmp(&b, "Cent", 4) == 0 && - memcmp(&d, "aurH", 4) == 0 && memcmp(&c, "auls", 4) == 0)) { - return 1; + if ((memcmp (&b, "Cent", 4) == 0 && + memcmp (&d, "aurH", 4) == 0 && memcmp (&c, "auls", 4) == 0)) + { + return 1; } - return 0; + return 0; } -void register_padlock_crypto(void) +void +register_padlock_crypto (void) { - int ret; - - /* Only enable the 32-bit padlock variant, until - * the 64-bit code is tested. - */ - if (check_via() == 0) - return; - - if (check_padlock()) { - _gnutls_debug_log("Padlock AES accelerator was detected\n"); - ret = - gnutls_crypto_single_cipher_register(GNUTLS_CIPHER_AES_128_CBC, - 80, &aes_padlock_struct); - if (ret < 0) { - gnutls_assert(); + int ret; + + /* Only enable the 32-bit padlock variant, until + * the 64-bit code is tested. + */ + if (check_via () == 0) + return; + + if (check_padlock ()) + { + _gnutls_debug_log ("Padlock AES accelerator was detected\n"); + ret = + gnutls_crypto_single_cipher_register + (GNUTLS_CIPHER_AES_128_CBC, 80, &aes_padlock_struct); + if (ret < 0) + { + gnutls_assert (); } - /* register GCM ciphers */ - ret = - gnutls_crypto_single_cipher_register(GNUTLS_CIPHER_AES_128_GCM, - 80, - &aes_gcm_padlock_struct); - if (ret < 0) { - gnutls_assert(); + /* register GCM ciphers */ + ret = + gnutls_crypto_single_cipher_register + (GNUTLS_CIPHER_AES_128_GCM, 80, &aes_gcm_padlock_struct); + if (ret < 0) + { + gnutls_assert (); } - } #ifdef HAVE_LIBNETTLE - ret = - gnutls_crypto_single_cipher_register(GNUTLS_CIPHER_AES_192_CBC, - 80, &aes_padlock_struct); - if (ret < 0) { - gnutls_assert(); - } + ret = + gnutls_crypto_single_cipher_register (GNUTLS_CIPHER_AES_192_CBC, + 80, &aes_padlock_struct); + if (ret < 0) + { + gnutls_assert (); + } - ret = - gnutls_crypto_single_cipher_register(GNUTLS_CIPHER_AES_256_CBC, - 80, &aes_padlock_struct); - if (ret < 0) { - gnutls_assert(); + ret = + gnutls_crypto_single_cipher_register (GNUTLS_CIPHER_AES_256_CBC, + 80, &aes_padlock_struct); + if (ret < 0) + { + gnutls_assert (); + } + + ret = + gnutls_crypto_single_cipher_register (GNUTLS_CIPHER_AES_256_GCM, + 80, + &aes_gcm_padlock_struct); + if (ret < 0) + { + gnutls_assert (); + } + +#endif } - ret = - gnutls_crypto_single_cipher_register(GNUTLS_CIPHER_AES_256_GCM, - 80, &aes_gcm_padlock_struct); - if (ret < 0) { - gnutls_assert(); + if (check_phe()) + { + ret = + gnutls_crypto_single_digest_register (GNUTLS_DIG_SHA1, + 80, &sha_padlock_struct); + if (ret < 0) + { + gnutls_assert (); + } + + ret = + gnutls_crypto_single_digest_register (GNUTLS_DIG_SHA256, + 80, &sha_padlock_struct); + if (ret < 0) + { + gnutls_assert (); + } + + ret = + gnutls_crypto_single_mac_register (GNUTLS_MAC_SHA1, + 80, &hmac_sha_padlock_struct); + if (ret < 0) + { + gnutls_assert (); + } + + ret = + gnutls_crypto_single_mac_register (GNUTLS_MAC_SHA256, + 80, &hmac_sha_padlock_struct); + if (ret < 0) + { + gnutls_assert (); + } } -#endif - return; + return; } diff --git a/lib/accelerated/intel/aes-padlock.h b/lib/accelerated/intel/aes-padlock.h index d15a6b9de5..c3798d6b0e 100644 --- a/lib/accelerated/intel/aes-padlock.h +++ b/lib/accelerated/intel/aes-padlock.h @@ -2,6 +2,7 @@ # define AES_PADLOCK_H #include +#include struct padlock_cipher_data { unsigned char iv[16]; /* Initialization vector */ @@ -27,6 +28,8 @@ struct padlock_ctx { }; extern const gnutls_crypto_cipher_st aes_gcm_padlock_struct; +extern const gnutls_crypto_mac_st hmac_sha_padlock_struct; +extern const gnutls_crypto_digest_st sha_padlock_struct; int padlock_aes_cipher_setkey(void *_ctx, const void *userkey, size_t keysize); diff --git a/lib/accelerated/intel/sha-padlock.c b/lib/accelerated/intel/sha-padlock.c new file mode 100644 index 0000000000..8c707fac38 --- /dev/null +++ b/lib/accelerated/intel/sha-padlock.c @@ -0,0 +1,294 @@ +/* + * Copyright (C) 2011 Free Software Foundation, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * The GnuTLS 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 3 of + * the License, or (at your option) any later version. + * + * This library 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 + * + */ + +#include +#include +#include +#include +#include + +/* This enables padlock's SHA capabilities for HMAC operations. + * Unfortunately due to padlock's inner workings only the final hash + * of the HMAC() is being hardware accelerated. The rest is plain + * software. + */ + +typedef void (*update_func) (void *, unsigned, const uint8_t *); +typedef void (*digest_func) (void *, unsigned, uint8_t *); +typedef void (*padlock_hash_func) (void* digest, const void* src, size_t len); + +#define SHA_BLOCK_SIZE 64 +#define MAX_SHA_DIGEST_SIZE 32 +#define IPAD 0x36 +#define OPAD 0x5c + +struct padlock_hmac_ctx +{ + gnutls_buffer_st buf; + + gnutls_mac_algorithm_t algo; + size_t length; + + unsigned char ipad[SHA_BLOCK_SIZE]; + unsigned char opad[SHA_BLOCK_SIZE]; +}; + +static int +wrap_padlock_hmac_init (gnutls_mac_algorithm_t algo, void **_ctx) +{ + struct padlock_hmac_ctx *ctx; + + if (algo != GNUTLS_MAC_SHA1 && algo != GNUTLS_MAC_SHA256) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + ctx = gnutls_calloc (1, sizeof (struct padlock_hmac_ctx)); + if (ctx == NULL) + { + gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + ctx->algo = algo; + _gnutls_buffer_init(&ctx->buf); + + *_ctx = ctx; + + return 0; +} + + +static int +wrap_padlock_hmac_setkey (void *_ctx, const void *key, size_t key_size) +{ + struct padlock_hmac_ctx *ctx = _ctx; + padlock_hash_func hash; + unsigned char hkey[MAX_SHA_DIGEST_SIZE]; + + if (key_size > SHA_BLOCK_SIZE) + { + if (ctx->algo == GNUTLS_MAC_SHA1) + hash = padlock_sha1_oneshot; + else + hash = padlock_sha256_oneshot; + + hash(hkey, key, key_size); + key = hkey; + key_size = _gnutls_hmac_get_algo_len(ctx->algo); + } + + memset (ctx->ipad, IPAD, SHA_BLOCK_SIZE); + memxor (ctx->ipad, key, key_size); + + _gnutls_buffer_append_data( &ctx->buf, ctx->ipad, SHA_BLOCK_SIZE); + + return GNUTLS_E_SUCCESS; +} + +static void +wrap_padlock_hmac_reset (void *_ctx) +{ + struct padlock_hmac_ctx *ctx = _ctx; + + _gnutls_buffer_reset(&ctx->buf); + _gnutls_buffer_append_data( &ctx->buf, ctx->ipad, SHA_BLOCK_SIZE); +} + +static int +wrap_padlock_hmac_update (void *_ctx, const void *text, size_t textsize) +{ + struct padlock_hmac_ctx *ctx = _ctx; + + _gnutls_buffer_append_data( &ctx->buf, text, textsize); + + return GNUTLS_E_SUCCESS; +} + +static void +wrap_padlock_hmac_deinit (void *_ctx) +{ + struct padlock_hmac_ctx *ctx = _ctx; + + _gnutls_buffer_clear(&ctx->buf); + gnutls_free (ctx); +} + +static int +wrap_padlock_hmac_output (void *_ctx, void *digest, size_t digestsize) +{ + struct padlock_hmac_ctx *ctx = _ctx; + unsigned char pad[SHA_BLOCK_SIZE + MAX_SHA_DIGEST_SIZE]; + padlock_hash_func hash; + + if (ctx->algo == GNUTLS_MAC_SHA1) + hash = padlock_sha1_oneshot; + else + hash = padlock_sha256_oneshot; + + if (digestsize < ctx->length) + { + gnutls_assert (); + return GNUTLS_E_SHORT_MEMORY_BUFFER; + } + + memcpy (pad, ctx->opad, SHA_BLOCK_SIZE); + hash(&pad[SHA_BLOCK_SIZE], ctx->buf.data, ctx->buf.length); + + hash(digest, pad, ctx->length + SHA_BLOCK_SIZE); + + return 0; +} + + +static int wrap_padlock_hmac_fast(gnutls_mac_algorithm_t algo, + const void *key, size_t key_size, const void* text, size_t text_size, + void* digest) +{ + unsigned char *pad; + unsigned char pad2[SHA_BLOCK_SIZE + MAX_SHA_DIGEST_SIZE]; + unsigned char hkey[MAX_SHA_DIGEST_SIZE]; + padlock_hash_func hash; + + if (algo == GNUTLS_MAC_SHA1) + hash = padlock_sha1_oneshot; + else + hash = padlock_sha256_oneshot; + + if (key_size > SHA_BLOCK_SIZE) + { + hash(hkey, key, key_size); + key = hkey; + key_size = _gnutls_hmac_get_algo_len(algo); + } + + pad = gnutls_malloc(text_size + SHA_BLOCK_SIZE); + if (pad == NULL) + return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + + memset (pad, IPAD, SHA_BLOCK_SIZE); + memxor (pad, key, key_size); + + memcpy (&pad[SHA_BLOCK_SIZE], text, text_size); + + hash(&pad2[SHA_BLOCK_SIZE], pad, text_size + SHA_BLOCK_SIZE); + + gnutls_free(pad); + + memset (pad2, OPAD, SHA_BLOCK_SIZE); + memxor (pad2, key, key_size); + + hash(digest, pad2, SHA1_DIGEST_SIZE + SHA_BLOCK_SIZE); + + return 0; +} + +const gnutls_crypto_mac_st hmac_sha_padlock_struct = { + .init = wrap_padlock_hmac_init, + .setkey = wrap_padlock_hmac_setkey, + .hash = wrap_padlock_hmac_update, + .reset = wrap_padlock_hmac_reset, + .output = wrap_padlock_hmac_output, + .deinit = wrap_padlock_hmac_deinit, + .fast = wrap_padlock_hmac_fast +}; + + +struct padlock_hash_ctx +{ + gnutls_buffer_st buf; + gnutls_digest_algorithm_t algo; + size_t length; /* output length */ +}; + +static int +wrap_padlock_hash_init (gnutls_digest_algorithm_t algo, void **_ctx) +{ + struct padlock_hash_ctx *ctx; + + if (algo != GNUTLS_DIG_SHA1 && algo != GNUTLS_DIG_SHA256) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + ctx = gnutls_calloc (1, sizeof (struct padlock_hash_ctx)); + if (ctx == NULL) + { + gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + ctx->algo = algo; + _gnutls_buffer_init(&ctx->buf); + + *_ctx = ctx; + + return 0; +} + +static int +wrap_padlock_hash_update (void *_ctx, const void *text, size_t textsize) +{ + struct padlock_hash_ctx *ctx = _ctx; + + _gnutls_buffer_append_data( &ctx->buf, text, textsize); + + return GNUTLS_E_SUCCESS; +} + +static void +wrap_padlock_hash_deinit (void *_ctx) +{ + struct padlock_hash_ctx *ctx = _ctx; + + _gnutls_buffer_clear(&ctx->buf); + gnutls_free (ctx); +} + +static int +wrap_padlock_hash_output (void *_ctx, void *digest, size_t digestsize) +{ + struct padlock_hash_ctx *ctx = _ctx; + + if (ctx->algo == GNUTLS_DIG_SHA1) + padlock_sha1_oneshot (digest, ctx->buf.data, ctx->buf.length); + else + padlock_sha256_oneshot (digest, ctx->buf.data, ctx->buf.length); + + return 0; +} + +static int wrap_padlock_hash_fast(gnutls_digest_algorithm_t algo, + const void* text, size_t text_size, + void* digest) +{ + if (algo == GNUTLS_DIG_SHA1) + padlock_sha1_oneshot (digest, text, text_size); + else + padlock_sha256_oneshot (digest, text, text_size); + + return 0; +} + +const gnutls_crypto_digest_st sha_padlock_struct = { + .init = wrap_padlock_hash_init, + .hash = wrap_padlock_hash_update, + .output = wrap_padlock_hash_output, + .deinit = wrap_padlock_hash_deinit, + .fast = wrap_padlock_hash_fast +}; diff --git a/lib/gnutls_str.h b/lib/gnutls_str.h index dbf299c0cb..3b6562e4c4 100644 --- a/lib/gnutls_str.h +++ b/lib/gnutls_str.h @@ -41,6 +41,12 @@ typedef struct void _gnutls_buffer_init (gnutls_buffer_st *); void _gnutls_buffer_clear (gnutls_buffer_st *); +inline static void _gnutls_buffer_reset (gnutls_buffer_st * buf) +{ + buf->data = buf->allocd; + buf->length = 0; +} + int _gnutls_buffer_resize (gnutls_buffer_st *, size_t new_size); int _gnutls_buffer_append_str (gnutls_buffer_st *, const char *str);