From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:35577) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YvOAN-0000s3-Rv for qemu-devel@nongnu.org; Thu, 21 May 2015 06:57:35 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YvOAH-0007iq-3w for qemu-devel@nongnu.org; Thu, 21 May 2015 06:57:31 -0400 Received: from mx1.redhat.com ([209.132.183.28]:48306) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YvOAG-0007gy-RR for qemu-devel@nongnu.org; Thu, 21 May 2015 06:57:25 -0400 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) by mx1.redhat.com (Postfix) with ESMTPS id 6B9608EFDB for ; Thu, 21 May 2015 10:57:24 +0000 (UTC) From: "Daniel P. Berrange" Date: Thu, 21 May 2015 11:56:53 +0100 Message-Id: <1432205817-16414-7-git-send-email-berrange@redhat.com> In-Reply-To: <1432205817-16414-1-git-send-email-berrange@redhat.com> References: <1432205817-16414-1-git-send-email-berrange@redhat.com> Subject: [Qemu-devel] [PATCH 06/10] crypto: add a nettle cipher implementation List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Kevin Wolf , Paolo Bonzini , Gerd Hoffmann If we are linking to gnutls already and gnutls is built against nettle, then we should use nettle as a cipher backend in preference to our built-in backend. This will be used when linking against some GNUTLS 2.x versions and all GNUTLS 3.x versions. Signed-off-by: Daniel P. Berrange --- configure | 35 +++++++- crypto/cipher-nettle.c | 226 +++++++++++++++++++++++++++++++++++++++++++++++++ crypto/cipher.c | 4 + 3 files changed, 262 insertions(+), 3 deletions(-) create mode 100644 crypto/cipher-nettle.c diff --git a/configure b/configure index 6629346..a48aa90 100755 --- a/configure +++ b/configure @@ -2163,6 +2163,7 @@ fi # GNUTLS probe gnutls_gcrypt=no +gnutls_nettle=no if test "$gnutls" != "no"; then if $pkg_config --exists "gnutls"; then gnutls_cflags=`$pkg_config --cflags gnutls` @@ -2181,14 +2182,25 @@ if test "$gnutls" != "no"; then if $pkg_config --exists 'gnutls >= 3.0'; then gnutls_gcrypt=no + gnutls_nettle=yes elif $pkg_config --exists 'gnutls >= 2.12'; then case `$pkg_config --libs --static gnutls` in - *gcrypt*) gnutls_gcrypt=yes ;; - *nettle*) gnutls_gcrypt=no ;; - *) gnutls_gcrypt=yes ;; + *gcrypt*) + gnutls_gcrypt=yes + gnutls_nettle=no + ;; + *nettle*) + gnutls_gcrypt=no + gnutls_nettle=yes + ;; + *) + gnutls_gcrypt=yes + gnutls_nettle=no + ;; esac else gnutls_gcrypt=yes + gnutls_nettle=no fi elif test "$gnutls" = "yes"; then feature_not_found "gnutls" "Install gnutls devel" @@ -2213,6 +2225,19 @@ if test "$gnutls_gcrypt" != "no"; then fi +if test "$gnutls_nettle" != "no"; then + if $pkg_config --exists "nettle"; then + nettle_cflags=`$pkg_config --cflags nettle` + nettle_libs=`$pkg_config --libs nettle` + libs_softmmu="$nettle_libs $libs_softmmu" + libs_tools="$nettle_libs $libs_tools" + QEMU_CFLAGS="$QEMU_CFLAGS $nettle_cflags" + else + feature_not_found "nettle" "Install nettle devel" + fi +fi + + ########################################## # VTE probe @@ -4459,6 +4484,7 @@ echo "GTK support $gtk" echo "GNUTLS support $gnutls" echo "GNUTLS hash $gnutls_hash" echo "GNUTLS gcrypt $gnutls_gcrypt" +echo "GNUTLS nettle $gnutls_nettle" echo "VTE support $vte" echo "curses support $curses" echo "curl support $curl" @@ -4820,6 +4846,9 @@ fi if test "$gnutls_gcrypt" = "yes" ; then echo "CONFIG_GNUTLS_GCRYPT=y" >> $config_host_mak fi +if test "$gnutls_nettle" = "yes" ; then + echo "CONFIG_GNUTLS_NETTLE=y" >> $config_host_mak +fi if test "$vte" = "yes" ; then echo "CONFIG_VTE=y" >> $config_host_mak echo "VTE_CFLAGS=$vte_cflags" >> $config_host_mak diff --git a/crypto/cipher-nettle.c b/crypto/cipher-nettle.c new file mode 100644 index 0000000..a455319 --- /dev/null +++ b/crypto/cipher-nettle.c @@ -0,0 +1,226 @@ +/* + * QEMU Crypto cipher nettle algorithms + * + * Copyright (c) 2015 Red Hat, Inc. + * + * This library 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 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 library; if not, see . + * + */ + +#include "crypto/cipher.h" + +#include +#include +#include +#include +#include + +typedef struct QCryptoCipherNettle QCryptoCipherNettle; +struct QCryptoCipherNettle { + void *ctx_encrypt; + void *ctx_decrypt; + nettle_crypt_func *alg_encrypt; + nettle_crypt_func *alg_decrypt; + uint8_t *iv; + size_t niv; +}; + +static uint8_t *qcrypto_cipher_munge_des_rfb_key(const uint8_t *key, + size_t nkey) +{ + uint8_t *ret = g_new0(uint8_t, nkey); + size_t i; + for (i = 0; i < nkey; i++) { + uint8_t r = key[i]; + r = (r & 0xf0)>>4 | (r & 0x0f)<<4; + r = (r & 0xcc)>>2 | (r & 0x33)<<2; + r = (r & 0xaa)>>1 | (r & 0x55)<<1; + ret[i] = r; + } + return ret; +} + + +bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg) +{ + if (alg == QCRYPTO_CIPHER_ALG_DES_RFB || + alg == QCRYPTO_CIPHER_ALG_AES) { + return true; + } + return false; +} + + +QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg, + QCryptoCipherMode mode, + const uint8_t *key, size_t nkey, + Error **errp) +{ + QCryptoCipher *cipher; + QCryptoCipherNettle *ctx; + uint8_t *rfbkey; + + switch (mode) { + case QCRYPTO_CIPHER_MODE_ECB: + case QCRYPTO_CIPHER_MODE_CBC: + break; + default: + error_setg(errp, _("Unsupported cipher mode %d"), mode); + return NULL; + } + + cipher = g_new0(QCryptoCipher, 1); + cipher->alg = alg; + cipher->mode = mode; + + ctx = g_new0(QCryptoCipherNettle, 1); + + switch (alg) { + case QCRYPTO_CIPHER_ALG_DES_RFB: + if (nkey != DES_KEY_SIZE) { + error_setg(errp, _("Expected key size %d got %zu"), + DES_KEY_SIZE, nkey); + goto error; + } + ctx->ctx_encrypt = g_new0(struct des_ctx, 1); + ctx->ctx_decrypt = NULL; /* 1 ctx can do both */ + rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey); + des_set_key(ctx->ctx_encrypt, rfbkey); + g_free(rfbkey); + + ctx->alg_encrypt = (nettle_crypt_func *)des_encrypt; + ctx->alg_decrypt = (nettle_crypt_func *)des_decrypt; + + ctx->niv = DES_BLOCK_SIZE; + break; + + case QCRYPTO_CIPHER_ALG_AES: + if (nkey < AES_MIN_KEY_SIZE || + nkey > AES_MAX_KEY_SIZE) { + error_setg(errp, _("Expected key size %d-%d got %zu"), + AES_MIN_KEY_SIZE, AES_MAX_KEY_SIZE, nkey); + goto error; + } + ctx->ctx_encrypt = g_new0(struct aes_ctx, 1); + ctx->ctx_decrypt = g_new0(struct aes_ctx, 1); + + aes_set_encrypt_key(ctx->ctx_encrypt, nkey, key); + aes_set_decrypt_key(ctx->ctx_decrypt, nkey, key); + + ctx->alg_encrypt = (nettle_crypt_func *)aes_encrypt; + ctx->alg_decrypt = (nettle_crypt_func *)aes_decrypt; + + ctx->niv = AES_BLOCK_SIZE; + break; + default: + error_setg(errp, _("Unsupported cipher algorithm %d"), alg); + goto error; + } + + ctx->iv = g_new0(uint8_t, ctx->niv); + cipher->opaque = ctx; + + return cipher; + + error: + g_free(cipher); + g_free(ctx); + return NULL; +} + + +void qcrypto_cipher_free(QCryptoCipher *cipher) +{ + QCryptoCipherNettle *ctx; + + if (!cipher) { + return; + } + + ctx = cipher->opaque; + g_free(ctx->iv); + g_free(ctx->ctx_encrypt); + g_free(ctx->ctx_decrypt); + g_free(ctx); + g_free(cipher); +} + + +int qcrypto_cipher_encrypt(QCryptoCipher *cipher, + const void *in, + void *out, + size_t len, + Error **errp) +{ + QCryptoCipherNettle *ctx = cipher->opaque; + + switch (cipher->mode) { + case QCRYPTO_CIPHER_MODE_ECB: + ctx->alg_encrypt(ctx->ctx_encrypt, len, out, in); + break; + + case QCRYPTO_CIPHER_MODE_CBC: + cbc_encrypt(ctx->ctx_encrypt, ctx->alg_encrypt, + ctx->niv, ctx->iv, + len, out, in); + break; + default: + error_setg(errp, _("Unsupported cipher algorithm %d"), + cipher->alg); + return -1; + } + return 0; +} + + +int qcrypto_cipher_decrypt(QCryptoCipher *cipher, + const void *in, + void *out, + size_t len, + Error **errp) +{ + QCryptoCipherNettle *ctx = cipher->opaque; + + switch (cipher->mode) { + case QCRYPTO_CIPHER_MODE_ECB: + ctx->alg_decrypt(ctx->ctx_decrypt ? ctx->ctx_decrypt : ctx->ctx_encrypt, + len, out, in); + break; + + case QCRYPTO_CIPHER_MODE_CBC: + cbc_decrypt(ctx->ctx_decrypt ? ctx->ctx_decrypt : ctx->ctx_encrypt, + ctx->alg_decrypt, ctx->niv, ctx->iv, + len, out, in); + break; + default: + error_setg(errp, _("Unsupported cipher algorithm %d"), + cipher->alg); + return -1; + } + return 0; +} + +int qcrypto_cipher_setiv(QCryptoCipher *cipher, + const uint8_t *iv, size_t niv, + Error **errp) +{ + QCryptoCipherNettle *ctx = cipher->opaque; + if (niv != ctx->niv) { + error_setg(errp, _("Expected IV size %zu not %zu"), + ctx->niv, niv); + return -1; + } + memcpy(ctx->iv, iv, niv); + return 0; +} diff --git a/crypto/cipher.c b/crypto/cipher.c index dc140fb..3299a7a 100644 --- a/crypto/cipher.c +++ b/crypto/cipher.c @@ -23,5 +23,9 @@ #ifdef CONFIG_GNUTLS_GCRYPT #include "crypto/cipher-gcrypt.c" #else +#ifdef CONFIG_GNUTLS_NETTLE +#include "crypto/cipher-nettle.c" +#else #include "crypto/cipher-builtin.c" #endif +#endif -- 2.1.0