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é <philmd@redhat.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
+++ /dev/null
-/*
- * 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 <http://www.gnu.org/licenses/>.
- *
- */
-
-#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,
-};
--- /dev/null
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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,
+};
+++ /dev/null
-/*
- * 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 <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "qemu/osdep.h"
-#ifdef CONFIG_QEMU_PRIVATE_XTS
-#include "crypto/xts.h"
-#endif
-#include "cipherpriv.h"
-
-#include <gcrypt.h>
-
-
-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,
-};
--- /dev/null
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "qemu/osdep.h"
+#ifdef CONFIG_QEMU_PRIVATE_XTS
+#include "crypto/xts.h"
+#endif
+#include "cipherpriv.h"
+
+#include <gcrypt.h>
+
+
+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,
+};
+++ /dev/null
-/*
- * 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 <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "qemu/osdep.h"
-#ifdef CONFIG_QEMU_PRIVATE_XTS
-#include "crypto/xts.h"
-#endif
-#include "cipherpriv.h"
-
-#include <nettle/nettle-types.h>
-#include <nettle/aes.h>
-#include <nettle/des.h>
-#include <nettle/cbc.h>
-#include <nettle/cast128.h>
-#include <nettle/serpent.h>
-#include <nettle/twofish.h>
-#include <nettle/ctr.h>
-#ifndef CONFIG_QEMU_PRIVATE_XTS
-#include <nettle/xts.h>
-#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,
-};
--- /dev/null
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "qemu/osdep.h"
+#ifdef CONFIG_QEMU_PRIVATE_XTS
+#include "crypto/xts.h"
+#endif
+#include "cipherpriv.h"
+
+#include <nettle/nettle-types.h>
+#include <nettle/aes.h>
+#include <nettle/des.h>
+#include <nettle/cbc.h>
+#include <nettle/cast128.h>
+#include <nettle/serpent.h>
+#include <nettle/twofish.h>
+#include <nettle/ctr.h>
+#ifndef CONFIG_QEMU_PRIVATE_XTS
+#include <nettle/xts.h>
+#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,
+};
#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,