mirror of https://github.com/xemu-project/xemu.git
Improve performance of crypto cipher subsystem
-----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEE2vOm/bJrYpEtDo4/vobrtBUQT98FAl9Z+l4ACgkQvobrtBUQ T99GMBAAqfNF+1ItW5sbXqfH/drd88zFSsD/L5+FXgj7CP7iPC77NlWE3AZXDQPd cp+UOM7qwStC3mJCeVRaHoNpH5rmnm3FSDV6cFOs6iXetrHD4tRGdGOvLFJCzaNK qJemosFoO/5+yKx8d5XP/xxHf1y7Vt1JBUmO4C9RNvdIB0ZpUNwAJB/xKEvjVgFq OKZE39HBKNOcFRx1n9VKSvuEW/LBOf9T+eWZ90NdLKZ02EKow0AF1LVlfbVChi5l 2nUzHwd53CsPVtaXplrU2ZFgh/CX2WbzE+XsNzQHFeHKeq+4z2c6NkFCoOUSGEvO ga7VdxiLBqGD/WMYga4/caxtBzHxUIXBvb8Z/KbUuhU6oZ90ml7wirZVK1DvWcwc IupySboWRqYMLATQvfnndIzLOyLtvtuwNXLQG8AeFQ2Lou3XjIK3Ebw8fwTgG0+J E9aT9W+YYtB9bS9VaxlBVnJtqpernF0twYTCRZTV58bYtbp9VGAzdJXMBN11SFhJ umAa27AS5966ypjWRl/OPp2RLAfXMkNjTNA4hNP2XZ/qiZCAMKDGK3rfV4eE8krk 7OUQdM5z540hPBm9yHJrGFkMRh+nfivufngRUrFxAEqLtuvkU2OAjD7x9E2nLrXI zOtGH+1B3+5QYFz68pS/ZQJHavKc7+4SgqnV1eCnT1ztoTo/jqY= =emNx -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/berrange-gitlab/tags/crypt-perf-pull-request' into staging Improve performance of crypto cipher subsystem # gpg: Signature made Thu 10 Sep 2020 11:05:18 BST # gpg: using RSA key DAF3A6FDB26B62912D0E8E3FBE86EBB415104FDF # gpg: Good signature from "Daniel P. Berrange <dan@berrange.com>" [full] # gpg: aka "Daniel P. Berrange <berrange@redhat.com>" [full] # Primary key fingerprint: DAF3 A6FD B26B 6291 2D0E 8E3F BE86 EBB4 1510 4FDF * remotes/berrange-gitlab/tags/crypt-perf-pull-request: crypto/gcrypt: Split QCryptoCipherGcrypt into subclasses crypto/nettle: Split QCryptoCipherNettle into subclasses crypto/builtin: Split QCryptoCipherBuiltin into subclasses crypto/builtin: Split and simplify AES_encrypt_cbc crypto/builtin: Move AES_cbc_encrypt into cipher-builtin.inc.c crypto/builtin: Merge qcrypto_cipher_aes_{ecb,xts}_{en,de}crypt crypto/builtin: Remove odd-sized AES block handling crypto: Constify cipher data tables crypto: Move cipher->driver init to qcrypto_*_cipher_ctx_new crypto: Allocate QCryptoCipher with the subclass crypto: Use the correct const type for driver crypto: Move QCryptoCipherDriver typedef to crypto/cipher.h crypto/nettle: Fix xts_encrypt arguments crypto: Remove redundant includes crypto: Rename cipher include files to .c.inc crypto: Assume blocksize is a power of 2 tests: fix output message formatting for crypto benchmarks Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
c47edb8dda
51
crypto/aes.c
51
crypto/aes.c
|
@ -1599,54 +1599,3 @@ void AES_decrypt(const unsigned char *in, unsigned char *out,
|
|||
}
|
||||
|
||||
#endif /* AES_ASM */
|
||||
|
||||
void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
|
||||
const unsigned long length, const AES_KEY *key,
|
||||
unsigned char *ivec, const int enc)
|
||||
{
|
||||
|
||||
unsigned long n;
|
||||
unsigned long len = length;
|
||||
unsigned char tmp[AES_BLOCK_SIZE];
|
||||
|
||||
assert(in && out && key && ivec);
|
||||
|
||||
if (enc) {
|
||||
while (len >= AES_BLOCK_SIZE) {
|
||||
for(n=0; n < AES_BLOCK_SIZE; ++n)
|
||||
tmp[n] = in[n] ^ ivec[n];
|
||||
AES_encrypt(tmp, out, key);
|
||||
memcpy(ivec, out, AES_BLOCK_SIZE);
|
||||
len -= AES_BLOCK_SIZE;
|
||||
in += AES_BLOCK_SIZE;
|
||||
out += AES_BLOCK_SIZE;
|
||||
}
|
||||
if (len) {
|
||||
for(n=0; n < len; ++n)
|
||||
tmp[n] = in[n] ^ ivec[n];
|
||||
for(n=len; n < AES_BLOCK_SIZE; ++n)
|
||||
tmp[n] = ivec[n];
|
||||
AES_encrypt(tmp, tmp, key);
|
||||
memcpy(out, tmp, AES_BLOCK_SIZE);
|
||||
memcpy(ivec, tmp, AES_BLOCK_SIZE);
|
||||
}
|
||||
} else {
|
||||
while (len >= AES_BLOCK_SIZE) {
|
||||
memcpy(tmp, in, AES_BLOCK_SIZE);
|
||||
AES_decrypt(in, out, key);
|
||||
for(n=0; n < AES_BLOCK_SIZE; ++n)
|
||||
out[n] ^= ivec[n];
|
||||
memcpy(ivec, tmp, AES_BLOCK_SIZE);
|
||||
len -= AES_BLOCK_SIZE;
|
||||
in += AES_BLOCK_SIZE;
|
||||
out += AES_BLOCK_SIZE;
|
||||
}
|
||||
if (len) {
|
||||
memcpy(tmp, in, AES_BLOCK_SIZE);
|
||||
AES_decrypt(tmp, tmp, key);
|
||||
for(n=0; n < len; ++n)
|
||||
out[n] = tmp[n] ^ ivec[n];
|
||||
memcpy(ivec, tmp, AES_BLOCK_SIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#define QCRYPTO_AFALGPRIV_H
|
||||
|
||||
#include <linux/if_alg.h>
|
||||
#include "crypto/cipher.h"
|
||||
|
||||
#define SALG_TYPE_LEN_MAX 14
|
||||
#define SALG_NAME_LEN_MAX 64
|
||||
|
@ -32,6 +33,8 @@
|
|||
typedef struct QCryptoAFAlg QCryptoAFAlg;
|
||||
|
||||
struct QCryptoAFAlg {
|
||||
QCryptoCipher base;
|
||||
|
||||
int tfmfd;
|
||||
int opfd;
|
||||
struct msghdr *msg;
|
||||
|
|
|
@ -58,7 +58,9 @@ qcrypto_afalg_cipher_format_name(QCryptoCipherAlgorithm alg,
|
|||
return name;
|
||||
}
|
||||
|
||||
QCryptoAFAlg *
|
||||
static const struct QCryptoCipherDriver qcrypto_cipher_afalg_driver;
|
||||
|
||||
QCryptoCipher *
|
||||
qcrypto_afalg_cipher_ctx_new(QCryptoCipherAlgorithm alg,
|
||||
QCryptoCipherMode mode,
|
||||
const uint8_t *key,
|
||||
|
@ -109,7 +111,8 @@ qcrypto_afalg_cipher_ctx_new(QCryptoCipherAlgorithm alg,
|
|||
}
|
||||
afalg->cmsg = CMSG_FIRSTHDR(afalg->msg);
|
||||
|
||||
return afalg;
|
||||
afalg->base.driver = &qcrypto_cipher_afalg_driver;
|
||||
return &afalg->base;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -117,9 +120,9 @@ qcrypto_afalg_cipher_setiv(QCryptoCipher *cipher,
|
|||
const uint8_t *iv,
|
||||
size_t niv, Error **errp)
|
||||
{
|
||||
QCryptoAFAlg *afalg = container_of(cipher, QCryptoAFAlg, base);
|
||||
struct af_alg_iv *alg_iv;
|
||||
size_t expect_niv;
|
||||
QCryptoAFAlg *afalg = cipher->opaque;
|
||||
|
||||
expect_niv = qcrypto_cipher_get_iv_len(cipher->alg, cipher->mode);
|
||||
if (niv != expect_niv) {
|
||||
|
@ -200,8 +203,9 @@ qcrypto_afalg_cipher_encrypt(QCryptoCipher *cipher,
|
|||
const void *in, void *out,
|
||||
size_t len, Error **errp)
|
||||
{
|
||||
return qcrypto_afalg_cipher_op(cipher->opaque, in, out,
|
||||
len, true, errp);
|
||||
QCryptoAFAlg *afalg = container_of(cipher, QCryptoAFAlg, base);
|
||||
|
||||
return qcrypto_afalg_cipher_op(afalg, in, out, len, true, errp);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -209,16 +213,19 @@ qcrypto_afalg_cipher_decrypt(QCryptoCipher *cipher,
|
|||
const void *in, void *out,
|
||||
size_t len, Error **errp)
|
||||
{
|
||||
return qcrypto_afalg_cipher_op(cipher->opaque, in, out,
|
||||
len, false, errp);
|
||||
QCryptoAFAlg *afalg = container_of(cipher, QCryptoAFAlg, base);
|
||||
|
||||
return qcrypto_afalg_cipher_op(afalg, in, out, len, false, errp);
|
||||
}
|
||||
|
||||
static void qcrypto_afalg_comm_ctx_free(QCryptoCipher *cipher)
|
||||
{
|
||||
qcrypto_afalg_comm_free(cipher->opaque);
|
||||
QCryptoAFAlg *afalg = container_of(cipher, QCryptoAFAlg, base);
|
||||
|
||||
qcrypto_afalg_comm_free(afalg);
|
||||
}
|
||||
|
||||
struct QCryptoCipherDriver qcrypto_cipher_afalg_driver = {
|
||||
static const struct QCryptoCipherDriver qcrypto_cipher_afalg_driver = {
|
||||
.cipher_encrypt = qcrypto_afalg_cipher_encrypt,
|
||||
.cipher_decrypt = qcrypto_afalg_cipher_decrypt,
|
||||
.cipher_setiv = qcrypto_afalg_cipher_setiv,
|
||||
|
|
|
@ -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 <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) {
|
||||
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) {
|
||||
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,
|
||||
};
|
|
@ -0,0 +1,435 @@
|
|||
/*
|
||||
* 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 "crypto/aes.h"
|
||||
#include "crypto/desrfb.h"
|
||||
#include "crypto/xts.h"
|
||||
|
||||
typedef struct QCryptoCipherBuiltinAESContext QCryptoCipherBuiltinAESContext;
|
||||
struct QCryptoCipherBuiltinAESContext {
|
||||
AES_KEY enc;
|
||||
AES_KEY dec;
|
||||
};
|
||||
|
||||
typedef struct QCryptoCipherBuiltinAES QCryptoCipherBuiltinAES;
|
||||
struct QCryptoCipherBuiltinAES {
|
||||
QCryptoCipher base;
|
||||
QCryptoCipherBuiltinAESContext key;
|
||||
QCryptoCipherBuiltinAESContext key_tweak;
|
||||
uint8_t iv[AES_BLOCK_SIZE];
|
||||
};
|
||||
|
||||
|
||||
static inline bool qcrypto_length_check(size_t len, size_t blocksize,
|
||||
Error **errp)
|
||||
{
|
||||
if (unlikely(len & (blocksize - 1))) {
|
||||
error_setg(errp, "Length %zu must be a multiple of block size %zu",
|
||||
len, blocksize);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void qcrypto_cipher_ctx_free(QCryptoCipher *cipher)
|
||||
{
|
||||
g_free(cipher);
|
||||
}
|
||||
|
||||
static int qcrypto_cipher_no_setiv(QCryptoCipher *cipher,
|
||||
const uint8_t *iv, size_t niv,
|
||||
Error **errp)
|
||||
{
|
||||
error_setg(errp, "Setting IV is not supported");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void do_aes_encrypt_ecb(const void *vctx,
|
||||
size_t len,
|
||||
uint8_t *out,
|
||||
const uint8_t *in)
|
||||
{
|
||||
const QCryptoCipherBuiltinAESContext *ctx = vctx;
|
||||
|
||||
/* We have already verified that len % AES_BLOCK_SIZE == 0. */
|
||||
while (len) {
|
||||
AES_encrypt(in, out, &ctx->enc);
|
||||
in += AES_BLOCK_SIZE;
|
||||
out += AES_BLOCK_SIZE;
|
||||
len -= AES_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
static void do_aes_decrypt_ecb(const void *vctx,
|
||||
size_t len,
|
||||
uint8_t *out,
|
||||
const uint8_t *in)
|
||||
{
|
||||
const QCryptoCipherBuiltinAESContext *ctx = vctx;
|
||||
|
||||
/* We have already verified that len % AES_BLOCK_SIZE == 0. */
|
||||
while (len) {
|
||||
AES_decrypt(in, out, &ctx->dec);
|
||||
in += AES_BLOCK_SIZE;
|
||||
out += AES_BLOCK_SIZE;
|
||||
len -= AES_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
static void do_aes_encrypt_cbc(const AES_KEY *key,
|
||||
size_t len,
|
||||
uint8_t *out,
|
||||
const uint8_t *in,
|
||||
uint8_t *ivec)
|
||||
{
|
||||
uint8_t tmp[AES_BLOCK_SIZE];
|
||||
size_t n;
|
||||
|
||||
/* We have already verified that len % AES_BLOCK_SIZE == 0. */
|
||||
while (len) {
|
||||
for (n = 0; n < AES_BLOCK_SIZE; ++n) {
|
||||
tmp[n] = in[n] ^ ivec[n];
|
||||
}
|
||||
AES_encrypt(tmp, out, key);
|
||||
memcpy(ivec, out, AES_BLOCK_SIZE);
|
||||
len -= AES_BLOCK_SIZE;
|
||||
in += AES_BLOCK_SIZE;
|
||||
out += AES_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
static void do_aes_decrypt_cbc(const AES_KEY *key,
|
||||
size_t len,
|
||||
uint8_t *out,
|
||||
const uint8_t *in,
|
||||
uint8_t *ivec)
|
||||
{
|
||||
uint8_t tmp[AES_BLOCK_SIZE];
|
||||
size_t n;
|
||||
|
||||
/* We have already verified that len % AES_BLOCK_SIZE == 0. */
|
||||
while (len) {
|
||||
memcpy(tmp, in, AES_BLOCK_SIZE);
|
||||
AES_decrypt(in, out, key);
|
||||
for (n = 0; n < AES_BLOCK_SIZE; ++n) {
|
||||
out[n] ^= ivec[n];
|
||||
}
|
||||
memcpy(ivec, tmp, AES_BLOCK_SIZE);
|
||||
len -= AES_BLOCK_SIZE;
|
||||
in += AES_BLOCK_SIZE;
|
||||
out += AES_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
static int qcrypto_cipher_aes_encrypt_ecb(QCryptoCipher *cipher,
|
||||
const void *in, void *out,
|
||||
size_t len, Error **errp)
|
||||
{
|
||||
QCryptoCipherBuiltinAES *ctx
|
||||
= container_of(cipher, QCryptoCipherBuiltinAES, base);
|
||||
|
||||
if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) {
|
||||
return -1;
|
||||
}
|
||||
do_aes_encrypt_ecb(&ctx->key, len, out, in);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcrypto_cipher_aes_decrypt_ecb(QCryptoCipher *cipher,
|
||||
const void *in, void *out,
|
||||
size_t len, Error **errp)
|
||||
{
|
||||
QCryptoCipherBuiltinAES *ctx
|
||||
= container_of(cipher, QCryptoCipherBuiltinAES, base);
|
||||
|
||||
if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) {
|
||||
return -1;
|
||||
}
|
||||
do_aes_decrypt_ecb(&ctx->key, len, out, in);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcrypto_cipher_aes_encrypt_cbc(QCryptoCipher *cipher,
|
||||
const void *in, void *out,
|
||||
size_t len, Error **errp)
|
||||
{
|
||||
QCryptoCipherBuiltinAES *ctx
|
||||
= container_of(cipher, QCryptoCipherBuiltinAES, base);
|
||||
|
||||
if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) {
|
||||
return -1;
|
||||
}
|
||||
do_aes_encrypt_cbc(&ctx->key.enc, len, out, in, ctx->iv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcrypto_cipher_aes_decrypt_cbc(QCryptoCipher *cipher,
|
||||
const void *in, void *out,
|
||||
size_t len, Error **errp)
|
||||
{
|
||||
QCryptoCipherBuiltinAES *ctx
|
||||
= container_of(cipher, QCryptoCipherBuiltinAES, base);
|
||||
|
||||
if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) {
|
||||
return -1;
|
||||
}
|
||||
do_aes_decrypt_cbc(&ctx->key.dec, len, out, in, ctx->iv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcrypto_cipher_aes_encrypt_xts(QCryptoCipher *cipher,
|
||||
const void *in, void *out,
|
||||
size_t len, Error **errp)
|
||||
{
|
||||
QCryptoCipherBuiltinAES *ctx
|
||||
= container_of(cipher, QCryptoCipherBuiltinAES, base);
|
||||
|
||||
if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) {
|
||||
return -1;
|
||||
}
|
||||
xts_encrypt(&ctx->key, &ctx->key_tweak,
|
||||
do_aes_encrypt_ecb, do_aes_decrypt_ecb,
|
||||
ctx->iv, len, out, in);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcrypto_cipher_aes_decrypt_xts(QCryptoCipher *cipher,
|
||||
const void *in, void *out,
|
||||
size_t len, Error **errp)
|
||||
{
|
||||
QCryptoCipherBuiltinAES *ctx
|
||||
= container_of(cipher, QCryptoCipherBuiltinAES, base);
|
||||
|
||||
if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) {
|
||||
return -1;
|
||||
}
|
||||
xts_decrypt(&ctx->key, &ctx->key_tweak,
|
||||
do_aes_encrypt_ecb, do_aes_decrypt_ecb,
|
||||
ctx->iv, len, out, in);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int qcrypto_cipher_aes_setiv(QCryptoCipher *cipher, const uint8_t *iv,
|
||||
size_t niv, Error **errp)
|
||||
{
|
||||
QCryptoCipherBuiltinAES *ctx
|
||||
= container_of(cipher, QCryptoCipherBuiltinAES, base);
|
||||
|
||||
if (niv != AES_BLOCK_SIZE) {
|
||||
error_setg(errp, "IV must be %d bytes not %zu",
|
||||
AES_BLOCK_SIZE, niv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(ctx->iv, iv, AES_BLOCK_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct QCryptoCipherDriver qcrypto_cipher_aes_driver_ecb = {
|
||||
.cipher_encrypt = qcrypto_cipher_aes_encrypt_ecb,
|
||||
.cipher_decrypt = qcrypto_cipher_aes_decrypt_ecb,
|
||||
.cipher_setiv = qcrypto_cipher_no_setiv,
|
||||
.cipher_free = qcrypto_cipher_ctx_free,
|
||||
};
|
||||
|
||||
static const struct QCryptoCipherDriver qcrypto_cipher_aes_driver_cbc = {
|
||||
.cipher_encrypt = qcrypto_cipher_aes_encrypt_cbc,
|
||||
.cipher_decrypt = qcrypto_cipher_aes_decrypt_cbc,
|
||||
.cipher_setiv = qcrypto_cipher_aes_setiv,
|
||||
.cipher_free = qcrypto_cipher_ctx_free,
|
||||
};
|
||||
|
||||
static const struct QCryptoCipherDriver qcrypto_cipher_aes_driver_xts = {
|
||||
.cipher_encrypt = qcrypto_cipher_aes_encrypt_xts,
|
||||
.cipher_decrypt = qcrypto_cipher_aes_decrypt_xts,
|
||||
.cipher_setiv = qcrypto_cipher_aes_setiv,
|
||||
.cipher_free = qcrypto_cipher_ctx_free,
|
||||
};
|
||||
|
||||
|
||||
typedef struct QCryptoCipherBuiltinDESRFB QCryptoCipherBuiltinDESRFB;
|
||||
struct QCryptoCipherBuiltinDESRFB {
|
||||
QCryptoCipher base;
|
||||
|
||||
/* C.f. alg_key_len[QCRYPTO_CIPHER_ALG_DES_RFB] */
|
||||
uint8_t key[8];
|
||||
};
|
||||
|
||||
static int qcrypto_cipher_encrypt_des_rfb(QCryptoCipher *cipher,
|
||||
const void *in, void *out,
|
||||
size_t len, Error **errp)
|
||||
{
|
||||
QCryptoCipherBuiltinDESRFB *ctx
|
||||
= container_of(cipher, QCryptoCipherBuiltinDESRFB, base);
|
||||
size_t i;
|
||||
|
||||
if (!qcrypto_length_check(len, 8, errp)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
deskey(ctx->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)
|
||||
{
|
||||
QCryptoCipherBuiltinDESRFB *ctx
|
||||
= container_of(cipher, QCryptoCipherBuiltinDESRFB, base);
|
||||
size_t i;
|
||||
|
||||
if (!qcrypto_length_check(len, 8, errp)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
deskey(ctx->key, DE1);
|
||||
|
||||
for (i = 0; i < len; i += 8) {
|
||||
des((void *)in + i, out + i);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct QCryptoCipherDriver qcrypto_cipher_des_rfb_driver = {
|
||||
.cipher_encrypt = qcrypto_cipher_encrypt_des_rfb,
|
||||
.cipher_decrypt = qcrypto_cipher_decrypt_des_rfb,
|
||||
.cipher_setiv = qcrypto_cipher_no_setiv,
|
||||
.cipher_free = qcrypto_cipher_ctx_free,
|
||||
};
|
||||
|
||||
bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
|
||||
QCryptoCipherMode mode)
|
||||
{
|
||||
switch (alg) {
|
||||
case QCRYPTO_CIPHER_ALG_DES_RFB:
|
||||
return mode == QCRYPTO_CIPHER_MODE_ECB;
|
||||
case QCRYPTO_CIPHER_ALG_AES_128:
|
||||
case QCRYPTO_CIPHER_ALG_AES_192:
|
||||
case QCRYPTO_CIPHER_ALG_AES_256:
|
||||
switch (mode) {
|
||||
case QCRYPTO_CIPHER_MODE_ECB:
|
||||
case QCRYPTO_CIPHER_MODE_CBC:
|
||||
case QCRYPTO_CIPHER_MODE_XTS:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
|
||||
QCryptoCipherMode mode,
|
||||
const uint8_t *key,
|
||||
size_t nkey,
|
||||
Error **errp)
|
||||
{
|
||||
if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (alg) {
|
||||
case QCRYPTO_CIPHER_ALG_DES_RFB:
|
||||
if (mode == QCRYPTO_CIPHER_MODE_ECB) {
|
||||
QCryptoCipherBuiltinDESRFB *ctx;
|
||||
|
||||
ctx = g_new0(QCryptoCipherBuiltinDESRFB, 1);
|
||||
ctx->base.driver = &qcrypto_cipher_des_rfb_driver;
|
||||
memcpy(ctx->key, key, sizeof(ctx->key));
|
||||
|
||||
return &ctx->base;
|
||||
}
|
||||
goto bad_mode;
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_AES_128:
|
||||
case QCRYPTO_CIPHER_ALG_AES_192:
|
||||
case QCRYPTO_CIPHER_ALG_AES_256:
|
||||
{
|
||||
QCryptoCipherBuiltinAES *ctx;
|
||||
const QCryptoCipherDriver *drv;
|
||||
|
||||
switch (mode) {
|
||||
case QCRYPTO_CIPHER_MODE_ECB:
|
||||
drv = &qcrypto_cipher_aes_driver_ecb;
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_CBC:
|
||||
drv = &qcrypto_cipher_aes_driver_cbc;
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_XTS:
|
||||
drv = &qcrypto_cipher_aes_driver_xts;
|
||||
break;
|
||||
default:
|
||||
goto bad_mode;
|
||||
}
|
||||
|
||||
ctx = g_new0(QCryptoCipherBuiltinAES, 1);
|
||||
ctx->base.driver = drv;
|
||||
|
||||
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
nkey /= 2;
|
||||
if (AES_set_encrypt_key(key + nkey, nkey * 8,
|
||||
&ctx->key_tweak.enc)) {
|
||||
error_setg(errp, "Failed to set encryption key");
|
||||
goto error;
|
||||
}
|
||||
if (AES_set_decrypt_key(key + nkey, nkey * 8,
|
||||
&ctx->key_tweak.dec)) {
|
||||
error_setg(errp, "Failed to set decryption key");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if (AES_set_encrypt_key(key, nkey * 8, &ctx->key.enc)) {
|
||||
error_setg(errp, "Failed to set encryption key");
|
||||
goto error;
|
||||
}
|
||||
if (AES_set_decrypt_key(key, nkey * 8, &ctx->key.dec)) {
|
||||
error_setg(errp, "Failed to set decryption key");
|
||||
goto error;
|
||||
}
|
||||
|
||||
return &ctx->base;
|
||||
|
||||
error:
|
||||
g_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
default:
|
||||
error_setg(errp,
|
||||
"Unsupported cipher algorithm %s",
|
||||
QCryptoCipherAlgorithm_str(alg));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bad_mode:
|
||||
error_setg(errp, "Unsupported cipher mode %s",
|
||||
QCryptoCipherMode_str(mode));
|
||||
return NULL;
|
||||
}
|
|
@ -18,15 +18,12 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#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)
|
||||
{
|
||||
|
@ -58,69 +55,224 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
|
|||
}
|
||||
}
|
||||
|
||||
typedef struct QCryptoCipherGcrypt QCryptoCipherGcrypt;
|
||||
struct QCryptoCipherGcrypt {
|
||||
typedef struct QCryptoCipherGcrypt {
|
||||
QCryptoCipher base;
|
||||
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;
|
||||
uint8_t iv[XTS_BLOCK_SIZE];
|
||||
#endif
|
||||
};
|
||||
} QCryptoCipherGcrypt;
|
||||
|
||||
static void
|
||||
qcrypto_gcrypt_cipher_free_ctx(QCryptoCipherGcrypt *ctx,
|
||||
QCryptoCipherMode mode)
|
||||
|
||||
static void qcrypto_gcrypt_ctx_free(QCryptoCipher *cipher)
|
||||
{
|
||||
if (!ctx) {
|
||||
return;
|
||||
}
|
||||
QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
|
||||
|
||||
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 int qcrypto_gcrypt_encrypt(QCryptoCipher *cipher, const void *in,
|
||||
void *out, size_t len, Error **errp)
|
||||
{
|
||||
QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
|
||||
gcry_error_t err;
|
||||
|
||||
static QCryptoCipherGcrypt *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
|
||||
QCryptoCipherMode mode,
|
||||
const uint8_t *key,
|
||||
size_t nkey,
|
||||
Error **errp)
|
||||
if (len & (ctx->blocksize - 1)) {
|
||||
error_setg(errp, "Length %zu must be a multiple of block size %zu",
|
||||
len, ctx->blocksize);
|
||||
return -1;
|
||||
}
|
||||
|
||||
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_decrypt(QCryptoCipher *cipher, const void *in,
|
||||
void *out, size_t len, Error **errp)
|
||||
{
|
||||
QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
|
||||
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;
|
||||
}
|
||||
|
||||
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_setiv(QCryptoCipher *cipher,
|
||||
const uint8_t *iv, size_t niv,
|
||||
Error **errp)
|
||||
{
|
||||
QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
|
||||
gcry_error_t err;
|
||||
|
||||
if (niv != ctx->blocksize) {
|
||||
error_setg(errp, "Expected IV size %zu not %zu",
|
||||
ctx->blocksize, niv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
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 int qcrypto_gcrypt_ctr_setiv(QCryptoCipher *cipher,
|
||||
const uint8_t *iv, size_t niv,
|
||||
Error **errp)
|
||||
{
|
||||
QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
|
||||
gcry_error_t err;
|
||||
|
||||
if (niv != ctx->blocksize) {
|
||||
error_setg(errp, "Expected IV size %zu not %zu",
|
||||
ctx->blocksize, niv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = gcry_cipher_setctr(ctx->handle, iv, niv);
|
||||
if (err != 0) {
|
||||
error_setg(errp, "Cannot set Counter: %s", gcry_strerror(err));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const struct QCryptoCipherDriver qcrypto_gcrypt_driver = {
|
||||
.cipher_encrypt = qcrypto_gcrypt_encrypt,
|
||||
.cipher_decrypt = qcrypto_gcrypt_decrypt,
|
||||
.cipher_setiv = qcrypto_gcrypt_setiv,
|
||||
.cipher_free = qcrypto_gcrypt_ctx_free,
|
||||
};
|
||||
|
||||
static const struct QCryptoCipherDriver qcrypto_gcrypt_ctr_driver = {
|
||||
.cipher_encrypt = qcrypto_gcrypt_encrypt,
|
||||
.cipher_decrypt = qcrypto_gcrypt_decrypt,
|
||||
.cipher_setiv = qcrypto_gcrypt_ctr_setiv,
|
||||
.cipher_free = qcrypto_gcrypt_ctx_free,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_QEMU_PRIVATE_XTS
|
||||
static void qcrypto_gcrypt_xts_ctx_free(QCryptoCipher *cipher)
|
||||
{
|
||||
QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
|
||||
|
||||
gcry_cipher_close(ctx->tweakhandle);
|
||||
qcrypto_gcrypt_ctx_free(cipher);
|
||||
}
|
||||
|
||||
static void qcrypto_gcrypt_xts_wrape(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_wrapd(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);
|
||||
}
|
||||
|
||||
static int qcrypto_gcrypt_xts_encrypt(QCryptoCipher *cipher, const void *in,
|
||||
void *out, size_t len, Error **errp)
|
||||
{
|
||||
QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
|
||||
|
||||
if (len & (ctx->blocksize - 1)) {
|
||||
error_setg(errp, "Length %zu must be a multiple of block size %zu",
|
||||
len, ctx->blocksize);
|
||||
return -1;
|
||||
}
|
||||
|
||||
xts_encrypt(ctx->handle, ctx->tweakhandle,
|
||||
qcrypto_gcrypt_xts_wrape, qcrypto_gcrypt_xts_wrapd,
|
||||
ctx->iv, len, out, in);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcrypto_gcrypt_xts_decrypt(QCryptoCipher *cipher, const void *in,
|
||||
void *out, size_t len, Error **errp)
|
||||
{
|
||||
QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
|
||||
|
||||
if (len & (ctx->blocksize - 1)) {
|
||||
error_setg(errp, "Length %zu must be a multiple of block size %zu",
|
||||
len, ctx->blocksize);
|
||||
return -1;
|
||||
}
|
||||
|
||||
xts_decrypt(ctx->handle, ctx->tweakhandle,
|
||||
qcrypto_gcrypt_xts_wrape, qcrypto_gcrypt_xts_wrapd,
|
||||
ctx->iv, len, out, in);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcrypto_gcrypt_xts_setiv(QCryptoCipher *cipher,
|
||||
const uint8_t *iv, size_t niv,
|
||||
Error **errp)
|
||||
{
|
||||
QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
|
||||
|
||||
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 const struct QCryptoCipherDriver qcrypto_gcrypt_xts_driver = {
|
||||
.cipher_encrypt = qcrypto_gcrypt_xts_encrypt,
|
||||
.cipher_decrypt = qcrypto_gcrypt_xts_decrypt,
|
||||
.cipher_setiv = qcrypto_gcrypt_xts_setiv,
|
||||
.cipher_free = qcrypto_gcrypt_xts_ctx_free,
|
||||
};
|
||||
#endif /* CONFIG_QEMU_PRIVATE_XTS */
|
||||
|
||||
|
||||
static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
|
||||
QCryptoCipherMode mode,
|
||||
const uint8_t *key,
|
||||
size_t nkey,
|
||||
Error **errp)
|
||||
{
|
||||
QCryptoCipherGcrypt *ctx;
|
||||
const QCryptoCipherDriver *drv;
|
||||
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;
|
||||
}
|
||||
|
@ -129,54 +281,70 @@ static QCryptoCipherGcrypt *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm 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;
|
||||
}
|
||||
|
||||
drv = &qcrypto_gcrypt_driver;
|
||||
switch (mode) {
|
||||
case QCRYPTO_CIPHER_MODE_ECB:
|
||||
gcrymode = GCRY_CIPHER_MODE_ECB;
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_XTS:
|
||||
#ifdef CONFIG_QEMU_PRIVATE_XTS
|
||||
drv = &qcrypto_gcrypt_xts_driver;
|
||||
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:
|
||||
drv = &qcrypto_gcrypt_ctr_driver;
|
||||
gcrymode = GCRY_CIPHER_MODE_CTR;
|
||||
break;
|
||||
default:
|
||||
error_setg(errp, "Unsupported cipher mode %s",
|
||||
QCryptoCipherMode_str(mode));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx = g_new0(QCryptoCipherGcrypt, 1);
|
||||
ctx->base.driver = drv;
|
||||
|
||||
err = gcry_cipher_open(&ctx->handle, gcryalg, gcrymode, 0);
|
||||
if (err != 0) {
|
||||
|
@ -184,8 +352,16 @@ static QCryptoCipherGcrypt *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
|
|||
gcry_strerror(err));
|
||||
goto error;
|
||||
}
|
||||
ctx->blocksize = gcry_cipher_get_algo_blklen(gcryalg);
|
||||
|
||||
#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;
|
||||
}
|
||||
err = gcry_cipher_open(&ctx->tweakhandle, gcryalg, gcrymode, 0);
|
||||
if (err != 0) {
|
||||
error_setg(errp, "Cannot initialize cipher: %s",
|
||||
|
@ -203,220 +379,31 @@ static QCryptoCipherGcrypt *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
|
|||
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);
|
||||
err = gcry_cipher_setkey(ctx->tweakhandle, key + nkey, nkey);
|
||||
if (err != 0) {
|
||||
error_setg(errp, "Cannot set key: %s",
|
||||
gcry_strerror(err));
|
||||
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();
|
||||
}
|
||||
err = gcry_cipher_setkey(ctx->handle, key, nkey);
|
||||
}
|
||||
if (err != 0) {
|
||||
error_setg(errp, "Cannot set key: %s", gcry_strerror(err));
|
||||
goto error;
|
||||
}
|
||||
|
||||
#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;
|
||||
return &ctx->base;
|
||||
|
||||
error:
|
||||
qcrypto_gcrypt_cipher_free_ctx(ctx, mode);
|
||||
#ifdef CONFIG_QEMU_PRIVATE_XTS
|
||||
gcry_cipher_close(ctx->tweakhandle);
|
||||
#endif
|
||||
gcry_cipher_close(ctx->handle);
|
||||
g_free(ctx);
|
||||
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) {
|
||||
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) {
|
||||
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,
|
||||
};
|
|
@ -1,733 +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 <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;
|
||||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
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,
|
||||
};
|
|
@ -0,0 +1,760 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_QEMU_PRIVATE_XTS
|
||||
#include "crypto/xts.h"
|
||||
#endif
|
||||
|
||||
#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 CONST_CTX
|
||||
|
||||
#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;
|
||||
#define CONST_CTX const
|
||||
#endif
|
||||
|
||||
static inline bool qcrypto_length_check(size_t len, size_t blocksize,
|
||||
Error **errp)
|
||||
{
|
||||
if (unlikely(len & (blocksize - 1))) {
|
||||
error_setg(errp, "Length %zu must be a multiple of block size %zu",
|
||||
len, blocksize);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static void qcrypto_cipher_ctx_free(QCryptoCipher *ctx)
|
||||
{
|
||||
g_free(ctx);
|
||||
}
|
||||
|
||||
static int qcrypto_cipher_no_setiv(QCryptoCipher *cipher,
|
||||
const uint8_t *iv, size_t niv,
|
||||
Error **errp)
|
||||
{
|
||||
error_setg(errp, "Setting IV is not supported");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
#define DEFINE_SETIV(NAME, TYPE, BLEN) \
|
||||
static int NAME##_setiv(QCryptoCipher *cipher, const uint8_t *iv, \
|
||||
size_t niv, Error **errp) \
|
||||
{ \
|
||||
TYPE *ctx = container_of(cipher, TYPE, base); \
|
||||
if (niv != BLEN) { \
|
||||
error_setg(errp, "Expected IV size %d not %zu", BLEN, niv); \
|
||||
return -1; \
|
||||
} \
|
||||
memcpy(ctx->iv, iv, niv); \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
|
||||
#define DEFINE_ECB(NAME, TYPE, BLEN, ENCRYPT, DECRYPT) \
|
||||
static int NAME##_encrypt_ecb(QCryptoCipher *cipher, const void *in, \
|
||||
void *out, size_t len, Error **errp) \
|
||||
{ \
|
||||
TYPE *ctx = container_of(cipher, TYPE, base); \
|
||||
if (!qcrypto_length_check(len, BLEN, errp)) { \
|
||||
return -1; \
|
||||
} \
|
||||
ENCRYPT(&ctx->key, len, out, in); \
|
||||
return 0; \
|
||||
} \
|
||||
static int NAME##_decrypt_ecb(QCryptoCipher *cipher, const void *in, \
|
||||
void *out, size_t len, Error **errp) \
|
||||
{ \
|
||||
TYPE *ctx = container_of(cipher, TYPE, base); \
|
||||
if (!qcrypto_length_check(len, BLEN, errp)) { \
|
||||
return -1; \
|
||||
} \
|
||||
DECRYPT(&ctx->key, len, out, in); \
|
||||
return 0; \
|
||||
} \
|
||||
static const struct QCryptoCipherDriver NAME##_driver_ecb = { \
|
||||
.cipher_encrypt = NAME##_encrypt_ecb, \
|
||||
.cipher_decrypt = NAME##_decrypt_ecb, \
|
||||
.cipher_setiv = qcrypto_cipher_no_setiv, \
|
||||
.cipher_free = qcrypto_cipher_ctx_free, \
|
||||
};
|
||||
|
||||
|
||||
#define DEFINE_CBC(NAME, TYPE, BLEN, ENCRYPT, DECRYPT) \
|
||||
static int NAME##_encrypt_cbc(QCryptoCipher *cipher, const void *in, \
|
||||
void *out, size_t len, Error **errp) \
|
||||
{ \
|
||||
TYPE *ctx = container_of(cipher, TYPE, base); \
|
||||
if (!qcrypto_length_check(len, BLEN, errp)) { \
|
||||
return -1; \
|
||||
} \
|
||||
cbc_encrypt(&ctx->key, ENCRYPT, BLEN, ctx->iv, len, out, in); \
|
||||
return 0; \
|
||||
} \
|
||||
static int NAME##_decrypt_cbc(QCryptoCipher *cipher, const void *in, \
|
||||
void *out, size_t len, Error **errp) \
|
||||
{ \
|
||||
TYPE *ctx = container_of(cipher, TYPE, base); \
|
||||
if (!qcrypto_length_check(len, BLEN, errp)) { \
|
||||
return -1; \
|
||||
} \
|
||||
cbc_decrypt(&ctx->key, DECRYPT, BLEN, ctx->iv, len, out, in); \
|
||||
return 0; \
|
||||
} \
|
||||
static const struct QCryptoCipherDriver NAME##_driver_cbc = { \
|
||||
.cipher_encrypt = NAME##_encrypt_cbc, \
|
||||
.cipher_decrypt = NAME##_decrypt_cbc, \
|
||||
.cipher_setiv = NAME##_setiv, \
|
||||
.cipher_free = qcrypto_cipher_ctx_free, \
|
||||
};
|
||||
|
||||
|
||||
#define DEFINE_CTR(NAME, TYPE, BLEN, ENCRYPT) \
|
||||
static int NAME##_encrypt_ctr(QCryptoCipher *cipher, const void *in, \
|
||||
void *out, size_t len, Error **errp) \
|
||||
{ \
|
||||
TYPE *ctx = container_of(cipher, TYPE, base); \
|
||||
if (!qcrypto_length_check(len, BLEN, errp)) { \
|
||||
return -1; \
|
||||
} \
|
||||
ctr_crypt(&ctx->key, ENCRYPT, BLEN, ctx->iv, len, out, in); \
|
||||
return 0; \
|
||||
} \
|
||||
static const struct QCryptoCipherDriver NAME##_driver_ctr = { \
|
||||
.cipher_encrypt = NAME##_encrypt_ctr, \
|
||||
.cipher_decrypt = NAME##_encrypt_ctr, \
|
||||
.cipher_setiv = NAME##_setiv, \
|
||||
.cipher_free = qcrypto_cipher_ctx_free, \
|
||||
};
|
||||
|
||||
|
||||
#ifdef CONFIG_QEMU_PRIVATE_XTS
|
||||
#define DEFINE__XTS(NAME, TYPE, BLEN, ENCRYPT, DECRYPT) \
|
||||
static void NAME##_xts_wrape(const void *ctx, size_t length, \
|
||||
uint8_t *dst, const uint8_t *src) \
|
||||
{ \
|
||||
ENCRYPT((cipher_ctx_t)ctx, length, dst, src); \
|
||||
} \
|
||||
static void NAME##_xts_wrapd(const void *ctx, size_t length, \
|
||||
uint8_t *dst, const uint8_t *src) \
|
||||
{ \
|
||||
DECRYPT((cipher_ctx_t)ctx, length, dst, src); \
|
||||
} \
|
||||
static int NAME##_encrypt_xts(QCryptoCipher *cipher, const void *in, \
|
||||
void *out, size_t len, Error **errp) \
|
||||
{ \
|
||||
TYPE *ctx = container_of(cipher, TYPE, base); \
|
||||
if (!qcrypto_length_check(len, BLEN, errp)) { \
|
||||
return -1; \
|
||||
} \
|
||||
xts_encrypt(&ctx->key, &ctx->key_xts, \
|
||||
NAME##_xts_wrape, NAME##_xts_wrapd, \
|
||||
ctx->iv, len, out, in); \
|
||||
return 0; \
|
||||
} \
|
||||
static int NAME##_decrypt_xts(QCryptoCipher *cipher, const void *in, \
|
||||
void *out, size_t len, Error **errp) \
|
||||
{ \
|
||||
TYPE *ctx = container_of(cipher, TYPE, base); \
|
||||
if (!qcrypto_length_check(len, BLEN, errp)) { \
|
||||
return -1; \
|
||||
} \
|
||||
xts_decrypt(&ctx->key, &ctx->key_xts, \
|
||||
NAME##_xts_wrape, NAME##_xts_wrapd, \
|
||||
ctx->iv, len, out, in); \
|
||||
return 0; \
|
||||
}
|
||||
#else
|
||||
#define DEFINE__XTS(NAME, TYPE, BLEN, ENCRYPT, DECRYPT) \
|
||||
static int NAME##_encrypt_xts(QCryptoCipher *cipher, const void *in, \
|
||||
void *out, size_t len, Error **errp) \
|
||||
{ \
|
||||
TYPE *ctx = container_of(cipher, TYPE, base); \
|
||||
if (!qcrypto_length_check(len, BLEN, errp)) { \
|
||||
return -1; \
|
||||
} \
|
||||
xts_encrypt_message(&ctx->key, &ctx->key_xts, ENCRYPT, \
|
||||
ctx->iv, len, out, in); \
|
||||
return 0; \
|
||||
} \
|
||||
static int NAME##_decrypt_xts(QCryptoCipher *cipher, const void *in, \
|
||||
void *out, size_t len, Error **errp) \
|
||||
{ \
|
||||
TYPE *ctx = container_of(cipher, TYPE, base); \
|
||||
if (!qcrypto_length_check(len, BLEN, errp)) { \
|
||||
return -1; \
|
||||
} \
|
||||
xts_decrypt_message(&ctx->key, &ctx->key_xts, DECRYPT, ENCRYPT, \
|
||||
ctx->iv, len, out, in); \
|
||||
return 0; \
|
||||
}
|
||||
#endif
|
||||
|
||||
#define DEFINE_XTS(NAME, TYPE, BLEN, ENCRYPT, DECRYPT) \
|
||||
QEMU_BUILD_BUG_ON(BLEN != XTS_BLOCK_SIZE); \
|
||||
DEFINE__XTS(NAME, TYPE, BLEN, ENCRYPT, DECRYPT) \
|
||||
static const struct QCryptoCipherDriver NAME##_driver_xts = { \
|
||||
.cipher_encrypt = NAME##_encrypt_xts, \
|
||||
.cipher_decrypt = NAME##_decrypt_xts, \
|
||||
.cipher_setiv = NAME##_setiv, \
|
||||
.cipher_free = qcrypto_cipher_ctx_free, \
|
||||
};
|
||||
|
||||
|
||||
#define DEFINE_ECB_CBC_CTR(NAME, TYPE, BLEN, ENCRYPT, DECRYPT) \
|
||||
DEFINE_SETIV(NAME, TYPE, BLEN) \
|
||||
DEFINE_ECB(NAME, TYPE, BLEN, ENCRYPT, DECRYPT) \
|
||||
DEFINE_CBC(NAME, TYPE, BLEN, ENCRYPT, DECRYPT) \
|
||||
DEFINE_CTR(NAME, TYPE, BLEN, ENCRYPT)
|
||||
|
||||
#define DEFINE_ECB_CBC_CTR_XTS(NAME, TYPE, BLEN, ENCRYPT, DECRYPT) \
|
||||
DEFINE_ECB_CBC_CTR(NAME, TYPE, BLEN, ENCRYPT, DECRYPT) \
|
||||
DEFINE_XTS(NAME, TYPE, BLEN, ENCRYPT, DECRYPT)
|
||||
|
||||
|
||||
typedef struct QCryptoNettleDESRFB {
|
||||
QCryptoCipher base;
|
||||
struct des_ctx key;
|
||||
uint8_t iv[DES_BLOCK_SIZE];
|
||||
} QCryptoNettleDESRFB;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
DEFINE_ECB_CBC_CTR(qcrypto_nettle_des_rfb, QCryptoNettleDESRFB,
|
||||
DES_BLOCK_SIZE, des_encrypt_native, des_decrypt_native)
|
||||
|
||||
|
||||
typedef struct QCryptoNettleDES3 {
|
||||
QCryptoCipher base;
|
||||
struct des3_ctx key;
|
||||
uint8_t iv[DES3_BLOCK_SIZE];
|
||||
} QCryptoNettleDES3;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
DEFINE_ECB_CBC_CTR(qcrypto_nettle_des3, QCryptoNettleDES3, DES3_BLOCK_SIZE,
|
||||
des3_encrypt_native, des3_decrypt_native)
|
||||
|
||||
|
||||
typedef struct QCryptoNettleAES128 {
|
||||
QCryptoCipher base;
|
||||
uint8_t iv[AES_BLOCK_SIZE];
|
||||
/* First key from pair is encode, second key is decode. */
|
||||
struct aes128_ctx key[2], key_xts[2];
|
||||
} QCryptoNettleAES128;
|
||||
|
||||
static void aes128_encrypt_native(cipher_ctx_t ctx, cipher_length_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
CONST_CTX struct aes128_ctx *keys = ctx;
|
||||
aes128_encrypt(&keys[0], length, dst, src);
|
||||
}
|
||||
|
||||
static void aes128_decrypt_native(cipher_ctx_t ctx, cipher_length_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
CONST_CTX struct aes128_ctx *keys = ctx;
|
||||
aes128_decrypt(&keys[1], length, dst, src);
|
||||
}
|
||||
|
||||
DEFINE_ECB_CBC_CTR_XTS(qcrypto_nettle_aes128,
|
||||
QCryptoNettleAES128, AES_BLOCK_SIZE,
|
||||
aes128_encrypt_native, aes128_decrypt_native)
|
||||
|
||||
|
||||
typedef struct QCryptoNettleAES192 {
|
||||
QCryptoCipher base;
|
||||
uint8_t iv[AES_BLOCK_SIZE];
|
||||
/* First key from pair is encode, second key is decode. */
|
||||
struct aes192_ctx key[2], key_xts[2];
|
||||
} QCryptoNettleAES192;
|
||||
|
||||
static void aes192_encrypt_native(cipher_ctx_t ctx, cipher_length_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
CONST_CTX struct aes192_ctx *keys = ctx;
|
||||
aes192_encrypt(&keys[0], length, dst, src);
|
||||
}
|
||||
|
||||
static void aes192_decrypt_native(cipher_ctx_t ctx, cipher_length_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
CONST_CTX struct aes192_ctx *keys = ctx;
|
||||
aes192_decrypt(&keys[1], length, dst, src);
|
||||
}
|
||||
|
||||
DEFINE_ECB_CBC_CTR_XTS(qcrypto_nettle_aes192,
|
||||
QCryptoNettleAES192, AES_BLOCK_SIZE,
|
||||
aes192_encrypt_native, aes192_decrypt_native)
|
||||
|
||||
|
||||
typedef struct QCryptoNettleAES256 {
|
||||
QCryptoCipher base;
|
||||
uint8_t iv[AES_BLOCK_SIZE];
|
||||
/* First key from pair is encode, second key is decode. */
|
||||
struct aes256_ctx key[2], key_xts[2];
|
||||
} QCryptoNettleAES256;
|
||||
|
||||
static void aes256_encrypt_native(cipher_ctx_t ctx, cipher_length_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
CONST_CTX struct aes256_ctx *keys = ctx;
|
||||
aes256_encrypt(&keys[0], length, dst, src);
|
||||
}
|
||||
|
||||
static void aes256_decrypt_native(cipher_ctx_t ctx, cipher_length_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
CONST_CTX struct aes256_ctx *keys = ctx;
|
||||
aes256_decrypt(&keys[1], length, dst, src);
|
||||
}
|
||||
|
||||
DEFINE_ECB_CBC_CTR_XTS(qcrypto_nettle_aes256,
|
||||
QCryptoNettleAES256, AES_BLOCK_SIZE,
|
||||
aes256_encrypt_native, aes256_decrypt_native)
|
||||
|
||||
|
||||
typedef struct QCryptoNettleCAST128 {
|
||||
QCryptoCipher base;
|
||||
uint8_t iv[CAST128_BLOCK_SIZE];
|
||||
struct cast128_ctx key, key_xts;
|
||||
} QCryptoNettleCAST128;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
DEFINE_ECB_CBC_CTR(qcrypto_nettle_cast128,
|
||||
QCryptoNettleCAST128, CAST128_BLOCK_SIZE,
|
||||
cast128_encrypt_native, cast128_decrypt_native)
|
||||
|
||||
|
||||
typedef struct QCryptoNettleSerpent {
|
||||
QCryptoCipher base;
|
||||
uint8_t iv[SERPENT_BLOCK_SIZE];
|
||||
struct serpent_ctx key, key_xts;
|
||||
} QCryptoNettleSerpent;
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
DEFINE_ECB_CBC_CTR_XTS(qcrypto_nettle_serpent,
|
||||
QCryptoNettleSerpent, SERPENT_BLOCK_SIZE,
|
||||
serpent_encrypt_native, serpent_decrypt_native)
|
||||
|
||||
|
||||
typedef struct QCryptoNettleTwofish {
|
||||
QCryptoCipher base;
|
||||
uint8_t iv[TWOFISH_BLOCK_SIZE];
|
||||
struct twofish_ctx key, key_xts;
|
||||
} QCryptoNettleTwofish;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
DEFINE_ECB_CBC_CTR_XTS(qcrypto_nettle_twofish,
|
||||
QCryptoNettleTwofish, TWOFISH_BLOCK_SIZE,
|
||||
twofish_encrypt_native, twofish_decrypt_native)
|
||||
|
||||
|
||||
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 QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
|
||||
QCryptoCipherMode mode,
|
||||
const uint8_t *key,
|
||||
size_t nkey,
|
||||
Error **errp)
|
||||
{
|
||||
switch (mode) {
|
||||
case QCRYPTO_CIPHER_MODE_ECB:
|
||||
case QCRYPTO_CIPHER_MODE_CBC:
|
||||
case QCRYPTO_CIPHER_MODE_XTS:
|
||||
case QCRYPTO_CIPHER_MODE_CTR:
|
||||
break;
|
||||
default:
|
||||
goto bad_cipher_mode;
|
||||
}
|
||||
|
||||
if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (alg) {
|
||||
case QCRYPTO_CIPHER_ALG_DES_RFB:
|
||||
{
|
||||
QCryptoNettleDESRFB *ctx;
|
||||
const QCryptoCipherDriver *drv;
|
||||
uint8_t *rfbkey;
|
||||
|
||||
switch (mode) {
|
||||
case QCRYPTO_CIPHER_MODE_ECB:
|
||||
drv = &qcrypto_nettle_des_rfb_driver_ecb;
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_CBC:
|
||||
drv = &qcrypto_nettle_des_rfb_driver_cbc;
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_CTR:
|
||||
drv = &qcrypto_nettle_des_rfb_driver_ctr;
|
||||
break;
|
||||
default:
|
||||
goto bad_cipher_mode;
|
||||
}
|
||||
|
||||
ctx = g_new0(QCryptoNettleDESRFB, 1);
|
||||
ctx->base.driver = drv;
|
||||
|
||||
rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey);
|
||||
des_set_key(&ctx->key, rfbkey);
|
||||
g_free(rfbkey);
|
||||
|
||||
return &ctx->base;
|
||||
}
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_3DES:
|
||||
{
|
||||
QCryptoNettleDES3 *ctx;
|
||||
const QCryptoCipherDriver *drv;
|
||||
|
||||
switch (mode) {
|
||||
case QCRYPTO_CIPHER_MODE_ECB:
|
||||
drv = &qcrypto_nettle_des3_driver_ecb;
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_CBC:
|
||||
drv = &qcrypto_nettle_des3_driver_cbc;
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_CTR:
|
||||
drv = &qcrypto_nettle_des3_driver_ctr;
|
||||
break;
|
||||
default:
|
||||
goto bad_cipher_mode;
|
||||
}
|
||||
|
||||
ctx = g_new0(QCryptoNettleDES3, 1);
|
||||
ctx->base.driver = drv;
|
||||
des3_set_key(&ctx->key, key);
|
||||
return &ctx->base;
|
||||
}
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_AES_128:
|
||||
{
|
||||
QCryptoNettleAES128 *ctx = g_new0(QCryptoNettleAES128, 1);
|
||||
|
||||
switch (mode) {
|
||||
case QCRYPTO_CIPHER_MODE_ECB:
|
||||
ctx->base.driver = &qcrypto_nettle_aes128_driver_ecb;
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_CBC:
|
||||
ctx->base.driver = &qcrypto_nettle_aes128_driver_cbc;
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_CTR:
|
||||
ctx->base.driver = &qcrypto_nettle_aes128_driver_ctr;
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_XTS:
|
||||
ctx->base.driver = &qcrypto_nettle_aes128_driver_xts;
|
||||
nkey /= 2;
|
||||
aes128_set_encrypt_key(&ctx->key_xts[0], key + nkey);
|
||||
aes128_set_decrypt_key(&ctx->key_xts[1], key + nkey);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
aes128_set_encrypt_key(&ctx->key[0], key);
|
||||
aes128_set_decrypt_key(&ctx->key[1], key);
|
||||
|
||||
return &ctx->base;
|
||||
}
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_AES_192:
|
||||
{
|
||||
QCryptoNettleAES192 *ctx = g_new0(QCryptoNettleAES192, 1);
|
||||
|
||||
switch (mode) {
|
||||
case QCRYPTO_CIPHER_MODE_ECB:
|
||||
ctx->base.driver = &qcrypto_nettle_aes192_driver_ecb;
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_CBC:
|
||||
ctx->base.driver = &qcrypto_nettle_aes192_driver_cbc;
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_CTR:
|
||||
ctx->base.driver = &qcrypto_nettle_aes192_driver_ctr;
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_XTS:
|
||||
ctx->base.driver = &qcrypto_nettle_aes192_driver_xts;
|
||||
nkey /= 2;
|
||||
aes192_set_encrypt_key(&ctx->key_xts[0], key + nkey);
|
||||
aes192_set_decrypt_key(&ctx->key_xts[1], key + nkey);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
aes192_set_encrypt_key(&ctx->key[0], key);
|
||||
aes192_set_decrypt_key(&ctx->key[1], key);
|
||||
|
||||
return &ctx->base;
|
||||
}
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_AES_256:
|
||||
{
|
||||
QCryptoNettleAES256 *ctx = g_new0(QCryptoNettleAES256, 1);
|
||||
|
||||
switch (mode) {
|
||||
case QCRYPTO_CIPHER_MODE_ECB:
|
||||
ctx->base.driver = &qcrypto_nettle_aes256_driver_ecb;
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_CBC:
|
||||
ctx->base.driver = &qcrypto_nettle_aes256_driver_cbc;
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_CTR:
|
||||
ctx->base.driver = &qcrypto_nettle_aes256_driver_ctr;
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_XTS:
|
||||
ctx->base.driver = &qcrypto_nettle_aes256_driver_xts;
|
||||
nkey /= 2;
|
||||
aes256_set_encrypt_key(&ctx->key_xts[0], key + nkey);
|
||||
aes256_set_decrypt_key(&ctx->key_xts[1], key + nkey);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
aes256_set_encrypt_key(&ctx->key[0], key);
|
||||
aes256_set_decrypt_key(&ctx->key[1], key);
|
||||
|
||||
return &ctx->base;
|
||||
}
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_CAST5_128:
|
||||
{
|
||||
QCryptoNettleCAST128 *ctx;
|
||||
const QCryptoCipherDriver *drv;
|
||||
|
||||
switch (mode) {
|
||||
case QCRYPTO_CIPHER_MODE_ECB:
|
||||
drv = &qcrypto_nettle_cast128_driver_ecb;
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_CBC:
|
||||
drv = &qcrypto_nettle_cast128_driver_cbc;
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_CTR:
|
||||
drv = &qcrypto_nettle_cast128_driver_ctr;
|
||||
break;
|
||||
default:
|
||||
goto bad_cipher_mode;
|
||||
}
|
||||
|
||||
ctx = g_new0(QCryptoNettleCAST128, 1);
|
||||
ctx->base.driver = drv;
|
||||
cast5_set_key(&ctx->key, nkey, key);
|
||||
|
||||
return &ctx->base;
|
||||
}
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_128:
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_192:
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_256:
|
||||
{
|
||||
QCryptoNettleSerpent *ctx = g_new0(QCryptoNettleSerpent, 1);
|
||||
|
||||
switch (mode) {
|
||||
case QCRYPTO_CIPHER_MODE_ECB:
|
||||
ctx->base.driver = &qcrypto_nettle_serpent_driver_ecb;
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_CBC:
|
||||
ctx->base.driver = &qcrypto_nettle_serpent_driver_cbc;
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_CTR:
|
||||
ctx->base.driver = &qcrypto_nettle_serpent_driver_ctr;
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_XTS:
|
||||
ctx->base.driver = &qcrypto_nettle_serpent_driver_xts;
|
||||
nkey /= 2;
|
||||
serpent_set_key(&ctx->key_xts, nkey, key + nkey);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
serpent_set_key(&ctx->key, nkey, key);
|
||||
|
||||
return &ctx->base;
|
||||
}
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_128:
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_192:
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_256:
|
||||
{
|
||||
QCryptoNettleTwofish *ctx = g_new0(QCryptoNettleTwofish, 1);
|
||||
|
||||
switch (mode) {
|
||||
case QCRYPTO_CIPHER_MODE_ECB:
|
||||
ctx->base.driver = &qcrypto_nettle_twofish_driver_ecb;
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_CBC:
|
||||
ctx->base.driver = &qcrypto_nettle_twofish_driver_cbc;
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_CTR:
|
||||
ctx->base.driver = &qcrypto_nettle_twofish_driver_ctr;
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_XTS:
|
||||
ctx->base.driver = &qcrypto_nettle_twofish_driver_xts;
|
||||
nkey /= 2;
|
||||
twofish_set_key(&ctx->key_xts, nkey, key + nkey);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
twofish_set_key(&ctx->key, nkey, key);
|
||||
|
||||
return &ctx->base;
|
||||
}
|
||||
|
||||
default:
|
||||
error_setg(errp, "Unsupported cipher algorithm %s",
|
||||
QCryptoCipherAlgorithm_str(alg));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bad_cipher_mode:
|
||||
error_setg(errp, "Unsupported cipher mode %s",
|
||||
QCryptoCipherMode_str(mode));
|
||||
return NULL;
|
||||
}
|
|
@ -19,12 +19,13 @@
|
|||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/host-utils.h"
|
||||
#include "qapi/error.h"
|
||||
#include "crypto/cipher.h"
|
||||
#include "cipherpriv.h"
|
||||
|
||||
|
||||
static size_t alg_key_len[QCRYPTO_CIPHER_ALG__MAX] = {
|
||||
static const size_t alg_key_len[QCRYPTO_CIPHER_ALG__MAX] = {
|
||||
[QCRYPTO_CIPHER_ALG_AES_128] = 16,
|
||||
[QCRYPTO_CIPHER_ALG_AES_192] = 24,
|
||||
[QCRYPTO_CIPHER_ALG_AES_256] = 32,
|
||||
|
@ -39,7 +40,7 @@ static size_t alg_key_len[QCRYPTO_CIPHER_ALG__MAX] = {
|
|||
[QCRYPTO_CIPHER_ALG_TWOFISH_256] = 32,
|
||||
};
|
||||
|
||||
static size_t alg_block_len[QCRYPTO_CIPHER_ALG__MAX] = {
|
||||
static const size_t alg_block_len[QCRYPTO_CIPHER_ALG__MAX] = {
|
||||
[QCRYPTO_CIPHER_ALG_AES_128] = 16,
|
||||
[QCRYPTO_CIPHER_ALG_AES_192] = 16,
|
||||
[QCRYPTO_CIPHER_ALG_AES_256] = 16,
|
||||
|
@ -54,7 +55,7 @@ static size_t alg_block_len[QCRYPTO_CIPHER_ALG__MAX] = {
|
|||
[QCRYPTO_CIPHER_ALG_TWOFISH_256] = 16,
|
||||
};
|
||||
|
||||
static bool mode_need_iv[QCRYPTO_CIPHER_MODE__MAX] = {
|
||||
static const bool mode_need_iv[QCRYPTO_CIPHER_MODE__MAX] = {
|
||||
[QCRYPTO_CIPHER_MODE_ECB] = false,
|
||||
[QCRYPTO_CIPHER_MODE_CBC] = true,
|
||||
[QCRYPTO_CIPHER_MODE_XTS] = true,
|
||||
|
@ -150,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,
|
||||
|
@ -162,31 +163,21 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
|||
const uint8_t *key, size_t nkey,
|
||||
Error **errp)
|
||||
{
|
||||
QCryptoCipher *cipher;
|
||||
void *ctx = NULL;
|
||||
QCryptoCipherDriver *drv = NULL;
|
||||
QCryptoCipher *cipher = NULL;
|
||||
|
||||
#ifdef CONFIG_AF_ALG
|
||||
ctx = qcrypto_afalg_cipher_ctx_new(alg, mode, key, nkey, NULL);
|
||||
if (ctx) {
|
||||
drv = &qcrypto_cipher_afalg_driver;
|
||||
}
|
||||
cipher = qcrypto_afalg_cipher_ctx_new(alg, mode, key, nkey, NULL);
|
||||
#endif
|
||||
|
||||
if (!ctx) {
|
||||
ctx = qcrypto_cipher_ctx_new(alg, mode, key, nkey, errp);
|
||||
if (!ctx) {
|
||||
if (!cipher) {
|
||||
cipher = qcrypto_cipher_ctx_new(alg, mode, key, nkey, errp);
|
||||
if (!cipher) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
drv = &qcrypto_cipher_lib_driver;
|
||||
}
|
||||
|
||||
cipher = g_new0(QCryptoCipher, 1);
|
||||
cipher->alg = alg;
|
||||
cipher->mode = mode;
|
||||
cipher->opaque = ctx;
|
||||
cipher->driver = (void *)drv;
|
||||
|
||||
return cipher;
|
||||
}
|
||||
|
@ -198,7 +189,7 @@ int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
|
|||
size_t len,
|
||||
Error **errp)
|
||||
{
|
||||
QCryptoCipherDriver *drv = cipher->driver;
|
||||
const QCryptoCipherDriver *drv = cipher->driver;
|
||||
return drv->cipher_encrypt(cipher, in, out, len, errp);
|
||||
}
|
||||
|
||||
|
@ -209,7 +200,7 @@ int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
|
|||
size_t len,
|
||||
Error **errp)
|
||||
{
|
||||
QCryptoCipherDriver *drv = cipher->driver;
|
||||
const QCryptoCipherDriver *drv = cipher->driver;
|
||||
return drv->cipher_decrypt(cipher, in, out, len, errp);
|
||||
}
|
||||
|
||||
|
@ -218,17 +209,14 @@ int qcrypto_cipher_setiv(QCryptoCipher *cipher,
|
|||
const uint8_t *iv, size_t niv,
|
||||
Error **errp)
|
||||
{
|
||||
QCryptoCipherDriver *drv = cipher->driver;
|
||||
const QCryptoCipherDriver *drv = cipher->driver;
|
||||
return drv->cipher_setiv(cipher, iv, niv, errp);
|
||||
}
|
||||
|
||||
|
||||
void qcrypto_cipher_free(QCryptoCipher *cipher)
|
||||
{
|
||||
QCryptoCipherDriver *drv;
|
||||
if (cipher) {
|
||||
drv = cipher->driver;
|
||||
drv->cipher_free(cipher);
|
||||
g_free(cipher);
|
||||
cipher->driver->cipher_free(cipher);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
|
||||
#include "qapi/qapi-types-crypto.h"
|
||||
|
||||
typedef struct QCryptoCipherDriver QCryptoCipherDriver;
|
||||
|
||||
struct QCryptoCipherDriver {
|
||||
int (*cipher_encrypt)(QCryptoCipher *cipher,
|
||||
const void *in,
|
||||
|
@ -43,14 +41,12 @@ struct QCryptoCipherDriver {
|
|||
|
||||
#include "afalgpriv.h"
|
||||
|
||||
extern QCryptoAFAlg *
|
||||
extern QCryptoCipher *
|
||||
qcrypto_afalg_cipher_ctx_new(QCryptoCipherAlgorithm alg,
|
||||
QCryptoCipherMode mode,
|
||||
const uint8_t *key,
|
||||
size_t nkey, Error **errp);
|
||||
|
||||
extern struct QCryptoCipherDriver qcrypto_cipher_afalg_driver;
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -16,7 +16,6 @@ typedef struct aes_key_st AES_KEY;
|
|||
#define AES_set_decrypt_key QEMU_AES_set_decrypt_key
|
||||
#define AES_encrypt QEMU_AES_encrypt
|
||||
#define AES_decrypt QEMU_AES_decrypt
|
||||
#define AES_cbc_encrypt QEMU_AES_cbc_encrypt
|
||||
|
||||
int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
|
||||
AES_KEY *key);
|
||||
|
@ -27,9 +26,6 @@ void AES_encrypt(const unsigned char *in, unsigned char *out,
|
|||
const AES_KEY *key);
|
||||
void AES_decrypt(const unsigned char *in, unsigned char *out,
|
||||
const AES_KEY *key);
|
||||
void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
|
||||
const unsigned long length, const AES_KEY *key,
|
||||
unsigned char *ivec, const int enc);
|
||||
|
||||
extern const uint8_t AES_sbox[256];
|
||||
extern const uint8_t AES_isbox[256];
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "qapi/qapi-types-crypto.h"
|
||||
|
||||
typedef struct QCryptoCipher QCryptoCipher;
|
||||
typedef struct QCryptoCipherDriver QCryptoCipherDriver;
|
||||
|
||||
/* See also "QCryptoCipherAlgorithm" and "QCryptoCipherMode"
|
||||
* enums defined in qapi/crypto.json */
|
||||
|
@ -79,8 +80,7 @@ typedef struct QCryptoCipher QCryptoCipher;
|
|||
struct QCryptoCipher {
|
||||
QCryptoCipherAlgorithm alg;
|
||||
QCryptoCipherMode mode;
|
||||
void *opaque;
|
||||
void *driver;
|
||||
const QCryptoCipherDriver *driver;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -70,8 +70,10 @@ static void test_cipher_speed(size_t chunk_size,
|
|||
}
|
||||
g_test_timer_elapsed();
|
||||
|
||||
g_test_message("Enc chunk %zu bytes ", chunk_size);
|
||||
g_test_message("%.2f MB/sec ", (double)total / MiB / g_test_timer_last());
|
||||
g_test_message("enc(%s-%s) chunk %zu bytes %.2f MB/sec ",
|
||||
QCryptoCipherAlgorithm_str(alg),
|
||||
QCryptoCipherMode_str(mode),
|
||||
chunk_size, (double)total / MiB / g_test_timer_last());
|
||||
|
||||
g_test_timer_start();
|
||||
remain = total;
|
||||
|
@ -85,8 +87,10 @@ static void test_cipher_speed(size_t chunk_size,
|
|||
}
|
||||
g_test_timer_elapsed();
|
||||
|
||||
g_test_message("Dec chunk %zu bytes ", chunk_size);
|
||||
g_test_message("%.2f MB/sec ", (double)total / MiB / g_test_timer_last());
|
||||
g_test_message("dec(%s-%s) chunk %zu bytes %.2f MB/sec ",
|
||||
QCryptoCipherAlgorithm_str(alg),
|
||||
QCryptoCipherMode_str(mode),
|
||||
chunk_size, (double)total / MiB / g_test_timer_last());
|
||||
|
||||
qcrypto_cipher_free(cipher);
|
||||
g_free(plaintext);
|
||||
|
|
|
@ -48,7 +48,9 @@ static void test_hash_speed(const void *opaque)
|
|||
}
|
||||
g_test_timer_elapsed();
|
||||
|
||||
g_test_message("%.2f MB/sec ", (double)total / MiB / g_test_timer_last());
|
||||
g_test_message("hash(%s): chunk %zu bytes %.2f MB/sec",
|
||||
QCryptoHashAlgorithm_str(opts->alg),
|
||||
opts->chunk_size, total / g_test_timer_last());
|
||||
|
||||
g_free(out);
|
||||
g_free(in);
|
||||
|
|
|
@ -55,10 +55,9 @@ static void test_hmac_speed(const void *opaque)
|
|||
} while (g_test_timer_elapsed() < 5.0);
|
||||
|
||||
total /= MiB;
|
||||
g_test_message("hmac(sha256): ");
|
||||
g_test_message("Testing chunk_size %zu bytes ", chunk_size);
|
||||
g_test_message("done: %.2f MB in %.2f secs: ", total, g_test_timer_last());
|
||||
g_test_message("%.2f MB/sec\n", total / g_test_timer_last());
|
||||
g_test_message("hmac(%s): chunk %zu bytes %.2f MB/sec",
|
||||
QCryptoHashAlgorithm_str(QCRYPTO_HASH_ALG_SHA256),
|
||||
chunk_size, total / g_test_timer_last());
|
||||
|
||||
g_free(out);
|
||||
g_free(in);
|
||||
|
|
Loading…
Reference in New Issue