From: Richard Henderson Date: Fri, 28 Aug 2020 17:05:09 +0000 (-0700) Subject: crypto: Rename cipher include files to .c.inc X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=6d92bdf44375f9819539927b7f234ba89ce9365e;p=qemu.git crypto: Rename cipher include files to .c.inc QEMU standard procedure for included c files is to use *.c.inc. E.g. there are a different set of checks that are applied. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson Signed-off-by: Daniel P. Berrangé --- diff --git a/crypto/cipher-builtin.c b/crypto/cipher-builtin.c deleted file mode 100644 index 6eafd39da0..0000000000 --- a/crypto/cipher-builtin.c +++ /dev/null @@ -1,532 +0,0 @@ -/* - * QEMU Crypto cipher built-in 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.1 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 "qemu/osdep.h" -#include "crypto/aes.h" -#include "crypto/desrfb.h" -#include "crypto/xts.h" -#include "cipherpriv.h" - -typedef struct QCryptoCipherBuiltinAESContext QCryptoCipherBuiltinAESContext; -struct QCryptoCipherBuiltinAESContext { - AES_KEY enc; - AES_KEY dec; -}; -typedef struct QCryptoCipherBuiltinAES QCryptoCipherBuiltinAES; -struct QCryptoCipherBuiltinAES { - QCryptoCipherBuiltinAESContext key; - QCryptoCipherBuiltinAESContext key_tweak; - uint8_t iv[AES_BLOCK_SIZE]; -}; -typedef struct QCryptoCipherBuiltinDESRFB QCryptoCipherBuiltinDESRFB; -struct QCryptoCipherBuiltinDESRFB { - uint8_t *key; - size_t nkey; -}; - -typedef struct QCryptoCipherBuiltin QCryptoCipherBuiltin; -struct QCryptoCipherBuiltin { - union { - QCryptoCipherBuiltinAES aes; - QCryptoCipherBuiltinDESRFB desrfb; - } state; - size_t blocksize; - void (*free)(QCryptoCipher *cipher); - int (*setiv)(QCryptoCipher *cipher, - const uint8_t *iv, size_t niv, - Error **errp); - int (*encrypt)(QCryptoCipher *cipher, - const void *in, - void *out, - size_t len, - Error **errp); - int (*decrypt)(QCryptoCipher *cipher, - const void *in, - void *out, - size_t len, - Error **errp); -}; - - -static void qcrypto_cipher_free_aes(QCryptoCipher *cipher) -{ - QCryptoCipherBuiltin *ctxt = cipher->opaque; - - g_free(ctxt); - cipher->opaque = NULL; -} - - -static void qcrypto_cipher_aes_ecb_encrypt(const AES_KEY *key, - const void *in, - void *out, - size_t len) -{ - const uint8_t *inptr = in; - uint8_t *outptr = out; - while (len) { - if (len > AES_BLOCK_SIZE) { - AES_encrypt(inptr, outptr, key); - inptr += AES_BLOCK_SIZE; - outptr += AES_BLOCK_SIZE; - len -= AES_BLOCK_SIZE; - } else { - uint8_t tmp1[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE]; - memcpy(tmp1, inptr, len); - /* Fill with 0 to avoid valgrind uninitialized reads */ - memset(tmp1 + len, 0, sizeof(tmp1) - len); - AES_encrypt(tmp1, tmp2, key); - memcpy(outptr, tmp2, len); - len = 0; - } - } -} - - -static void qcrypto_cipher_aes_ecb_decrypt(const AES_KEY *key, - const void *in, - void *out, - size_t len) -{ - const uint8_t *inptr = in; - uint8_t *outptr = out; - while (len) { - if (len > AES_BLOCK_SIZE) { - AES_decrypt(inptr, outptr, key); - inptr += AES_BLOCK_SIZE; - outptr += AES_BLOCK_SIZE; - len -= AES_BLOCK_SIZE; - } else { - uint8_t tmp1[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE]; - memcpy(tmp1, inptr, len); - /* Fill with 0 to avoid valgrind uninitialized reads */ - memset(tmp1 + len, 0, sizeof(tmp1) - len); - AES_decrypt(tmp1, tmp2, key); - memcpy(outptr, tmp2, len); - len = 0; - } - } -} - - -static void qcrypto_cipher_aes_xts_encrypt(const void *ctx, - size_t length, - uint8_t *dst, - const uint8_t *src) -{ - const QCryptoCipherBuiltinAESContext *aesctx = ctx; - - qcrypto_cipher_aes_ecb_encrypt(&aesctx->enc, src, dst, length); -} - - -static void qcrypto_cipher_aes_xts_decrypt(const void *ctx, - size_t length, - uint8_t *dst, - const uint8_t *src) -{ - const QCryptoCipherBuiltinAESContext *aesctx = ctx; - - qcrypto_cipher_aes_ecb_decrypt(&aesctx->dec, src, dst, length); -} - - -static int qcrypto_cipher_encrypt_aes(QCryptoCipher *cipher, - const void *in, - void *out, - size_t len, - Error **errp) -{ - QCryptoCipherBuiltin *ctxt = cipher->opaque; - - switch (cipher->mode) { - case QCRYPTO_CIPHER_MODE_ECB: - qcrypto_cipher_aes_ecb_encrypt(&ctxt->state.aes.key.enc, - in, out, len); - break; - case QCRYPTO_CIPHER_MODE_CBC: - AES_cbc_encrypt(in, out, len, - &ctxt->state.aes.key.enc, - ctxt->state.aes.iv, 1); - break; - case QCRYPTO_CIPHER_MODE_XTS: - xts_encrypt(&ctxt->state.aes.key, - &ctxt->state.aes.key_tweak, - qcrypto_cipher_aes_xts_encrypt, - qcrypto_cipher_aes_xts_decrypt, - ctxt->state.aes.iv, - len, out, in); - break; - default: - g_assert_not_reached(); - } - - return 0; -} - - -static int qcrypto_cipher_decrypt_aes(QCryptoCipher *cipher, - const void *in, - void *out, - size_t len, - Error **errp) -{ - QCryptoCipherBuiltin *ctxt = cipher->opaque; - - switch (cipher->mode) { - case QCRYPTO_CIPHER_MODE_ECB: - qcrypto_cipher_aes_ecb_decrypt(&ctxt->state.aes.key.dec, - in, out, len); - break; - case QCRYPTO_CIPHER_MODE_CBC: - AES_cbc_encrypt(in, out, len, - &ctxt->state.aes.key.dec, - ctxt->state.aes.iv, 0); - break; - case QCRYPTO_CIPHER_MODE_XTS: - xts_decrypt(&ctxt->state.aes.key, - &ctxt->state.aes.key_tweak, - qcrypto_cipher_aes_xts_encrypt, - qcrypto_cipher_aes_xts_decrypt, - ctxt->state.aes.iv, - len, out, in); - break; - default: - g_assert_not_reached(); - } - - return 0; -} - -static int qcrypto_cipher_setiv_aes(QCryptoCipher *cipher, - const uint8_t *iv, size_t niv, - Error **errp) -{ - QCryptoCipherBuiltin *ctxt = cipher->opaque; - if (niv != AES_BLOCK_SIZE) { - error_setg(errp, "IV must be %d bytes not %zu", - AES_BLOCK_SIZE, niv); - return -1; - } - - memcpy(ctxt->state.aes.iv, iv, AES_BLOCK_SIZE); - - return 0; -} - - - - -static QCryptoCipherBuiltin * -qcrypto_cipher_init_aes(QCryptoCipherMode mode, - const uint8_t *key, size_t nkey, - Error **errp) -{ - QCryptoCipherBuiltin *ctxt; - - if (mode != QCRYPTO_CIPHER_MODE_CBC && - mode != QCRYPTO_CIPHER_MODE_ECB && - mode != QCRYPTO_CIPHER_MODE_XTS) { - error_setg(errp, "Unsupported cipher mode %s", - QCryptoCipherMode_str(mode)); - return NULL; - } - - ctxt = g_new0(QCryptoCipherBuiltin, 1); - - if (mode == QCRYPTO_CIPHER_MODE_XTS) { - if (AES_set_encrypt_key(key, nkey * 4, &ctxt->state.aes.key.enc) != 0) { - error_setg(errp, "Failed to set encryption key"); - goto error; - } - - if (AES_set_decrypt_key(key, nkey * 4, &ctxt->state.aes.key.dec) != 0) { - error_setg(errp, "Failed to set decryption key"); - goto error; - } - - if (AES_set_encrypt_key(key + (nkey / 2), nkey * 4, - &ctxt->state.aes.key_tweak.enc) != 0) { - error_setg(errp, "Failed to set encryption key"); - goto error; - } - - if (AES_set_decrypt_key(key + (nkey / 2), nkey * 4, - &ctxt->state.aes.key_tweak.dec) != 0) { - error_setg(errp, "Failed to set decryption key"); - goto error; - } - } else { - if (AES_set_encrypt_key(key, nkey * 8, &ctxt->state.aes.key.enc) != 0) { - error_setg(errp, "Failed to set encryption key"); - goto error; - } - - if (AES_set_decrypt_key(key, nkey * 8, &ctxt->state.aes.key.dec) != 0) { - error_setg(errp, "Failed to set decryption key"); - goto error; - } - } - - ctxt->blocksize = AES_BLOCK_SIZE; - ctxt->free = qcrypto_cipher_free_aes; - ctxt->setiv = qcrypto_cipher_setiv_aes; - ctxt->encrypt = qcrypto_cipher_encrypt_aes; - ctxt->decrypt = qcrypto_cipher_decrypt_aes; - - return ctxt; - - error: - g_free(ctxt); - return NULL; -} - - -static void qcrypto_cipher_free_des_rfb(QCryptoCipher *cipher) -{ - QCryptoCipherBuiltin *ctxt = cipher->opaque; - - g_free(ctxt->state.desrfb.key); - g_free(ctxt); - cipher->opaque = NULL; -} - - -static int qcrypto_cipher_encrypt_des_rfb(QCryptoCipher *cipher, - const void *in, - void *out, - size_t len, - Error **errp) -{ - QCryptoCipherBuiltin *ctxt = cipher->opaque; - size_t i; - - if (len % 8) { - error_setg(errp, "Buffer size must be multiple of 8 not %zu", - len); - return -1; - } - - deskey(ctxt->state.desrfb.key, EN0); - - for (i = 0; i < len; i += 8) { - des((void *)in + i, out + i); - } - - return 0; -} - - -static int qcrypto_cipher_decrypt_des_rfb(QCryptoCipher *cipher, - const void *in, - void *out, - size_t len, - Error **errp) -{ - QCryptoCipherBuiltin *ctxt = cipher->opaque; - size_t i; - - if (len % 8) { - error_setg(errp, "Buffer size must be multiple of 8 not %zu", - len); - return -1; - } - - deskey(ctxt->state.desrfb.key, DE1); - - for (i = 0; i < len; i += 8) { - des((void *)in + i, out + i); - } - - return 0; -} - - -static int qcrypto_cipher_setiv_des_rfb(QCryptoCipher *cipher, - const uint8_t *iv, size_t niv, - Error **errp) -{ - error_setg(errp, "Setting IV is not supported"); - return -1; -} - - -static QCryptoCipherBuiltin * -qcrypto_cipher_init_des_rfb(QCryptoCipherMode mode, - const uint8_t *key, size_t nkey, - Error **errp) -{ - QCryptoCipherBuiltin *ctxt; - - if (mode != QCRYPTO_CIPHER_MODE_ECB) { - error_setg(errp, "Unsupported cipher mode %s", - QCryptoCipherMode_str(mode)); - return NULL; - } - - ctxt = g_new0(QCryptoCipherBuiltin, 1); - - ctxt->state.desrfb.key = g_new0(uint8_t, nkey); - memcpy(ctxt->state.desrfb.key, key, nkey); - ctxt->state.desrfb.nkey = nkey; - - ctxt->blocksize = 8; - ctxt->free = qcrypto_cipher_free_des_rfb; - ctxt->setiv = qcrypto_cipher_setiv_des_rfb; - ctxt->encrypt = qcrypto_cipher_encrypt_des_rfb; - ctxt->decrypt = qcrypto_cipher_decrypt_des_rfb; - - return ctxt; -} - - -bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg, - QCryptoCipherMode mode) -{ - switch (alg) { - case QCRYPTO_CIPHER_ALG_DES_RFB: - case QCRYPTO_CIPHER_ALG_AES_128: - case QCRYPTO_CIPHER_ALG_AES_192: - case QCRYPTO_CIPHER_ALG_AES_256: - break; - default: - return false; - } - - switch (mode) { - case QCRYPTO_CIPHER_MODE_ECB: - case QCRYPTO_CIPHER_MODE_CBC: - case QCRYPTO_CIPHER_MODE_XTS: - return true; - case QCRYPTO_CIPHER_MODE_CTR: - return false; - default: - return false; - } -} - - -static QCryptoCipherBuiltin *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg, - QCryptoCipherMode mode, - const uint8_t *key, - size_t nkey, - Error **errp) -{ - QCryptoCipherBuiltin *ctxt; - - switch (mode) { - case QCRYPTO_CIPHER_MODE_ECB: - case QCRYPTO_CIPHER_MODE_CBC: - case QCRYPTO_CIPHER_MODE_XTS: - break; - default: - error_setg(errp, "Unsupported cipher mode %s", - QCryptoCipherMode_str(mode)); - return NULL; - } - - if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) { - return NULL; - } - - switch (alg) { - case QCRYPTO_CIPHER_ALG_DES_RFB: - ctxt = qcrypto_cipher_init_des_rfb(mode, key, nkey, errp); - break; - case QCRYPTO_CIPHER_ALG_AES_128: - case QCRYPTO_CIPHER_ALG_AES_192: - case QCRYPTO_CIPHER_ALG_AES_256: - ctxt = qcrypto_cipher_init_aes(mode, key, nkey, errp); - break; - default: - error_setg(errp, - "Unsupported cipher algorithm %s", - QCryptoCipherAlgorithm_str(alg)); - return NULL; - } - - return ctxt; -} - -static void -qcrypto_builtin_cipher_ctx_free(QCryptoCipher *cipher) -{ - QCryptoCipherBuiltin *ctxt; - - ctxt = cipher->opaque; - ctxt->free(cipher); -} - - -static int -qcrypto_builtin_cipher_encrypt(QCryptoCipher *cipher, - const void *in, - void *out, - size_t len, - Error **errp) -{ - QCryptoCipherBuiltin *ctxt = cipher->opaque; - - if (len & (ctxt->blocksize - 1)) { - error_setg(errp, "Length %zu must be a multiple of block size %zu", - len, ctxt->blocksize); - return -1; - } - - return ctxt->encrypt(cipher, in, out, len, errp); -} - - -static int -qcrypto_builtin_cipher_decrypt(QCryptoCipher *cipher, - const void *in, - void *out, - size_t len, - Error **errp) -{ - QCryptoCipherBuiltin *ctxt = cipher->opaque; - - if (len & (ctxt->blocksize - 1)) { - error_setg(errp, "Length %zu must be a multiple of block size %zu", - len, ctxt->blocksize); - return -1; - } - - return ctxt->decrypt(cipher, in, out, len, errp); -} - - -static int -qcrypto_builtin_cipher_setiv(QCryptoCipher *cipher, - const uint8_t *iv, size_t niv, - Error **errp) -{ - QCryptoCipherBuiltin *ctxt = cipher->opaque; - - return ctxt->setiv(cipher, iv, niv, errp); -} - - -static struct QCryptoCipherDriver qcrypto_cipher_lib_driver = { - .cipher_encrypt = qcrypto_builtin_cipher_encrypt, - .cipher_decrypt = qcrypto_builtin_cipher_decrypt, - .cipher_setiv = qcrypto_builtin_cipher_setiv, - .cipher_free = qcrypto_builtin_cipher_ctx_free, -}; diff --git a/crypto/cipher-builtin.c.inc b/crypto/cipher-builtin.c.inc new file mode 100644 index 0000000000..6eafd39da0 --- /dev/null +++ b/crypto/cipher-builtin.c.inc @@ -0,0 +1,532 @@ +/* + * QEMU Crypto cipher built-in 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.1 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 "qemu/osdep.h" +#include "crypto/aes.h" +#include "crypto/desrfb.h" +#include "crypto/xts.h" +#include "cipherpriv.h" + +typedef struct QCryptoCipherBuiltinAESContext QCryptoCipherBuiltinAESContext; +struct QCryptoCipherBuiltinAESContext { + AES_KEY enc; + AES_KEY dec; +}; +typedef struct QCryptoCipherBuiltinAES QCryptoCipherBuiltinAES; +struct QCryptoCipherBuiltinAES { + QCryptoCipherBuiltinAESContext key; + QCryptoCipherBuiltinAESContext key_tweak; + uint8_t iv[AES_BLOCK_SIZE]; +}; +typedef struct QCryptoCipherBuiltinDESRFB QCryptoCipherBuiltinDESRFB; +struct QCryptoCipherBuiltinDESRFB { + uint8_t *key; + size_t nkey; +}; + +typedef struct QCryptoCipherBuiltin QCryptoCipherBuiltin; +struct QCryptoCipherBuiltin { + union { + QCryptoCipherBuiltinAES aes; + QCryptoCipherBuiltinDESRFB desrfb; + } state; + size_t blocksize; + void (*free)(QCryptoCipher *cipher); + int (*setiv)(QCryptoCipher *cipher, + const uint8_t *iv, size_t niv, + Error **errp); + int (*encrypt)(QCryptoCipher *cipher, + const void *in, + void *out, + size_t len, + Error **errp); + int (*decrypt)(QCryptoCipher *cipher, + const void *in, + void *out, + size_t len, + Error **errp); +}; + + +static void qcrypto_cipher_free_aes(QCryptoCipher *cipher) +{ + QCryptoCipherBuiltin *ctxt = cipher->opaque; + + g_free(ctxt); + cipher->opaque = NULL; +} + + +static void qcrypto_cipher_aes_ecb_encrypt(const AES_KEY *key, + const void *in, + void *out, + size_t len) +{ + const uint8_t *inptr = in; + uint8_t *outptr = out; + while (len) { + if (len > AES_BLOCK_SIZE) { + AES_encrypt(inptr, outptr, key); + inptr += AES_BLOCK_SIZE; + outptr += AES_BLOCK_SIZE; + len -= AES_BLOCK_SIZE; + } else { + uint8_t tmp1[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE]; + memcpy(tmp1, inptr, len); + /* Fill with 0 to avoid valgrind uninitialized reads */ + memset(tmp1 + len, 0, sizeof(tmp1) - len); + AES_encrypt(tmp1, tmp2, key); + memcpy(outptr, tmp2, len); + len = 0; + } + } +} + + +static void qcrypto_cipher_aes_ecb_decrypt(const AES_KEY *key, + const void *in, + void *out, + size_t len) +{ + const uint8_t *inptr = in; + uint8_t *outptr = out; + while (len) { + if (len > AES_BLOCK_SIZE) { + AES_decrypt(inptr, outptr, key); + inptr += AES_BLOCK_SIZE; + outptr += AES_BLOCK_SIZE; + len -= AES_BLOCK_SIZE; + } else { + uint8_t tmp1[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE]; + memcpy(tmp1, inptr, len); + /* Fill with 0 to avoid valgrind uninitialized reads */ + memset(tmp1 + len, 0, sizeof(tmp1) - len); + AES_decrypt(tmp1, tmp2, key); + memcpy(outptr, tmp2, len); + len = 0; + } + } +} + + +static void qcrypto_cipher_aes_xts_encrypt(const void *ctx, + size_t length, + uint8_t *dst, + const uint8_t *src) +{ + const QCryptoCipherBuiltinAESContext *aesctx = ctx; + + qcrypto_cipher_aes_ecb_encrypt(&aesctx->enc, src, dst, length); +} + + +static void qcrypto_cipher_aes_xts_decrypt(const void *ctx, + size_t length, + uint8_t *dst, + const uint8_t *src) +{ + const QCryptoCipherBuiltinAESContext *aesctx = ctx; + + qcrypto_cipher_aes_ecb_decrypt(&aesctx->dec, src, dst, length); +} + + +static int qcrypto_cipher_encrypt_aes(QCryptoCipher *cipher, + const void *in, + void *out, + size_t len, + Error **errp) +{ + QCryptoCipherBuiltin *ctxt = cipher->opaque; + + switch (cipher->mode) { + case QCRYPTO_CIPHER_MODE_ECB: + qcrypto_cipher_aes_ecb_encrypt(&ctxt->state.aes.key.enc, + in, out, len); + break; + case QCRYPTO_CIPHER_MODE_CBC: + AES_cbc_encrypt(in, out, len, + &ctxt->state.aes.key.enc, + ctxt->state.aes.iv, 1); + break; + case QCRYPTO_CIPHER_MODE_XTS: + xts_encrypt(&ctxt->state.aes.key, + &ctxt->state.aes.key_tweak, + qcrypto_cipher_aes_xts_encrypt, + qcrypto_cipher_aes_xts_decrypt, + ctxt->state.aes.iv, + len, out, in); + break; + default: + g_assert_not_reached(); + } + + return 0; +} + + +static int qcrypto_cipher_decrypt_aes(QCryptoCipher *cipher, + const void *in, + void *out, + size_t len, + Error **errp) +{ + QCryptoCipherBuiltin *ctxt = cipher->opaque; + + switch (cipher->mode) { + case QCRYPTO_CIPHER_MODE_ECB: + qcrypto_cipher_aes_ecb_decrypt(&ctxt->state.aes.key.dec, + in, out, len); + break; + case QCRYPTO_CIPHER_MODE_CBC: + AES_cbc_encrypt(in, out, len, + &ctxt->state.aes.key.dec, + ctxt->state.aes.iv, 0); + break; + case QCRYPTO_CIPHER_MODE_XTS: + xts_decrypt(&ctxt->state.aes.key, + &ctxt->state.aes.key_tweak, + qcrypto_cipher_aes_xts_encrypt, + qcrypto_cipher_aes_xts_decrypt, + ctxt->state.aes.iv, + len, out, in); + break; + default: + g_assert_not_reached(); + } + + return 0; +} + +static int qcrypto_cipher_setiv_aes(QCryptoCipher *cipher, + const uint8_t *iv, size_t niv, + Error **errp) +{ + QCryptoCipherBuiltin *ctxt = cipher->opaque; + if (niv != AES_BLOCK_SIZE) { + error_setg(errp, "IV must be %d bytes not %zu", + AES_BLOCK_SIZE, niv); + return -1; + } + + memcpy(ctxt->state.aes.iv, iv, AES_BLOCK_SIZE); + + return 0; +} + + + + +static QCryptoCipherBuiltin * +qcrypto_cipher_init_aes(QCryptoCipherMode mode, + const uint8_t *key, size_t nkey, + Error **errp) +{ + QCryptoCipherBuiltin *ctxt; + + if (mode != QCRYPTO_CIPHER_MODE_CBC && + mode != QCRYPTO_CIPHER_MODE_ECB && + mode != QCRYPTO_CIPHER_MODE_XTS) { + error_setg(errp, "Unsupported cipher mode %s", + QCryptoCipherMode_str(mode)); + return NULL; + } + + ctxt = g_new0(QCryptoCipherBuiltin, 1); + + if (mode == QCRYPTO_CIPHER_MODE_XTS) { + if (AES_set_encrypt_key(key, nkey * 4, &ctxt->state.aes.key.enc) != 0) { + error_setg(errp, "Failed to set encryption key"); + goto error; + } + + if (AES_set_decrypt_key(key, nkey * 4, &ctxt->state.aes.key.dec) != 0) { + error_setg(errp, "Failed to set decryption key"); + goto error; + } + + if (AES_set_encrypt_key(key + (nkey / 2), nkey * 4, + &ctxt->state.aes.key_tweak.enc) != 0) { + error_setg(errp, "Failed to set encryption key"); + goto error; + } + + if (AES_set_decrypt_key(key + (nkey / 2), nkey * 4, + &ctxt->state.aes.key_tweak.dec) != 0) { + error_setg(errp, "Failed to set decryption key"); + goto error; + } + } else { + if (AES_set_encrypt_key(key, nkey * 8, &ctxt->state.aes.key.enc) != 0) { + error_setg(errp, "Failed to set encryption key"); + goto error; + } + + if (AES_set_decrypt_key(key, nkey * 8, &ctxt->state.aes.key.dec) != 0) { + error_setg(errp, "Failed to set decryption key"); + goto error; + } + } + + ctxt->blocksize = AES_BLOCK_SIZE; + ctxt->free = qcrypto_cipher_free_aes; + ctxt->setiv = qcrypto_cipher_setiv_aes; + ctxt->encrypt = qcrypto_cipher_encrypt_aes; + ctxt->decrypt = qcrypto_cipher_decrypt_aes; + + return ctxt; + + error: + g_free(ctxt); + return NULL; +} + + +static void qcrypto_cipher_free_des_rfb(QCryptoCipher *cipher) +{ + QCryptoCipherBuiltin *ctxt = cipher->opaque; + + g_free(ctxt->state.desrfb.key); + g_free(ctxt); + cipher->opaque = NULL; +} + + +static int qcrypto_cipher_encrypt_des_rfb(QCryptoCipher *cipher, + const void *in, + void *out, + size_t len, + Error **errp) +{ + QCryptoCipherBuiltin *ctxt = cipher->opaque; + size_t i; + + if (len % 8) { + error_setg(errp, "Buffer size must be multiple of 8 not %zu", + len); + return -1; + } + + deskey(ctxt->state.desrfb.key, EN0); + + for (i = 0; i < len; i += 8) { + des((void *)in + i, out + i); + } + + return 0; +} + + +static int qcrypto_cipher_decrypt_des_rfb(QCryptoCipher *cipher, + const void *in, + void *out, + size_t len, + Error **errp) +{ + QCryptoCipherBuiltin *ctxt = cipher->opaque; + size_t i; + + if (len % 8) { + error_setg(errp, "Buffer size must be multiple of 8 not %zu", + len); + return -1; + } + + deskey(ctxt->state.desrfb.key, DE1); + + for (i = 0; i < len; i += 8) { + des((void *)in + i, out + i); + } + + return 0; +} + + +static int qcrypto_cipher_setiv_des_rfb(QCryptoCipher *cipher, + const uint8_t *iv, size_t niv, + Error **errp) +{ + error_setg(errp, "Setting IV is not supported"); + return -1; +} + + +static QCryptoCipherBuiltin * +qcrypto_cipher_init_des_rfb(QCryptoCipherMode mode, + const uint8_t *key, size_t nkey, + Error **errp) +{ + QCryptoCipherBuiltin *ctxt; + + if (mode != QCRYPTO_CIPHER_MODE_ECB) { + error_setg(errp, "Unsupported cipher mode %s", + QCryptoCipherMode_str(mode)); + return NULL; + } + + ctxt = g_new0(QCryptoCipherBuiltin, 1); + + ctxt->state.desrfb.key = g_new0(uint8_t, nkey); + memcpy(ctxt->state.desrfb.key, key, nkey); + ctxt->state.desrfb.nkey = nkey; + + ctxt->blocksize = 8; + ctxt->free = qcrypto_cipher_free_des_rfb; + ctxt->setiv = qcrypto_cipher_setiv_des_rfb; + ctxt->encrypt = qcrypto_cipher_encrypt_des_rfb; + ctxt->decrypt = qcrypto_cipher_decrypt_des_rfb; + + return ctxt; +} + + +bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg, + QCryptoCipherMode mode) +{ + switch (alg) { + case QCRYPTO_CIPHER_ALG_DES_RFB: + case QCRYPTO_CIPHER_ALG_AES_128: + case QCRYPTO_CIPHER_ALG_AES_192: + case QCRYPTO_CIPHER_ALG_AES_256: + break; + default: + return false; + } + + switch (mode) { + case QCRYPTO_CIPHER_MODE_ECB: + case QCRYPTO_CIPHER_MODE_CBC: + case QCRYPTO_CIPHER_MODE_XTS: + return true; + case QCRYPTO_CIPHER_MODE_CTR: + return false; + default: + return false; + } +} + + +static QCryptoCipherBuiltin *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg, + QCryptoCipherMode mode, + const uint8_t *key, + size_t nkey, + Error **errp) +{ + QCryptoCipherBuiltin *ctxt; + + switch (mode) { + case QCRYPTO_CIPHER_MODE_ECB: + case QCRYPTO_CIPHER_MODE_CBC: + case QCRYPTO_CIPHER_MODE_XTS: + break; + default: + error_setg(errp, "Unsupported cipher mode %s", + QCryptoCipherMode_str(mode)); + return NULL; + } + + if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) { + return NULL; + } + + switch (alg) { + case QCRYPTO_CIPHER_ALG_DES_RFB: + ctxt = qcrypto_cipher_init_des_rfb(mode, key, nkey, errp); + break; + case QCRYPTO_CIPHER_ALG_AES_128: + case QCRYPTO_CIPHER_ALG_AES_192: + case QCRYPTO_CIPHER_ALG_AES_256: + ctxt = qcrypto_cipher_init_aes(mode, key, nkey, errp); + break; + default: + error_setg(errp, + "Unsupported cipher algorithm %s", + QCryptoCipherAlgorithm_str(alg)); + return NULL; + } + + return ctxt; +} + +static void +qcrypto_builtin_cipher_ctx_free(QCryptoCipher *cipher) +{ + QCryptoCipherBuiltin *ctxt; + + ctxt = cipher->opaque; + ctxt->free(cipher); +} + + +static int +qcrypto_builtin_cipher_encrypt(QCryptoCipher *cipher, + const void *in, + void *out, + size_t len, + Error **errp) +{ + QCryptoCipherBuiltin *ctxt = cipher->opaque; + + if (len & (ctxt->blocksize - 1)) { + error_setg(errp, "Length %zu must be a multiple of block size %zu", + len, ctxt->blocksize); + return -1; + } + + return ctxt->encrypt(cipher, in, out, len, errp); +} + + +static int +qcrypto_builtin_cipher_decrypt(QCryptoCipher *cipher, + const void *in, + void *out, + size_t len, + Error **errp) +{ + QCryptoCipherBuiltin *ctxt = cipher->opaque; + + if (len & (ctxt->blocksize - 1)) { + error_setg(errp, "Length %zu must be a multiple of block size %zu", + len, ctxt->blocksize); + return -1; + } + + return ctxt->decrypt(cipher, in, out, len, errp); +} + + +static int +qcrypto_builtin_cipher_setiv(QCryptoCipher *cipher, + const uint8_t *iv, size_t niv, + Error **errp) +{ + QCryptoCipherBuiltin *ctxt = cipher->opaque; + + return ctxt->setiv(cipher, iv, niv, errp); +} + + +static struct QCryptoCipherDriver qcrypto_cipher_lib_driver = { + .cipher_encrypt = qcrypto_builtin_cipher_encrypt, + .cipher_decrypt = qcrypto_builtin_cipher_decrypt, + .cipher_setiv = qcrypto_builtin_cipher_setiv, + .cipher_free = qcrypto_builtin_cipher_ctx_free, +}; diff --git a/crypto/cipher-gcrypt.c b/crypto/cipher-gcrypt.c deleted file mode 100644 index 81e4745bff..0000000000 --- a/crypto/cipher-gcrypt.c +++ /dev/null @@ -1,423 +0,0 @@ -/* - * QEMU Crypto cipher libgcrypt 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.1 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 "qemu/osdep.h" -#ifdef CONFIG_QEMU_PRIVATE_XTS -#include "crypto/xts.h" -#endif -#include "cipherpriv.h" - -#include - - -bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg, - QCryptoCipherMode mode) -{ - switch (alg) { - case QCRYPTO_CIPHER_ALG_DES_RFB: - case QCRYPTO_CIPHER_ALG_3DES: - case QCRYPTO_CIPHER_ALG_AES_128: - case QCRYPTO_CIPHER_ALG_AES_192: - case QCRYPTO_CIPHER_ALG_AES_256: - case QCRYPTO_CIPHER_ALG_CAST5_128: - case QCRYPTO_CIPHER_ALG_SERPENT_128: - case QCRYPTO_CIPHER_ALG_SERPENT_192: - case QCRYPTO_CIPHER_ALG_SERPENT_256: - case QCRYPTO_CIPHER_ALG_TWOFISH_128: - case QCRYPTO_CIPHER_ALG_TWOFISH_256: - break; - default: - return false; - } - - switch (mode) { - case QCRYPTO_CIPHER_MODE_ECB: - case QCRYPTO_CIPHER_MODE_CBC: - case QCRYPTO_CIPHER_MODE_XTS: - case QCRYPTO_CIPHER_MODE_CTR: - return true; - default: - return false; - } -} - -typedef struct QCryptoCipherGcrypt QCryptoCipherGcrypt; -struct QCryptoCipherGcrypt { - gcry_cipher_hd_t handle; - size_t blocksize; -#ifdef CONFIG_QEMU_PRIVATE_XTS - gcry_cipher_hd_t tweakhandle; - /* Initialization vector or Counter */ - uint8_t *iv; -#endif -}; - -static void -qcrypto_gcrypt_cipher_free_ctx(QCryptoCipherGcrypt *ctx, - QCryptoCipherMode mode) -{ - if (!ctx) { - return; - } - - gcry_cipher_close(ctx->handle); -#ifdef CONFIG_QEMU_PRIVATE_XTS - if (mode == QCRYPTO_CIPHER_MODE_XTS) { - gcry_cipher_close(ctx->tweakhandle); - } - g_free(ctx->iv); -#endif - g_free(ctx); -} - - -static QCryptoCipherGcrypt *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg, - QCryptoCipherMode mode, - const uint8_t *key, - size_t nkey, - Error **errp) -{ - QCryptoCipherGcrypt *ctx; - gcry_error_t err; - int gcryalg, gcrymode; - - switch (mode) { - case QCRYPTO_CIPHER_MODE_ECB: - gcrymode = GCRY_CIPHER_MODE_ECB; - break; - case QCRYPTO_CIPHER_MODE_XTS: -#ifdef CONFIG_QEMU_PRIVATE_XTS - gcrymode = GCRY_CIPHER_MODE_ECB; -#else - gcrymode = GCRY_CIPHER_MODE_XTS; -#endif - break; - case QCRYPTO_CIPHER_MODE_CBC: - gcrymode = GCRY_CIPHER_MODE_CBC; - break; - case QCRYPTO_CIPHER_MODE_CTR: - gcrymode = GCRY_CIPHER_MODE_CTR; - break; - default: - error_setg(errp, "Unsupported cipher mode %s", - QCryptoCipherMode_str(mode)); - return NULL; - } - - if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) { - return NULL; - } - - switch (alg) { - case QCRYPTO_CIPHER_ALG_DES_RFB: - gcryalg = GCRY_CIPHER_DES; - break; - - case QCRYPTO_CIPHER_ALG_3DES: - gcryalg = GCRY_CIPHER_3DES; - break; - - case QCRYPTO_CIPHER_ALG_AES_128: - gcryalg = GCRY_CIPHER_AES128; - break; - - case QCRYPTO_CIPHER_ALG_AES_192: - gcryalg = GCRY_CIPHER_AES192; - break; - - case QCRYPTO_CIPHER_ALG_AES_256: - gcryalg = GCRY_CIPHER_AES256; - break; - - case QCRYPTO_CIPHER_ALG_CAST5_128: - gcryalg = GCRY_CIPHER_CAST5; - break; - - case QCRYPTO_CIPHER_ALG_SERPENT_128: - gcryalg = GCRY_CIPHER_SERPENT128; - break; - - case QCRYPTO_CIPHER_ALG_SERPENT_192: - gcryalg = GCRY_CIPHER_SERPENT192; - break; - - case QCRYPTO_CIPHER_ALG_SERPENT_256: - gcryalg = GCRY_CIPHER_SERPENT256; - break; - - case QCRYPTO_CIPHER_ALG_TWOFISH_128: - gcryalg = GCRY_CIPHER_TWOFISH128; - break; - - case QCRYPTO_CIPHER_ALG_TWOFISH_256: - gcryalg = GCRY_CIPHER_TWOFISH; - break; - - default: - error_setg(errp, "Unsupported cipher algorithm %s", - QCryptoCipherAlgorithm_str(alg)); - return NULL; - } - - ctx = g_new0(QCryptoCipherGcrypt, 1); - - err = gcry_cipher_open(&ctx->handle, gcryalg, gcrymode, 0); - if (err != 0) { - error_setg(errp, "Cannot initialize cipher: %s", - gcry_strerror(err)); - goto error; - } -#ifdef CONFIG_QEMU_PRIVATE_XTS - if (mode == QCRYPTO_CIPHER_MODE_XTS) { - err = gcry_cipher_open(&ctx->tweakhandle, gcryalg, gcrymode, 0); - if (err != 0) { - error_setg(errp, "Cannot initialize cipher: %s", - gcry_strerror(err)); - goto error; - } - } -#endif - - if (alg == QCRYPTO_CIPHER_ALG_DES_RFB) { - /* We're using standard DES cipher from gcrypt, so we need - * to munge the key so that the results are the same as the - * bizarre RFB variant of DES :-) - */ - uint8_t *rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey); - err = gcry_cipher_setkey(ctx->handle, rfbkey, nkey); - g_free(rfbkey); - ctx->blocksize = 8; - } else { -#ifdef CONFIG_QEMU_PRIVATE_XTS - if (mode == QCRYPTO_CIPHER_MODE_XTS) { - nkey /= 2; - err = gcry_cipher_setkey(ctx->handle, key, nkey); - if (err != 0) { - error_setg(errp, "Cannot set key: %s", - gcry_strerror(err)); - goto error; - } - err = gcry_cipher_setkey(ctx->tweakhandle, key + nkey, nkey); - } else { -#endif - err = gcry_cipher_setkey(ctx->handle, key, nkey); -#ifdef CONFIG_QEMU_PRIVATE_XTS - } -#endif - if (err != 0) { - error_setg(errp, "Cannot set key: %s", - gcry_strerror(err)); - goto error; - } - switch (alg) { - case QCRYPTO_CIPHER_ALG_AES_128: - case QCRYPTO_CIPHER_ALG_AES_192: - case QCRYPTO_CIPHER_ALG_AES_256: - case QCRYPTO_CIPHER_ALG_SERPENT_128: - case QCRYPTO_CIPHER_ALG_SERPENT_192: - case QCRYPTO_CIPHER_ALG_SERPENT_256: - case QCRYPTO_CIPHER_ALG_TWOFISH_128: - case QCRYPTO_CIPHER_ALG_TWOFISH_256: - ctx->blocksize = 16; - break; - case QCRYPTO_CIPHER_ALG_3DES: - case QCRYPTO_CIPHER_ALG_CAST5_128: - ctx->blocksize = 8; - break; - default: - g_assert_not_reached(); - } - } - g_assert(is_power_of_2(ctx->blocksize)); - -#ifdef CONFIG_QEMU_PRIVATE_XTS - if (mode == QCRYPTO_CIPHER_MODE_XTS) { - if (ctx->blocksize != XTS_BLOCK_SIZE) { - error_setg(errp, - "Cipher block size %zu must equal XTS block size %d", - ctx->blocksize, XTS_BLOCK_SIZE); - goto error; - } - ctx->iv = g_new0(uint8_t, ctx->blocksize); - } -#endif - - return ctx; - - error: - qcrypto_gcrypt_cipher_free_ctx(ctx, mode); - return NULL; -} - - -static void -qcrypto_gcrypt_cipher_ctx_free(QCryptoCipher *cipher) -{ - qcrypto_gcrypt_cipher_free_ctx(cipher->opaque, cipher->mode); -} - - -#ifdef CONFIG_QEMU_PRIVATE_XTS -static void qcrypto_gcrypt_xts_encrypt(const void *ctx, - size_t length, - uint8_t *dst, - const uint8_t *src) -{ - gcry_error_t err; - err = gcry_cipher_encrypt((gcry_cipher_hd_t)ctx, dst, length, src, length); - g_assert(err == 0); -} - -static void qcrypto_gcrypt_xts_decrypt(const void *ctx, - size_t length, - uint8_t *dst, - const uint8_t *src) -{ - gcry_error_t err; - err = gcry_cipher_decrypt((gcry_cipher_hd_t)ctx, dst, length, src, length); - g_assert(err == 0); -} -#endif - -static int -qcrypto_gcrypt_cipher_encrypt(QCryptoCipher *cipher, - const void *in, - void *out, - size_t len, - Error **errp) -{ - QCryptoCipherGcrypt *ctx = cipher->opaque; - gcry_error_t err; - - if (len & (ctx->blocksize - 1)) { - error_setg(errp, "Length %zu must be a multiple of block size %zu", - len, ctx->blocksize); - return -1; - } - -#ifdef CONFIG_QEMU_PRIVATE_XTS - if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) { - xts_encrypt(ctx->handle, ctx->tweakhandle, - qcrypto_gcrypt_xts_encrypt, - qcrypto_gcrypt_xts_decrypt, - ctx->iv, len, out, in); - return 0; - } -#endif - - err = gcry_cipher_encrypt(ctx->handle, - out, len, - in, len); - if (err != 0) { - error_setg(errp, "Cannot encrypt data: %s", - gcry_strerror(err)); - return -1; - } - - return 0; -} - - -static int -qcrypto_gcrypt_cipher_decrypt(QCryptoCipher *cipher, - const void *in, - void *out, - size_t len, - Error **errp) -{ - QCryptoCipherGcrypt *ctx = cipher->opaque; - gcry_error_t err; - - if (len & (ctx->blocksize - 1)) { - error_setg(errp, "Length %zu must be a multiple of block size %zu", - len, ctx->blocksize); - return -1; - } - -#ifdef CONFIG_QEMU_PRIVATE_XTS - if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) { - xts_decrypt(ctx->handle, ctx->tweakhandle, - qcrypto_gcrypt_xts_encrypt, - qcrypto_gcrypt_xts_decrypt, - ctx->iv, len, out, in); - return 0; - } -#endif - - err = gcry_cipher_decrypt(ctx->handle, - out, len, - in, len); - if (err != 0) { - error_setg(errp, "Cannot decrypt data: %s", - gcry_strerror(err)); - return -1; - } - - return 0; -} - -static int -qcrypto_gcrypt_cipher_setiv(QCryptoCipher *cipher, - const uint8_t *iv, size_t niv, - Error **errp) -{ - QCryptoCipherGcrypt *ctx = cipher->opaque; - gcry_error_t err; - - if (niv != ctx->blocksize) { - error_setg(errp, "Expected IV size %zu not %zu", - ctx->blocksize, niv); - return -1; - } - -#ifdef CONFIG_QEMU_PRIVATE_XTS - if (ctx->iv) { - memcpy(ctx->iv, iv, niv); - return 0; - } -#endif - - if (cipher->mode == QCRYPTO_CIPHER_MODE_CTR) { - err = gcry_cipher_setctr(ctx->handle, iv, niv); - if (err != 0) { - error_setg(errp, "Cannot set Counter: %s", - gcry_strerror(err)); - return -1; - } - } else { - gcry_cipher_reset(ctx->handle); - err = gcry_cipher_setiv(ctx->handle, iv, niv); - if (err != 0) { - error_setg(errp, "Cannot set IV: %s", - gcry_strerror(err)); - return -1; - } - } - - return 0; -} - - -static struct QCryptoCipherDriver qcrypto_cipher_lib_driver = { - .cipher_encrypt = qcrypto_gcrypt_cipher_encrypt, - .cipher_decrypt = qcrypto_gcrypt_cipher_decrypt, - .cipher_setiv = qcrypto_gcrypt_cipher_setiv, - .cipher_free = qcrypto_gcrypt_cipher_ctx_free, -}; diff --git a/crypto/cipher-gcrypt.c.inc b/crypto/cipher-gcrypt.c.inc new file mode 100644 index 0000000000..81e4745bff --- /dev/null +++ b/crypto/cipher-gcrypt.c.inc @@ -0,0 +1,423 @@ +/* + * QEMU Crypto cipher libgcrypt 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.1 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 "qemu/osdep.h" +#ifdef CONFIG_QEMU_PRIVATE_XTS +#include "crypto/xts.h" +#endif +#include "cipherpriv.h" + +#include + + +bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg, + QCryptoCipherMode mode) +{ + switch (alg) { + case QCRYPTO_CIPHER_ALG_DES_RFB: + case QCRYPTO_CIPHER_ALG_3DES: + case QCRYPTO_CIPHER_ALG_AES_128: + case QCRYPTO_CIPHER_ALG_AES_192: + case QCRYPTO_CIPHER_ALG_AES_256: + case QCRYPTO_CIPHER_ALG_CAST5_128: + case QCRYPTO_CIPHER_ALG_SERPENT_128: + case QCRYPTO_CIPHER_ALG_SERPENT_192: + case QCRYPTO_CIPHER_ALG_SERPENT_256: + case QCRYPTO_CIPHER_ALG_TWOFISH_128: + case QCRYPTO_CIPHER_ALG_TWOFISH_256: + break; + default: + return false; + } + + switch (mode) { + case QCRYPTO_CIPHER_MODE_ECB: + case QCRYPTO_CIPHER_MODE_CBC: + case QCRYPTO_CIPHER_MODE_XTS: + case QCRYPTO_CIPHER_MODE_CTR: + return true; + default: + return false; + } +} + +typedef struct QCryptoCipherGcrypt QCryptoCipherGcrypt; +struct QCryptoCipherGcrypt { + gcry_cipher_hd_t handle; + size_t blocksize; +#ifdef CONFIG_QEMU_PRIVATE_XTS + gcry_cipher_hd_t tweakhandle; + /* Initialization vector or Counter */ + uint8_t *iv; +#endif +}; + +static void +qcrypto_gcrypt_cipher_free_ctx(QCryptoCipherGcrypt *ctx, + QCryptoCipherMode mode) +{ + if (!ctx) { + return; + } + + gcry_cipher_close(ctx->handle); +#ifdef CONFIG_QEMU_PRIVATE_XTS + if (mode == QCRYPTO_CIPHER_MODE_XTS) { + gcry_cipher_close(ctx->tweakhandle); + } + g_free(ctx->iv); +#endif + g_free(ctx); +} + + +static QCryptoCipherGcrypt *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg, + QCryptoCipherMode mode, + const uint8_t *key, + size_t nkey, + Error **errp) +{ + QCryptoCipherGcrypt *ctx; + gcry_error_t err; + int gcryalg, gcrymode; + + switch (mode) { + case QCRYPTO_CIPHER_MODE_ECB: + gcrymode = GCRY_CIPHER_MODE_ECB; + break; + case QCRYPTO_CIPHER_MODE_XTS: +#ifdef CONFIG_QEMU_PRIVATE_XTS + gcrymode = GCRY_CIPHER_MODE_ECB; +#else + gcrymode = GCRY_CIPHER_MODE_XTS; +#endif + break; + case QCRYPTO_CIPHER_MODE_CBC: + gcrymode = GCRY_CIPHER_MODE_CBC; + break; + case QCRYPTO_CIPHER_MODE_CTR: + gcrymode = GCRY_CIPHER_MODE_CTR; + break; + default: + error_setg(errp, "Unsupported cipher mode %s", + QCryptoCipherMode_str(mode)); + return NULL; + } + + if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) { + return NULL; + } + + switch (alg) { + case QCRYPTO_CIPHER_ALG_DES_RFB: + gcryalg = GCRY_CIPHER_DES; + break; + + case QCRYPTO_CIPHER_ALG_3DES: + gcryalg = GCRY_CIPHER_3DES; + break; + + case QCRYPTO_CIPHER_ALG_AES_128: + gcryalg = GCRY_CIPHER_AES128; + break; + + case QCRYPTO_CIPHER_ALG_AES_192: + gcryalg = GCRY_CIPHER_AES192; + break; + + case QCRYPTO_CIPHER_ALG_AES_256: + gcryalg = GCRY_CIPHER_AES256; + break; + + case QCRYPTO_CIPHER_ALG_CAST5_128: + gcryalg = GCRY_CIPHER_CAST5; + break; + + case QCRYPTO_CIPHER_ALG_SERPENT_128: + gcryalg = GCRY_CIPHER_SERPENT128; + break; + + case QCRYPTO_CIPHER_ALG_SERPENT_192: + gcryalg = GCRY_CIPHER_SERPENT192; + break; + + case QCRYPTO_CIPHER_ALG_SERPENT_256: + gcryalg = GCRY_CIPHER_SERPENT256; + break; + + case QCRYPTO_CIPHER_ALG_TWOFISH_128: + gcryalg = GCRY_CIPHER_TWOFISH128; + break; + + case QCRYPTO_CIPHER_ALG_TWOFISH_256: + gcryalg = GCRY_CIPHER_TWOFISH; + break; + + default: + error_setg(errp, "Unsupported cipher algorithm %s", + QCryptoCipherAlgorithm_str(alg)); + return NULL; + } + + ctx = g_new0(QCryptoCipherGcrypt, 1); + + err = gcry_cipher_open(&ctx->handle, gcryalg, gcrymode, 0); + if (err != 0) { + error_setg(errp, "Cannot initialize cipher: %s", + gcry_strerror(err)); + goto error; + } +#ifdef CONFIG_QEMU_PRIVATE_XTS + if (mode == QCRYPTO_CIPHER_MODE_XTS) { + err = gcry_cipher_open(&ctx->tweakhandle, gcryalg, gcrymode, 0); + if (err != 0) { + error_setg(errp, "Cannot initialize cipher: %s", + gcry_strerror(err)); + goto error; + } + } +#endif + + if (alg == QCRYPTO_CIPHER_ALG_DES_RFB) { + /* We're using standard DES cipher from gcrypt, so we need + * to munge the key so that the results are the same as the + * bizarre RFB variant of DES :-) + */ + uint8_t *rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey); + err = gcry_cipher_setkey(ctx->handle, rfbkey, nkey); + g_free(rfbkey); + ctx->blocksize = 8; + } else { +#ifdef CONFIG_QEMU_PRIVATE_XTS + if (mode == QCRYPTO_CIPHER_MODE_XTS) { + nkey /= 2; + err = gcry_cipher_setkey(ctx->handle, key, nkey); + if (err != 0) { + error_setg(errp, "Cannot set key: %s", + gcry_strerror(err)); + goto error; + } + err = gcry_cipher_setkey(ctx->tweakhandle, key + nkey, nkey); + } else { +#endif + err = gcry_cipher_setkey(ctx->handle, key, nkey); +#ifdef CONFIG_QEMU_PRIVATE_XTS + } +#endif + if (err != 0) { + error_setg(errp, "Cannot set key: %s", + gcry_strerror(err)); + goto error; + } + switch (alg) { + case QCRYPTO_CIPHER_ALG_AES_128: + case QCRYPTO_CIPHER_ALG_AES_192: + case QCRYPTO_CIPHER_ALG_AES_256: + case QCRYPTO_CIPHER_ALG_SERPENT_128: + case QCRYPTO_CIPHER_ALG_SERPENT_192: + case QCRYPTO_CIPHER_ALG_SERPENT_256: + case QCRYPTO_CIPHER_ALG_TWOFISH_128: + case QCRYPTO_CIPHER_ALG_TWOFISH_256: + ctx->blocksize = 16; + break; + case QCRYPTO_CIPHER_ALG_3DES: + case QCRYPTO_CIPHER_ALG_CAST5_128: + ctx->blocksize = 8; + break; + default: + g_assert_not_reached(); + } + } + g_assert(is_power_of_2(ctx->blocksize)); + +#ifdef CONFIG_QEMU_PRIVATE_XTS + if (mode == QCRYPTO_CIPHER_MODE_XTS) { + if (ctx->blocksize != XTS_BLOCK_SIZE) { + error_setg(errp, + "Cipher block size %zu must equal XTS block size %d", + ctx->blocksize, XTS_BLOCK_SIZE); + goto error; + } + ctx->iv = g_new0(uint8_t, ctx->blocksize); + } +#endif + + return ctx; + + error: + qcrypto_gcrypt_cipher_free_ctx(ctx, mode); + return NULL; +} + + +static void +qcrypto_gcrypt_cipher_ctx_free(QCryptoCipher *cipher) +{ + qcrypto_gcrypt_cipher_free_ctx(cipher->opaque, cipher->mode); +} + + +#ifdef CONFIG_QEMU_PRIVATE_XTS +static void qcrypto_gcrypt_xts_encrypt(const void *ctx, + size_t length, + uint8_t *dst, + const uint8_t *src) +{ + gcry_error_t err; + err = gcry_cipher_encrypt((gcry_cipher_hd_t)ctx, dst, length, src, length); + g_assert(err == 0); +} + +static void qcrypto_gcrypt_xts_decrypt(const void *ctx, + size_t length, + uint8_t *dst, + const uint8_t *src) +{ + gcry_error_t err; + err = gcry_cipher_decrypt((gcry_cipher_hd_t)ctx, dst, length, src, length); + g_assert(err == 0); +} +#endif + +static int +qcrypto_gcrypt_cipher_encrypt(QCryptoCipher *cipher, + const void *in, + void *out, + size_t len, + Error **errp) +{ + QCryptoCipherGcrypt *ctx = cipher->opaque; + gcry_error_t err; + + if (len & (ctx->blocksize - 1)) { + error_setg(errp, "Length %zu must be a multiple of block size %zu", + len, ctx->blocksize); + return -1; + } + +#ifdef CONFIG_QEMU_PRIVATE_XTS + if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) { + xts_encrypt(ctx->handle, ctx->tweakhandle, + qcrypto_gcrypt_xts_encrypt, + qcrypto_gcrypt_xts_decrypt, + ctx->iv, len, out, in); + return 0; + } +#endif + + err = gcry_cipher_encrypt(ctx->handle, + out, len, + in, len); + if (err != 0) { + error_setg(errp, "Cannot encrypt data: %s", + gcry_strerror(err)); + return -1; + } + + return 0; +} + + +static int +qcrypto_gcrypt_cipher_decrypt(QCryptoCipher *cipher, + const void *in, + void *out, + size_t len, + Error **errp) +{ + QCryptoCipherGcrypt *ctx = cipher->opaque; + gcry_error_t err; + + if (len & (ctx->blocksize - 1)) { + error_setg(errp, "Length %zu must be a multiple of block size %zu", + len, ctx->blocksize); + return -1; + } + +#ifdef CONFIG_QEMU_PRIVATE_XTS + if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) { + xts_decrypt(ctx->handle, ctx->tweakhandle, + qcrypto_gcrypt_xts_encrypt, + qcrypto_gcrypt_xts_decrypt, + ctx->iv, len, out, in); + return 0; + } +#endif + + err = gcry_cipher_decrypt(ctx->handle, + out, len, + in, len); + if (err != 0) { + error_setg(errp, "Cannot decrypt data: %s", + gcry_strerror(err)); + return -1; + } + + return 0; +} + +static int +qcrypto_gcrypt_cipher_setiv(QCryptoCipher *cipher, + const uint8_t *iv, size_t niv, + Error **errp) +{ + QCryptoCipherGcrypt *ctx = cipher->opaque; + gcry_error_t err; + + if (niv != ctx->blocksize) { + error_setg(errp, "Expected IV size %zu not %zu", + ctx->blocksize, niv); + return -1; + } + +#ifdef CONFIG_QEMU_PRIVATE_XTS + if (ctx->iv) { + memcpy(ctx->iv, iv, niv); + return 0; + } +#endif + + if (cipher->mode == QCRYPTO_CIPHER_MODE_CTR) { + err = gcry_cipher_setctr(ctx->handle, iv, niv); + if (err != 0) { + error_setg(errp, "Cannot set Counter: %s", + gcry_strerror(err)); + return -1; + } + } else { + gcry_cipher_reset(ctx->handle); + err = gcry_cipher_setiv(ctx->handle, iv, niv); + if (err != 0) { + error_setg(errp, "Cannot set IV: %s", + gcry_strerror(err)); + return -1; + } + } + + return 0; +} + + +static struct QCryptoCipherDriver qcrypto_cipher_lib_driver = { + .cipher_encrypt = qcrypto_gcrypt_cipher_encrypt, + .cipher_decrypt = qcrypto_gcrypt_cipher_decrypt, + .cipher_setiv = qcrypto_gcrypt_cipher_setiv, + .cipher_free = qcrypto_gcrypt_cipher_ctx_free, +}; diff --git a/crypto/cipher-nettle.c b/crypto/cipher-nettle.c deleted file mode 100644 index 0677fdfd33..0000000000 --- a/crypto/cipher-nettle.c +++ /dev/null @@ -1,734 +0,0 @@ -/* - * 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.1 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 "qemu/osdep.h" -#ifdef CONFIG_QEMU_PRIVATE_XTS -#include "crypto/xts.h" -#endif -#include "cipherpriv.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef CONFIG_QEMU_PRIVATE_XTS -#include -#endif - -typedef void (*QCryptoCipherNettleFuncWrapper)(const void *ctx, - size_t length, - uint8_t *dst, - const uint8_t *src); - -#if CONFIG_NETTLE_VERSION_MAJOR < 3 -typedef nettle_crypt_func * QCryptoCipherNettleFuncNative; -typedef void * cipher_ctx_t; -typedef unsigned cipher_length_t; - -#define cast5_set_key cast128_set_key - -#define aes128_ctx aes_ctx -#define aes192_ctx aes_ctx -#define aes256_ctx aes_ctx -#define aes128_set_encrypt_key(c, k) \ - aes_set_encrypt_key(c, 16, k) -#define aes192_set_encrypt_key(c, k) \ - aes_set_encrypt_key(c, 24, k) -#define aes256_set_encrypt_key(c, k) \ - aes_set_encrypt_key(c, 32, k) -#define aes128_set_decrypt_key(c, k) \ - aes_set_decrypt_key(c, 16, k) -#define aes192_set_decrypt_key(c, k) \ - aes_set_decrypt_key(c, 24, k) -#define aes256_set_decrypt_key(c, k) \ - aes_set_decrypt_key(c, 32, k) -#define aes128_encrypt aes_encrypt -#define aes192_encrypt aes_encrypt -#define aes256_encrypt aes_encrypt -#define aes128_decrypt aes_decrypt -#define aes192_decrypt aes_decrypt -#define aes256_decrypt aes_decrypt -#else -typedef nettle_cipher_func * QCryptoCipherNettleFuncNative; -typedef const void * cipher_ctx_t; -typedef size_t cipher_length_t; -#endif - -typedef struct QCryptoNettleAES128 { - struct aes128_ctx enc; - struct aes128_ctx dec; -} QCryptoNettleAES128; - -typedef struct QCryptoNettleAES192 { - struct aes192_ctx enc; - struct aes192_ctx dec; -} QCryptoNettleAES192; - -typedef struct QCryptoNettleAES256 { - struct aes256_ctx enc; - struct aes256_ctx dec; -} QCryptoNettleAES256; - -static void aes128_encrypt_native(cipher_ctx_t ctx, cipher_length_t length, - uint8_t *dst, const uint8_t *src) -{ - const QCryptoNettleAES128 *aesctx = ctx; - aes128_encrypt(&aesctx->enc, length, dst, src); -} - -static void aes128_decrypt_native(cipher_ctx_t ctx, cipher_length_t length, - uint8_t *dst, const uint8_t *src) -{ - const QCryptoNettleAES128 *aesctx = ctx; - aes128_decrypt(&aesctx->dec, length, dst, src); -} - -static void aes192_encrypt_native(cipher_ctx_t ctx, cipher_length_t length, - uint8_t *dst, const uint8_t *src) -{ - const QCryptoNettleAES192 *aesctx = ctx; - aes192_encrypt(&aesctx->enc, length, dst, src); -} - -static void aes192_decrypt_native(cipher_ctx_t ctx, cipher_length_t length, - uint8_t *dst, const uint8_t *src) -{ - const QCryptoNettleAES192 *aesctx = ctx; - aes192_decrypt(&aesctx->dec, length, dst, src); -} - -static void aes256_encrypt_native(cipher_ctx_t ctx, cipher_length_t length, - uint8_t *dst, const uint8_t *src) -{ - const QCryptoNettleAES256 *aesctx = ctx; - aes256_encrypt(&aesctx->enc, length, dst, src); -} - -static void aes256_decrypt_native(cipher_ctx_t ctx, cipher_length_t length, - uint8_t *dst, const uint8_t *src) -{ - const QCryptoNettleAES256 *aesctx = ctx; - aes256_decrypt(&aesctx->dec, length, dst, src); -} - -static void des_encrypt_native(cipher_ctx_t ctx, cipher_length_t length, - uint8_t *dst, const uint8_t *src) -{ - des_encrypt(ctx, length, dst, src); -} - -static void des_decrypt_native(cipher_ctx_t ctx, cipher_length_t length, - uint8_t *dst, const uint8_t *src) -{ - des_decrypt(ctx, length, dst, src); -} - -static void des3_encrypt_native(cipher_ctx_t ctx, cipher_length_t length, - uint8_t *dst, const uint8_t *src) -{ - des3_encrypt(ctx, length, dst, src); -} - -static void des3_decrypt_native(cipher_ctx_t ctx, cipher_length_t length, - uint8_t *dst, const uint8_t *src) -{ - des3_decrypt(ctx, length, dst, src); -} - -static void cast128_encrypt_native(cipher_ctx_t ctx, cipher_length_t length, - uint8_t *dst, const uint8_t *src) -{ - cast128_encrypt(ctx, length, dst, src); -} - -static void cast128_decrypt_native(cipher_ctx_t ctx, cipher_length_t length, - uint8_t *dst, const uint8_t *src) -{ - cast128_decrypt(ctx, length, dst, src); -} - -static void serpent_encrypt_native(cipher_ctx_t ctx, cipher_length_t length, - uint8_t *dst, const uint8_t *src) -{ - serpent_encrypt(ctx, length, dst, src); -} - -static void serpent_decrypt_native(cipher_ctx_t ctx, cipher_length_t length, - uint8_t *dst, const uint8_t *src) -{ - serpent_decrypt(ctx, length, dst, src); -} - -static void twofish_encrypt_native(cipher_ctx_t ctx, cipher_length_t length, - uint8_t *dst, const uint8_t *src) -{ - twofish_encrypt(ctx, length, dst, src); -} - -static void twofish_decrypt_native(cipher_ctx_t ctx, cipher_length_t length, - uint8_t *dst, const uint8_t *src) -{ - twofish_decrypt(ctx, length, dst, src); -} - -static void aes128_encrypt_wrapper(const void *ctx, size_t length, - uint8_t *dst, const uint8_t *src) -{ - const QCryptoNettleAES128 *aesctx = ctx; - aes128_encrypt(&aesctx->enc, length, dst, src); -} - -static void aes128_decrypt_wrapper(const void *ctx, size_t length, - uint8_t *dst, const uint8_t *src) -{ - const QCryptoNettleAES128 *aesctx = ctx; - aes128_decrypt(&aesctx->dec, length, dst, src); -} - -static void aes192_encrypt_wrapper(const void *ctx, size_t length, - uint8_t *dst, const uint8_t *src) -{ - const QCryptoNettleAES192 *aesctx = ctx; - aes192_encrypt(&aesctx->enc, length, dst, src); -} - -static void aes192_decrypt_wrapper(const void *ctx, size_t length, - uint8_t *dst, const uint8_t *src) -{ - const QCryptoNettleAES192 *aesctx = ctx; - aes192_decrypt(&aesctx->dec, length, dst, src); -} - -static void aes256_encrypt_wrapper(const void *ctx, size_t length, - uint8_t *dst, const uint8_t *src) -{ - const QCryptoNettleAES256 *aesctx = ctx; - aes256_encrypt(&aesctx->enc, length, dst, src); -} - -static void aes256_decrypt_wrapper(const void *ctx, size_t length, - uint8_t *dst, const uint8_t *src) -{ - const QCryptoNettleAES256 *aesctx = ctx; - aes256_decrypt(&aesctx->dec, length, dst, src); -} - -static void des_encrypt_wrapper(const void *ctx, size_t length, - uint8_t *dst, const uint8_t *src) -{ - des_encrypt(ctx, length, dst, src); -} - -static void des_decrypt_wrapper(const void *ctx, size_t length, - uint8_t *dst, const uint8_t *src) -{ - des_decrypt(ctx, length, dst, src); -} - -static void des3_encrypt_wrapper(const void *ctx, size_t length, - uint8_t *dst, const uint8_t *src) -{ - des3_encrypt(ctx, length, dst, src); -} - -static void des3_decrypt_wrapper(const void *ctx, size_t length, - uint8_t *dst, const uint8_t *src) -{ - des3_decrypt(ctx, length, dst, src); -} - -static void cast128_encrypt_wrapper(const void *ctx, size_t length, - uint8_t *dst, const uint8_t *src) -{ - cast128_encrypt(ctx, length, dst, src); -} - -static void cast128_decrypt_wrapper(const void *ctx, size_t length, - uint8_t *dst, const uint8_t *src) -{ - cast128_decrypt(ctx, length, dst, src); -} - -static void serpent_encrypt_wrapper(const void *ctx, size_t length, - uint8_t *dst, const uint8_t *src) -{ - serpent_encrypt(ctx, length, dst, src); -} - -static void serpent_decrypt_wrapper(const void *ctx, size_t length, - uint8_t *dst, const uint8_t *src) -{ - serpent_decrypt(ctx, length, dst, src); -} - -static void twofish_encrypt_wrapper(const void *ctx, size_t length, - uint8_t *dst, const uint8_t *src) -{ - twofish_encrypt(ctx, length, dst, src); -} - -static void twofish_decrypt_wrapper(const void *ctx, size_t length, - uint8_t *dst, const uint8_t *src) -{ - twofish_decrypt(ctx, length, dst, src); -} - -typedef struct QCryptoCipherNettle QCryptoCipherNettle; -struct QCryptoCipherNettle { - /* Primary cipher context for all modes */ - void *ctx; - /* Second cipher context for XTS mode only */ - void *ctx_tweak; - /* Cipher callbacks for both contexts */ - QCryptoCipherNettleFuncNative alg_encrypt_native; - QCryptoCipherNettleFuncNative alg_decrypt_native; - QCryptoCipherNettleFuncWrapper alg_encrypt_wrapper; - QCryptoCipherNettleFuncWrapper alg_decrypt_wrapper; - /* Initialization vector or Counter */ - uint8_t *iv; - size_t blocksize; -}; - -bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg, - QCryptoCipherMode mode) -{ - switch (alg) { - case QCRYPTO_CIPHER_ALG_DES_RFB: - case QCRYPTO_CIPHER_ALG_3DES: - case QCRYPTO_CIPHER_ALG_AES_128: - case QCRYPTO_CIPHER_ALG_AES_192: - case QCRYPTO_CIPHER_ALG_AES_256: - case QCRYPTO_CIPHER_ALG_CAST5_128: - case QCRYPTO_CIPHER_ALG_SERPENT_128: - case QCRYPTO_CIPHER_ALG_SERPENT_192: - case QCRYPTO_CIPHER_ALG_SERPENT_256: - case QCRYPTO_CIPHER_ALG_TWOFISH_128: - case QCRYPTO_CIPHER_ALG_TWOFISH_192: - case QCRYPTO_CIPHER_ALG_TWOFISH_256: - break; - default: - return false; - } - - switch (mode) { - case QCRYPTO_CIPHER_MODE_ECB: - case QCRYPTO_CIPHER_MODE_CBC: - case QCRYPTO_CIPHER_MODE_XTS: - case QCRYPTO_CIPHER_MODE_CTR: - return true; - default: - return false; - } -} - - -static void -qcrypto_nettle_cipher_free_ctx(QCryptoCipherNettle *ctx) -{ - if (!ctx) { - return; - } - - g_free(ctx->iv); - g_free(ctx->ctx); - g_free(ctx->ctx_tweak); - g_free(ctx); -} - - -static QCryptoCipherNettle *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg, - QCryptoCipherMode mode, - const uint8_t *key, - size_t nkey, - Error **errp) -{ - QCryptoCipherNettle *ctx; - uint8_t *rfbkey; - - switch (mode) { - case QCRYPTO_CIPHER_MODE_ECB: - case QCRYPTO_CIPHER_MODE_CBC: - case QCRYPTO_CIPHER_MODE_XTS: - case QCRYPTO_CIPHER_MODE_CTR: - break; - default: - error_setg(errp, "Unsupported cipher mode %s", - QCryptoCipherMode_str(mode)); - return NULL; - } - - if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) { - return NULL; - } - - ctx = g_new0(QCryptoCipherNettle, 1); - - switch (alg) { - case QCRYPTO_CIPHER_ALG_DES_RFB: - ctx->ctx = g_new0(struct des_ctx, 1); - rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey); - des_set_key(ctx->ctx, rfbkey); - g_free(rfbkey); - - ctx->alg_encrypt_native = des_encrypt_native; - ctx->alg_decrypt_native = des_decrypt_native; - ctx->alg_encrypt_wrapper = des_encrypt_wrapper; - ctx->alg_decrypt_wrapper = des_decrypt_wrapper; - - ctx->blocksize = DES_BLOCK_SIZE; - break; - - case QCRYPTO_CIPHER_ALG_3DES: - ctx->ctx = g_new0(struct des3_ctx, 1); - des3_set_key(ctx->ctx, key); - - ctx->alg_encrypt_native = des3_encrypt_native; - ctx->alg_decrypt_native = des3_decrypt_native; - ctx->alg_encrypt_wrapper = des3_encrypt_wrapper; - ctx->alg_decrypt_wrapper = des3_decrypt_wrapper; - - ctx->blocksize = DES3_BLOCK_SIZE; - break; - - case QCRYPTO_CIPHER_ALG_AES_128: - ctx->ctx = g_new0(QCryptoNettleAES128, 1); - - if (mode == QCRYPTO_CIPHER_MODE_XTS) { - ctx->ctx_tweak = g_new0(QCryptoNettleAES128, 1); - - nkey /= 2; - aes128_set_encrypt_key(&((QCryptoNettleAES128 *)ctx->ctx)->enc, - key); - aes128_set_decrypt_key(&((QCryptoNettleAES128 *)ctx->ctx)->dec, - key); - - aes128_set_encrypt_key(&((QCryptoNettleAES128 *)ctx->ctx_tweak)-> - enc, key + nkey); - aes128_set_decrypt_key(&((QCryptoNettleAES128 *)ctx->ctx_tweak)-> - dec, key + nkey); - } else { - aes128_set_encrypt_key(&((QCryptoNettleAES128 *)ctx->ctx)->enc, - key); - aes128_set_decrypt_key(&((QCryptoNettleAES128 *)ctx->ctx)->dec, - key); - } - - ctx->alg_encrypt_native = aes128_encrypt_native; - ctx->alg_decrypt_native = aes128_decrypt_native; - ctx->alg_encrypt_wrapper = aes128_encrypt_wrapper; - ctx->alg_decrypt_wrapper = aes128_decrypt_wrapper; - - ctx->blocksize = AES_BLOCK_SIZE; - break; - - case QCRYPTO_CIPHER_ALG_AES_192: - ctx->ctx = g_new0(QCryptoNettleAES192, 1); - - if (mode == QCRYPTO_CIPHER_MODE_XTS) { - ctx->ctx_tweak = g_new0(QCryptoNettleAES192, 1); - - nkey /= 2; - aes192_set_encrypt_key(&((QCryptoNettleAES192 *)ctx->ctx)->enc, - key); - aes192_set_decrypt_key(&((QCryptoNettleAES192 *)ctx->ctx)->dec, - key); - - aes192_set_encrypt_key(&((QCryptoNettleAES192 *)ctx->ctx_tweak)-> - enc, key + nkey); - aes192_set_decrypt_key(&((QCryptoNettleAES192 *)ctx->ctx_tweak)-> - dec, key + nkey); - } else { - aes192_set_encrypt_key(&((QCryptoNettleAES192 *)ctx->ctx)->enc, - key); - aes192_set_decrypt_key(&((QCryptoNettleAES192 *)ctx->ctx)->dec, - key); - } - - ctx->alg_encrypt_native = aes192_encrypt_native; - ctx->alg_decrypt_native = aes192_decrypt_native; - ctx->alg_encrypt_wrapper = aes192_encrypt_wrapper; - ctx->alg_decrypt_wrapper = aes192_decrypt_wrapper; - - ctx->blocksize = AES_BLOCK_SIZE; - break; - - case QCRYPTO_CIPHER_ALG_AES_256: - ctx->ctx = g_new0(QCryptoNettleAES256, 1); - - if (mode == QCRYPTO_CIPHER_MODE_XTS) { - ctx->ctx_tweak = g_new0(QCryptoNettleAES256, 1); - - nkey /= 2; - aes256_set_encrypt_key(&((QCryptoNettleAES256 *)ctx->ctx)->enc, - key); - aes256_set_decrypt_key(&((QCryptoNettleAES256 *)ctx->ctx)->dec, - key); - - aes256_set_encrypt_key(&((QCryptoNettleAES256 *)ctx->ctx_tweak)-> - enc, key + nkey); - aes256_set_decrypt_key(&((QCryptoNettleAES256 *)ctx->ctx_tweak)-> - dec, key + nkey); - } else { - aes256_set_encrypt_key(&((QCryptoNettleAES256 *)ctx->ctx)->enc, - key); - aes256_set_decrypt_key(&((QCryptoNettleAES256 *)ctx->ctx)->dec, - key); - } - - ctx->alg_encrypt_native = aes256_encrypt_native; - ctx->alg_decrypt_native = aes256_decrypt_native; - ctx->alg_encrypt_wrapper = aes256_encrypt_wrapper; - ctx->alg_decrypt_wrapper = aes256_decrypt_wrapper; - - ctx->blocksize = AES_BLOCK_SIZE; - break; - - case QCRYPTO_CIPHER_ALG_CAST5_128: - ctx->ctx = g_new0(struct cast128_ctx, 1); - - if (mode == QCRYPTO_CIPHER_MODE_XTS) { - ctx->ctx_tweak = g_new0(struct cast128_ctx, 1); - - nkey /= 2; - cast5_set_key(ctx->ctx, nkey, key); - cast5_set_key(ctx->ctx_tweak, nkey, key + nkey); - } else { - cast5_set_key(ctx->ctx, nkey, key); - } - - ctx->alg_encrypt_native = cast128_encrypt_native; - ctx->alg_decrypt_native = cast128_decrypt_native; - ctx->alg_encrypt_wrapper = cast128_encrypt_wrapper; - ctx->alg_decrypt_wrapper = cast128_decrypt_wrapper; - - ctx->blocksize = CAST128_BLOCK_SIZE; - break; - - case QCRYPTO_CIPHER_ALG_SERPENT_128: - case QCRYPTO_CIPHER_ALG_SERPENT_192: - case QCRYPTO_CIPHER_ALG_SERPENT_256: - ctx->ctx = g_new0(struct serpent_ctx, 1); - - if (mode == QCRYPTO_CIPHER_MODE_XTS) { - ctx->ctx_tweak = g_new0(struct serpent_ctx, 1); - - nkey /= 2; - serpent_set_key(ctx->ctx, nkey, key); - serpent_set_key(ctx->ctx_tweak, nkey, key + nkey); - } else { - serpent_set_key(ctx->ctx, nkey, key); - } - - ctx->alg_encrypt_native = serpent_encrypt_native; - ctx->alg_decrypt_native = serpent_decrypt_native; - ctx->alg_encrypt_wrapper = serpent_encrypt_wrapper; - ctx->alg_decrypt_wrapper = serpent_decrypt_wrapper; - - ctx->blocksize = SERPENT_BLOCK_SIZE; - break; - - case QCRYPTO_CIPHER_ALG_TWOFISH_128: - case QCRYPTO_CIPHER_ALG_TWOFISH_192: - case QCRYPTO_CIPHER_ALG_TWOFISH_256: - ctx->ctx = g_new0(struct twofish_ctx, 1); - - if (mode == QCRYPTO_CIPHER_MODE_XTS) { - ctx->ctx_tweak = g_new0(struct twofish_ctx, 1); - - nkey /= 2; - twofish_set_key(ctx->ctx, nkey, key); - twofish_set_key(ctx->ctx_tweak, nkey, key + nkey); - } else { - twofish_set_key(ctx->ctx, nkey, key); - } - - ctx->alg_encrypt_native = twofish_encrypt_native; - ctx->alg_decrypt_native = twofish_decrypt_native; - ctx->alg_encrypt_wrapper = twofish_encrypt_wrapper; - ctx->alg_decrypt_wrapper = twofish_decrypt_wrapper; - - ctx->blocksize = TWOFISH_BLOCK_SIZE; - break; - - default: - error_setg(errp, "Unsupported cipher algorithm %s", - QCryptoCipherAlgorithm_str(alg)); - goto error; - } - g_assert(is_power_of_2(ctx->blocksize)); - - if (mode == QCRYPTO_CIPHER_MODE_XTS && - ctx->blocksize != XTS_BLOCK_SIZE) { - error_setg(errp, "Cipher block size %zu must equal XTS block size %d", - ctx->blocksize, XTS_BLOCK_SIZE); - goto error; - } - - ctx->iv = g_new0(uint8_t, ctx->blocksize); - - return ctx; - - error: - qcrypto_nettle_cipher_free_ctx(ctx); - return NULL; -} - - -static void -qcrypto_nettle_cipher_ctx_free(QCryptoCipher *cipher) -{ - QCryptoCipherNettle *ctx; - - ctx = cipher->opaque; - qcrypto_nettle_cipher_free_ctx(ctx); -} - - -static int -qcrypto_nettle_cipher_encrypt(QCryptoCipher *cipher, - const void *in, - void *out, - size_t len, - Error **errp) -{ - QCryptoCipherNettle *ctx = cipher->opaque; - - if (len & (ctx->blocksize - 1)) { - error_setg(errp, "Length %zu must be a multiple of block size %zu", - len, ctx->blocksize); - return -1; - } - - switch (cipher->mode) { - case QCRYPTO_CIPHER_MODE_ECB: - ctx->alg_encrypt_wrapper(ctx->ctx, len, out, in); - break; - - case QCRYPTO_CIPHER_MODE_CBC: - cbc_encrypt(ctx->ctx, ctx->alg_encrypt_native, - ctx->blocksize, ctx->iv, - len, out, in); - break; - - case QCRYPTO_CIPHER_MODE_XTS: -#ifdef CONFIG_QEMU_PRIVATE_XTS - xts_encrypt(ctx->ctx, ctx->ctx_tweak, - ctx->alg_encrypt_wrapper, ctx->alg_encrypt_wrapper, - ctx->iv, len, out, in); -#else - xts_encrypt_message(ctx->ctx, ctx->ctx_tweak, - ctx->alg_encrypt_native, - ctx->iv, len, out, in); -#endif - break; - - case QCRYPTO_CIPHER_MODE_CTR: - ctr_crypt(ctx->ctx, ctx->alg_encrypt_native, - ctx->blocksize, ctx->iv, - len, out, in); - break; - - default: - error_setg(errp, "Unsupported cipher mode %s", - QCryptoCipherMode_str(cipher->mode)); - return -1; - } - return 0; -} - - -static int -qcrypto_nettle_cipher_decrypt(QCryptoCipher *cipher, - const void *in, - void *out, - size_t len, - Error **errp) -{ - QCryptoCipherNettle *ctx = cipher->opaque; - - if (len & (ctx->blocksize - 1)) { - error_setg(errp, "Length %zu must be a multiple of block size %zu", - len, ctx->blocksize); - return -1; - } - - switch (cipher->mode) { - case QCRYPTO_CIPHER_MODE_ECB: - ctx->alg_decrypt_wrapper(ctx->ctx, len, out, in); - break; - - case QCRYPTO_CIPHER_MODE_CBC: - cbc_decrypt(ctx->ctx, ctx->alg_decrypt_native, - ctx->blocksize, ctx->iv, - len, out, in); - break; - - case QCRYPTO_CIPHER_MODE_XTS: -#ifdef CONFIG_QEMU_PRIVATE_XTS - xts_decrypt(ctx->ctx, ctx->ctx_tweak, - ctx->alg_encrypt_wrapper, ctx->alg_decrypt_wrapper, - ctx->iv, len, out, in); -#else - xts_decrypt_message(ctx->ctx, ctx->ctx_tweak, - ctx->alg_decrypt_native, - ctx->alg_encrypt_native, - ctx->iv, len, out, in); -#endif - break; - case QCRYPTO_CIPHER_MODE_CTR: - ctr_crypt(ctx->ctx, ctx->alg_encrypt_native, - ctx->blocksize, ctx->iv, - len, out, in); - break; - - default: - error_setg(errp, "Unsupported cipher mode %s", - QCryptoCipherMode_str(cipher->mode)); - return -1; - } - return 0; -} - -static int -qcrypto_nettle_cipher_setiv(QCryptoCipher *cipher, - const uint8_t *iv, size_t niv, - Error **errp) -{ - QCryptoCipherNettle *ctx = cipher->opaque; - if (niv != ctx->blocksize) { - error_setg(errp, "Expected IV size %zu not %zu", - ctx->blocksize, niv); - return -1; - } - memcpy(ctx->iv, iv, niv); - return 0; -} - - -static struct QCryptoCipherDriver qcrypto_cipher_lib_driver = { - .cipher_encrypt = qcrypto_nettle_cipher_encrypt, - .cipher_decrypt = qcrypto_nettle_cipher_decrypt, - .cipher_setiv = qcrypto_nettle_cipher_setiv, - .cipher_free = qcrypto_nettle_cipher_ctx_free, -}; diff --git a/crypto/cipher-nettle.c.inc b/crypto/cipher-nettle.c.inc new file mode 100644 index 0000000000..0677fdfd33 --- /dev/null +++ b/crypto/cipher-nettle.c.inc @@ -0,0 +1,734 @@ +/* + * 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.1 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 "qemu/osdep.h" +#ifdef CONFIG_QEMU_PRIVATE_XTS +#include "crypto/xts.h" +#endif +#include "cipherpriv.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef CONFIG_QEMU_PRIVATE_XTS +#include +#endif + +typedef void (*QCryptoCipherNettleFuncWrapper)(const void *ctx, + size_t length, + uint8_t *dst, + const uint8_t *src); + +#if CONFIG_NETTLE_VERSION_MAJOR < 3 +typedef nettle_crypt_func * QCryptoCipherNettleFuncNative; +typedef void * cipher_ctx_t; +typedef unsigned cipher_length_t; + +#define cast5_set_key cast128_set_key + +#define aes128_ctx aes_ctx +#define aes192_ctx aes_ctx +#define aes256_ctx aes_ctx +#define aes128_set_encrypt_key(c, k) \ + aes_set_encrypt_key(c, 16, k) +#define aes192_set_encrypt_key(c, k) \ + aes_set_encrypt_key(c, 24, k) +#define aes256_set_encrypt_key(c, k) \ + aes_set_encrypt_key(c, 32, k) +#define aes128_set_decrypt_key(c, k) \ + aes_set_decrypt_key(c, 16, k) +#define aes192_set_decrypt_key(c, k) \ + aes_set_decrypt_key(c, 24, k) +#define aes256_set_decrypt_key(c, k) \ + aes_set_decrypt_key(c, 32, k) +#define aes128_encrypt aes_encrypt +#define aes192_encrypt aes_encrypt +#define aes256_encrypt aes_encrypt +#define aes128_decrypt aes_decrypt +#define aes192_decrypt aes_decrypt +#define aes256_decrypt aes_decrypt +#else +typedef nettle_cipher_func * QCryptoCipherNettleFuncNative; +typedef const void * cipher_ctx_t; +typedef size_t cipher_length_t; +#endif + +typedef struct QCryptoNettleAES128 { + struct aes128_ctx enc; + struct aes128_ctx dec; +} QCryptoNettleAES128; + +typedef struct QCryptoNettleAES192 { + struct aes192_ctx enc; + struct aes192_ctx dec; +} QCryptoNettleAES192; + +typedef struct QCryptoNettleAES256 { + struct aes256_ctx enc; + struct aes256_ctx dec; +} QCryptoNettleAES256; + +static void aes128_encrypt_native(cipher_ctx_t ctx, cipher_length_t length, + uint8_t *dst, const uint8_t *src) +{ + const QCryptoNettleAES128 *aesctx = ctx; + aes128_encrypt(&aesctx->enc, length, dst, src); +} + +static void aes128_decrypt_native(cipher_ctx_t ctx, cipher_length_t length, + uint8_t *dst, const uint8_t *src) +{ + const QCryptoNettleAES128 *aesctx = ctx; + aes128_decrypt(&aesctx->dec, length, dst, src); +} + +static void aes192_encrypt_native(cipher_ctx_t ctx, cipher_length_t length, + uint8_t *dst, const uint8_t *src) +{ + const QCryptoNettleAES192 *aesctx = ctx; + aes192_encrypt(&aesctx->enc, length, dst, src); +} + +static void aes192_decrypt_native(cipher_ctx_t ctx, cipher_length_t length, + uint8_t *dst, const uint8_t *src) +{ + const QCryptoNettleAES192 *aesctx = ctx; + aes192_decrypt(&aesctx->dec, length, dst, src); +} + +static void aes256_encrypt_native(cipher_ctx_t ctx, cipher_length_t length, + uint8_t *dst, const uint8_t *src) +{ + const QCryptoNettleAES256 *aesctx = ctx; + aes256_encrypt(&aesctx->enc, length, dst, src); +} + +static void aes256_decrypt_native(cipher_ctx_t ctx, cipher_length_t length, + uint8_t *dst, const uint8_t *src) +{ + const QCryptoNettleAES256 *aesctx = ctx; + aes256_decrypt(&aesctx->dec, length, dst, src); +} + +static void des_encrypt_native(cipher_ctx_t ctx, cipher_length_t length, + uint8_t *dst, const uint8_t *src) +{ + des_encrypt(ctx, length, dst, src); +} + +static void des_decrypt_native(cipher_ctx_t ctx, cipher_length_t length, + uint8_t *dst, const uint8_t *src) +{ + des_decrypt(ctx, length, dst, src); +} + +static void des3_encrypt_native(cipher_ctx_t ctx, cipher_length_t length, + uint8_t *dst, const uint8_t *src) +{ + des3_encrypt(ctx, length, dst, src); +} + +static void des3_decrypt_native(cipher_ctx_t ctx, cipher_length_t length, + uint8_t *dst, const uint8_t *src) +{ + des3_decrypt(ctx, length, dst, src); +} + +static void cast128_encrypt_native(cipher_ctx_t ctx, cipher_length_t length, + uint8_t *dst, const uint8_t *src) +{ + cast128_encrypt(ctx, length, dst, src); +} + +static void cast128_decrypt_native(cipher_ctx_t ctx, cipher_length_t length, + uint8_t *dst, const uint8_t *src) +{ + cast128_decrypt(ctx, length, dst, src); +} + +static void serpent_encrypt_native(cipher_ctx_t ctx, cipher_length_t length, + uint8_t *dst, const uint8_t *src) +{ + serpent_encrypt(ctx, length, dst, src); +} + +static void serpent_decrypt_native(cipher_ctx_t ctx, cipher_length_t length, + uint8_t *dst, const uint8_t *src) +{ + serpent_decrypt(ctx, length, dst, src); +} + +static void twofish_encrypt_native(cipher_ctx_t ctx, cipher_length_t length, + uint8_t *dst, const uint8_t *src) +{ + twofish_encrypt(ctx, length, dst, src); +} + +static void twofish_decrypt_native(cipher_ctx_t ctx, cipher_length_t length, + uint8_t *dst, const uint8_t *src) +{ + twofish_decrypt(ctx, length, dst, src); +} + +static void aes128_encrypt_wrapper(const void *ctx, size_t length, + uint8_t *dst, const uint8_t *src) +{ + const QCryptoNettleAES128 *aesctx = ctx; + aes128_encrypt(&aesctx->enc, length, dst, src); +} + +static void aes128_decrypt_wrapper(const void *ctx, size_t length, + uint8_t *dst, const uint8_t *src) +{ + const QCryptoNettleAES128 *aesctx = ctx; + aes128_decrypt(&aesctx->dec, length, dst, src); +} + +static void aes192_encrypt_wrapper(const void *ctx, size_t length, + uint8_t *dst, const uint8_t *src) +{ + const QCryptoNettleAES192 *aesctx = ctx; + aes192_encrypt(&aesctx->enc, length, dst, src); +} + +static void aes192_decrypt_wrapper(const void *ctx, size_t length, + uint8_t *dst, const uint8_t *src) +{ + const QCryptoNettleAES192 *aesctx = ctx; + aes192_decrypt(&aesctx->dec, length, dst, src); +} + +static void aes256_encrypt_wrapper(const void *ctx, size_t length, + uint8_t *dst, const uint8_t *src) +{ + const QCryptoNettleAES256 *aesctx = ctx; + aes256_encrypt(&aesctx->enc, length, dst, src); +} + +static void aes256_decrypt_wrapper(const void *ctx, size_t length, + uint8_t *dst, const uint8_t *src) +{ + const QCryptoNettleAES256 *aesctx = ctx; + aes256_decrypt(&aesctx->dec, length, dst, src); +} + +static void des_encrypt_wrapper(const void *ctx, size_t length, + uint8_t *dst, const uint8_t *src) +{ + des_encrypt(ctx, length, dst, src); +} + +static void des_decrypt_wrapper(const void *ctx, size_t length, + uint8_t *dst, const uint8_t *src) +{ + des_decrypt(ctx, length, dst, src); +} + +static void des3_encrypt_wrapper(const void *ctx, size_t length, + uint8_t *dst, const uint8_t *src) +{ + des3_encrypt(ctx, length, dst, src); +} + +static void des3_decrypt_wrapper(const void *ctx, size_t length, + uint8_t *dst, const uint8_t *src) +{ + des3_decrypt(ctx, length, dst, src); +} + +static void cast128_encrypt_wrapper(const void *ctx, size_t length, + uint8_t *dst, const uint8_t *src) +{ + cast128_encrypt(ctx, length, dst, src); +} + +static void cast128_decrypt_wrapper(const void *ctx, size_t length, + uint8_t *dst, const uint8_t *src) +{ + cast128_decrypt(ctx, length, dst, src); +} + +static void serpent_encrypt_wrapper(const void *ctx, size_t length, + uint8_t *dst, const uint8_t *src) +{ + serpent_encrypt(ctx, length, dst, src); +} + +static void serpent_decrypt_wrapper(const void *ctx, size_t length, + uint8_t *dst, const uint8_t *src) +{ + serpent_decrypt(ctx, length, dst, src); +} + +static void twofish_encrypt_wrapper(const void *ctx, size_t length, + uint8_t *dst, const uint8_t *src) +{ + twofish_encrypt(ctx, length, dst, src); +} + +static void twofish_decrypt_wrapper(const void *ctx, size_t length, + uint8_t *dst, const uint8_t *src) +{ + twofish_decrypt(ctx, length, dst, src); +} + +typedef struct QCryptoCipherNettle QCryptoCipherNettle; +struct QCryptoCipherNettle { + /* Primary cipher context for all modes */ + void *ctx; + /* Second cipher context for XTS mode only */ + void *ctx_tweak; + /* Cipher callbacks for both contexts */ + QCryptoCipherNettleFuncNative alg_encrypt_native; + QCryptoCipherNettleFuncNative alg_decrypt_native; + QCryptoCipherNettleFuncWrapper alg_encrypt_wrapper; + QCryptoCipherNettleFuncWrapper alg_decrypt_wrapper; + /* Initialization vector or Counter */ + uint8_t *iv; + size_t blocksize; +}; + +bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg, + QCryptoCipherMode mode) +{ + switch (alg) { + case QCRYPTO_CIPHER_ALG_DES_RFB: + case QCRYPTO_CIPHER_ALG_3DES: + case QCRYPTO_CIPHER_ALG_AES_128: + case QCRYPTO_CIPHER_ALG_AES_192: + case QCRYPTO_CIPHER_ALG_AES_256: + case QCRYPTO_CIPHER_ALG_CAST5_128: + case QCRYPTO_CIPHER_ALG_SERPENT_128: + case QCRYPTO_CIPHER_ALG_SERPENT_192: + case QCRYPTO_CIPHER_ALG_SERPENT_256: + case QCRYPTO_CIPHER_ALG_TWOFISH_128: + case QCRYPTO_CIPHER_ALG_TWOFISH_192: + case QCRYPTO_CIPHER_ALG_TWOFISH_256: + break; + default: + return false; + } + + switch (mode) { + case QCRYPTO_CIPHER_MODE_ECB: + case QCRYPTO_CIPHER_MODE_CBC: + case QCRYPTO_CIPHER_MODE_XTS: + case QCRYPTO_CIPHER_MODE_CTR: + return true; + default: + return false; + } +} + + +static void +qcrypto_nettle_cipher_free_ctx(QCryptoCipherNettle *ctx) +{ + if (!ctx) { + return; + } + + g_free(ctx->iv); + g_free(ctx->ctx); + g_free(ctx->ctx_tweak); + g_free(ctx); +} + + +static QCryptoCipherNettle *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg, + QCryptoCipherMode mode, + const uint8_t *key, + size_t nkey, + Error **errp) +{ + QCryptoCipherNettle *ctx; + uint8_t *rfbkey; + + switch (mode) { + case QCRYPTO_CIPHER_MODE_ECB: + case QCRYPTO_CIPHER_MODE_CBC: + case QCRYPTO_CIPHER_MODE_XTS: + case QCRYPTO_CIPHER_MODE_CTR: + break; + default: + error_setg(errp, "Unsupported cipher mode %s", + QCryptoCipherMode_str(mode)); + return NULL; + } + + if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) { + return NULL; + } + + ctx = g_new0(QCryptoCipherNettle, 1); + + switch (alg) { + case QCRYPTO_CIPHER_ALG_DES_RFB: + ctx->ctx = g_new0(struct des_ctx, 1); + rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey); + des_set_key(ctx->ctx, rfbkey); + g_free(rfbkey); + + ctx->alg_encrypt_native = des_encrypt_native; + ctx->alg_decrypt_native = des_decrypt_native; + ctx->alg_encrypt_wrapper = des_encrypt_wrapper; + ctx->alg_decrypt_wrapper = des_decrypt_wrapper; + + ctx->blocksize = DES_BLOCK_SIZE; + break; + + case QCRYPTO_CIPHER_ALG_3DES: + ctx->ctx = g_new0(struct des3_ctx, 1); + des3_set_key(ctx->ctx, key); + + ctx->alg_encrypt_native = des3_encrypt_native; + ctx->alg_decrypt_native = des3_decrypt_native; + ctx->alg_encrypt_wrapper = des3_encrypt_wrapper; + ctx->alg_decrypt_wrapper = des3_decrypt_wrapper; + + ctx->blocksize = DES3_BLOCK_SIZE; + break; + + case QCRYPTO_CIPHER_ALG_AES_128: + ctx->ctx = g_new0(QCryptoNettleAES128, 1); + + if (mode == QCRYPTO_CIPHER_MODE_XTS) { + ctx->ctx_tweak = g_new0(QCryptoNettleAES128, 1); + + nkey /= 2; + aes128_set_encrypt_key(&((QCryptoNettleAES128 *)ctx->ctx)->enc, + key); + aes128_set_decrypt_key(&((QCryptoNettleAES128 *)ctx->ctx)->dec, + key); + + aes128_set_encrypt_key(&((QCryptoNettleAES128 *)ctx->ctx_tweak)-> + enc, key + nkey); + aes128_set_decrypt_key(&((QCryptoNettleAES128 *)ctx->ctx_tweak)-> + dec, key + nkey); + } else { + aes128_set_encrypt_key(&((QCryptoNettleAES128 *)ctx->ctx)->enc, + key); + aes128_set_decrypt_key(&((QCryptoNettleAES128 *)ctx->ctx)->dec, + key); + } + + ctx->alg_encrypt_native = aes128_encrypt_native; + ctx->alg_decrypt_native = aes128_decrypt_native; + ctx->alg_encrypt_wrapper = aes128_encrypt_wrapper; + ctx->alg_decrypt_wrapper = aes128_decrypt_wrapper; + + ctx->blocksize = AES_BLOCK_SIZE; + break; + + case QCRYPTO_CIPHER_ALG_AES_192: + ctx->ctx = g_new0(QCryptoNettleAES192, 1); + + if (mode == QCRYPTO_CIPHER_MODE_XTS) { + ctx->ctx_tweak = g_new0(QCryptoNettleAES192, 1); + + nkey /= 2; + aes192_set_encrypt_key(&((QCryptoNettleAES192 *)ctx->ctx)->enc, + key); + aes192_set_decrypt_key(&((QCryptoNettleAES192 *)ctx->ctx)->dec, + key); + + aes192_set_encrypt_key(&((QCryptoNettleAES192 *)ctx->ctx_tweak)-> + enc, key + nkey); + aes192_set_decrypt_key(&((QCryptoNettleAES192 *)ctx->ctx_tweak)-> + dec, key + nkey); + } else { + aes192_set_encrypt_key(&((QCryptoNettleAES192 *)ctx->ctx)->enc, + key); + aes192_set_decrypt_key(&((QCryptoNettleAES192 *)ctx->ctx)->dec, + key); + } + + ctx->alg_encrypt_native = aes192_encrypt_native; + ctx->alg_decrypt_native = aes192_decrypt_native; + ctx->alg_encrypt_wrapper = aes192_encrypt_wrapper; + ctx->alg_decrypt_wrapper = aes192_decrypt_wrapper; + + ctx->blocksize = AES_BLOCK_SIZE; + break; + + case QCRYPTO_CIPHER_ALG_AES_256: + ctx->ctx = g_new0(QCryptoNettleAES256, 1); + + if (mode == QCRYPTO_CIPHER_MODE_XTS) { + ctx->ctx_tweak = g_new0(QCryptoNettleAES256, 1); + + nkey /= 2; + aes256_set_encrypt_key(&((QCryptoNettleAES256 *)ctx->ctx)->enc, + key); + aes256_set_decrypt_key(&((QCryptoNettleAES256 *)ctx->ctx)->dec, + key); + + aes256_set_encrypt_key(&((QCryptoNettleAES256 *)ctx->ctx_tweak)-> + enc, key + nkey); + aes256_set_decrypt_key(&((QCryptoNettleAES256 *)ctx->ctx_tweak)-> + dec, key + nkey); + } else { + aes256_set_encrypt_key(&((QCryptoNettleAES256 *)ctx->ctx)->enc, + key); + aes256_set_decrypt_key(&((QCryptoNettleAES256 *)ctx->ctx)->dec, + key); + } + + ctx->alg_encrypt_native = aes256_encrypt_native; + ctx->alg_decrypt_native = aes256_decrypt_native; + ctx->alg_encrypt_wrapper = aes256_encrypt_wrapper; + ctx->alg_decrypt_wrapper = aes256_decrypt_wrapper; + + ctx->blocksize = AES_BLOCK_SIZE; + break; + + case QCRYPTO_CIPHER_ALG_CAST5_128: + ctx->ctx = g_new0(struct cast128_ctx, 1); + + if (mode == QCRYPTO_CIPHER_MODE_XTS) { + ctx->ctx_tweak = g_new0(struct cast128_ctx, 1); + + nkey /= 2; + cast5_set_key(ctx->ctx, nkey, key); + cast5_set_key(ctx->ctx_tweak, nkey, key + nkey); + } else { + cast5_set_key(ctx->ctx, nkey, key); + } + + ctx->alg_encrypt_native = cast128_encrypt_native; + ctx->alg_decrypt_native = cast128_decrypt_native; + ctx->alg_encrypt_wrapper = cast128_encrypt_wrapper; + ctx->alg_decrypt_wrapper = cast128_decrypt_wrapper; + + ctx->blocksize = CAST128_BLOCK_SIZE; + break; + + case QCRYPTO_CIPHER_ALG_SERPENT_128: + case QCRYPTO_CIPHER_ALG_SERPENT_192: + case QCRYPTO_CIPHER_ALG_SERPENT_256: + ctx->ctx = g_new0(struct serpent_ctx, 1); + + if (mode == QCRYPTO_CIPHER_MODE_XTS) { + ctx->ctx_tweak = g_new0(struct serpent_ctx, 1); + + nkey /= 2; + serpent_set_key(ctx->ctx, nkey, key); + serpent_set_key(ctx->ctx_tweak, nkey, key + nkey); + } else { + serpent_set_key(ctx->ctx, nkey, key); + } + + ctx->alg_encrypt_native = serpent_encrypt_native; + ctx->alg_decrypt_native = serpent_decrypt_native; + ctx->alg_encrypt_wrapper = serpent_encrypt_wrapper; + ctx->alg_decrypt_wrapper = serpent_decrypt_wrapper; + + ctx->blocksize = SERPENT_BLOCK_SIZE; + break; + + case QCRYPTO_CIPHER_ALG_TWOFISH_128: + case QCRYPTO_CIPHER_ALG_TWOFISH_192: + case QCRYPTO_CIPHER_ALG_TWOFISH_256: + ctx->ctx = g_new0(struct twofish_ctx, 1); + + if (mode == QCRYPTO_CIPHER_MODE_XTS) { + ctx->ctx_tweak = g_new0(struct twofish_ctx, 1); + + nkey /= 2; + twofish_set_key(ctx->ctx, nkey, key); + twofish_set_key(ctx->ctx_tweak, nkey, key + nkey); + } else { + twofish_set_key(ctx->ctx, nkey, key); + } + + ctx->alg_encrypt_native = twofish_encrypt_native; + ctx->alg_decrypt_native = twofish_decrypt_native; + ctx->alg_encrypt_wrapper = twofish_encrypt_wrapper; + ctx->alg_decrypt_wrapper = twofish_decrypt_wrapper; + + ctx->blocksize = TWOFISH_BLOCK_SIZE; + break; + + default: + error_setg(errp, "Unsupported cipher algorithm %s", + QCryptoCipherAlgorithm_str(alg)); + goto error; + } + g_assert(is_power_of_2(ctx->blocksize)); + + if (mode == QCRYPTO_CIPHER_MODE_XTS && + ctx->blocksize != XTS_BLOCK_SIZE) { + error_setg(errp, "Cipher block size %zu must equal XTS block size %d", + ctx->blocksize, XTS_BLOCK_SIZE); + goto error; + } + + ctx->iv = g_new0(uint8_t, ctx->blocksize); + + return ctx; + + error: + qcrypto_nettle_cipher_free_ctx(ctx); + return NULL; +} + + +static void +qcrypto_nettle_cipher_ctx_free(QCryptoCipher *cipher) +{ + QCryptoCipherNettle *ctx; + + ctx = cipher->opaque; + qcrypto_nettle_cipher_free_ctx(ctx); +} + + +static int +qcrypto_nettle_cipher_encrypt(QCryptoCipher *cipher, + const void *in, + void *out, + size_t len, + Error **errp) +{ + QCryptoCipherNettle *ctx = cipher->opaque; + + if (len & (ctx->blocksize - 1)) { + error_setg(errp, "Length %zu must be a multiple of block size %zu", + len, ctx->blocksize); + return -1; + } + + switch (cipher->mode) { + case QCRYPTO_CIPHER_MODE_ECB: + ctx->alg_encrypt_wrapper(ctx->ctx, len, out, in); + break; + + case QCRYPTO_CIPHER_MODE_CBC: + cbc_encrypt(ctx->ctx, ctx->alg_encrypt_native, + ctx->blocksize, ctx->iv, + len, out, in); + break; + + case QCRYPTO_CIPHER_MODE_XTS: +#ifdef CONFIG_QEMU_PRIVATE_XTS + xts_encrypt(ctx->ctx, ctx->ctx_tweak, + ctx->alg_encrypt_wrapper, ctx->alg_encrypt_wrapper, + ctx->iv, len, out, in); +#else + xts_encrypt_message(ctx->ctx, ctx->ctx_tweak, + ctx->alg_encrypt_native, + ctx->iv, len, out, in); +#endif + break; + + case QCRYPTO_CIPHER_MODE_CTR: + ctr_crypt(ctx->ctx, ctx->alg_encrypt_native, + ctx->blocksize, ctx->iv, + len, out, in); + break; + + default: + error_setg(errp, "Unsupported cipher mode %s", + QCryptoCipherMode_str(cipher->mode)); + return -1; + } + return 0; +} + + +static int +qcrypto_nettle_cipher_decrypt(QCryptoCipher *cipher, + const void *in, + void *out, + size_t len, + Error **errp) +{ + QCryptoCipherNettle *ctx = cipher->opaque; + + if (len & (ctx->blocksize - 1)) { + error_setg(errp, "Length %zu must be a multiple of block size %zu", + len, ctx->blocksize); + return -1; + } + + switch (cipher->mode) { + case QCRYPTO_CIPHER_MODE_ECB: + ctx->alg_decrypt_wrapper(ctx->ctx, len, out, in); + break; + + case QCRYPTO_CIPHER_MODE_CBC: + cbc_decrypt(ctx->ctx, ctx->alg_decrypt_native, + ctx->blocksize, ctx->iv, + len, out, in); + break; + + case QCRYPTO_CIPHER_MODE_XTS: +#ifdef CONFIG_QEMU_PRIVATE_XTS + xts_decrypt(ctx->ctx, ctx->ctx_tweak, + ctx->alg_encrypt_wrapper, ctx->alg_decrypt_wrapper, + ctx->iv, len, out, in); +#else + xts_decrypt_message(ctx->ctx, ctx->ctx_tweak, + ctx->alg_decrypt_native, + ctx->alg_encrypt_native, + ctx->iv, len, out, in); +#endif + break; + case QCRYPTO_CIPHER_MODE_CTR: + ctr_crypt(ctx->ctx, ctx->alg_encrypt_native, + ctx->blocksize, ctx->iv, + len, out, in); + break; + + default: + error_setg(errp, "Unsupported cipher mode %s", + QCryptoCipherMode_str(cipher->mode)); + return -1; + } + return 0; +} + +static int +qcrypto_nettle_cipher_setiv(QCryptoCipher *cipher, + const uint8_t *iv, size_t niv, + Error **errp) +{ + QCryptoCipherNettle *ctx = cipher->opaque; + if (niv != ctx->blocksize) { + error_setg(errp, "Expected IV size %zu not %zu", + ctx->blocksize, niv); + return -1; + } + memcpy(ctx->iv, iv, niv); + return 0; +} + + +static struct QCryptoCipherDriver qcrypto_cipher_lib_driver = { + .cipher_encrypt = qcrypto_nettle_cipher_encrypt, + .cipher_decrypt = qcrypto_nettle_cipher_decrypt, + .cipher_setiv = qcrypto_nettle_cipher_setiv, + .cipher_free = qcrypto_nettle_cipher_ctx_free, +}; diff --git a/crypto/cipher.c b/crypto/cipher.c index 2722dc7d87..005b5da4de 100644 --- a/crypto/cipher.c +++ b/crypto/cipher.c @@ -151,11 +151,11 @@ qcrypto_cipher_munge_des_rfb_key(const uint8_t *key, #endif /* CONFIG_GCRYPT || CONFIG_NETTLE */ #ifdef CONFIG_GCRYPT -#include "cipher-gcrypt.c" +#include "cipher-gcrypt.c.inc" #elif defined CONFIG_NETTLE -#include "cipher-nettle.c" +#include "cipher-nettle.c.inc" #else -#include "cipher-builtin.c" +#include "cipher-builtin.c.inc" #endif QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,