Merge crypto updates and misc fixes

* Introduce a GNUTLS backend for crypto algorithms
  * Change crypto library preference gnutls > gcrypt > nettle > built-in
  * Remove built-in DES impl
  * Remove XTS mode from built-in AES impl
  * Fix seccomp rules to allow resource info getters
  * Fix migration performance test
  * Use GDateTime in io/ and net/rocker/ code
  * Improve docs for -smp
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEE2vOm/bJrYpEtDo4/vobrtBUQT98FAmDu78AACgkQvobrtBUQ
 T9+TlRAAsk3hQRN8cn+7MtpdGPd1YUn/TDaWDzmTtB19hbOZFizxSNuBIzs/sqtD
 jttdsBg9he7Z99BKMSTXxNPGoMOBuijruXQpNPRAW4fXmfDh7uwPTaUDI0q1B2UH
 U67vAUaMt+I/X62BzXdZDx00neSQy30guYmJHiOr02NZMd+r6Ds0XQn/SAsnkU64
 rNoBHWTOX0HelSc6qGSZMC+VSTQK/EKbg7HP5YHqgYzxt8IhxAD0bGtFgYgCL/D8
 FAEL190CRj4J5CgC7OSRgw82Q068CvpMwo/fhk4Ctlwu2nx5oqnUcLkntalitBD0
 lj/73IW8Hdho4pBhI86CD3FU1tJ0eDtAEAUcRLWdHlAFIp5T8D9mWvaBNGD937e1
 3obcNurtkQmUPqNuVk1kYVCMuxdexfUrGHEKqONW9GqyXHy2Q8CZqOTNKNUQSJd3
 Zx/u+p0/iPGUCiQozBJp5QEPdAlU/2EQyQpo6UQ9Bctf73Pr9cpeOoIEml2kC5Z5
 oaK9KGsJUfXt/9sFqYXtXQR24iXFthhHZnQv7mANdaSeOvzu07tUxe7+Iqu4aXb+
 4YHCWcOpHG0btbwOFL/a18XtRJHycr+abxlL9w1MMAeuBfqWMLROzRh4cbqekH5C
 TogMQpcJn2D835oBqwDv6VgUBoStW14wVMBbHRfpqf0/Oekixxo=
 =iCvI
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/berrange-gitlab/tags/crypto-and-more-pull-request' into staging

Merge crypto updates and misc fixes

 * Introduce a GNUTLS backend for crypto algorithms
 * Change crypto library preference gnutls > gcrypt > nettle > built-in
 * Remove built-in DES impl
 * Remove XTS mode from built-in AES impl
 * Fix seccomp rules to allow resource info getters
 * Fix migration performance test
 * Use GDateTime in io/ and net/rocker/ code
 * Improve docs for -smp

# gpg: Signature made Wed 14 Jul 2021 15:08:00 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/crypto-and-more-pull-request: (26 commits)
  qemu-options: rewrite help for -smp options
  qemu-options: tweak to show that CPU count is optional
  qemu-options: re-arrange CPU topology options
  docs: fix typo s/Intel/AMD/ in CPU model notes
  tests/migration: fix unix socket migration
  seccomp: don't block getters for resource control syscalls
  io: use GDateTime for formatting timestamp for websock headers
  net/rocker: use GDateTime for formatting timestamp in debug messages
  crypto: prefer gnutls as the crypto backend if new enough
  crypto: add gnutls pbkdf provider
  crypto: add gnutls hmac provider
  crypto: add gnutls hash provider
  crypto: add gnutls cipher provider
  crypto: introduce build system for gnutls crypto backend
  crypto: flip priority of backends to prefer gcrypt
  crypto: replace 'des-rfb' cipher with 'des'
  crypto: delete built-in XTS cipher mode support
  crypto: delete built-in DES implementation
  crypto: add crypto tests for single block DES-ECB and DES-CBC
  crypto: drop custom XTS support in gcrypt driver
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
master
Peter Maydell 2021-07-15 19:06:08 +01:00
commit d4127349e3
25 changed files with 865 additions and 913 deletions

View File

@ -19,8 +19,6 @@
*/
#include "crypto/aes.h"
#include "crypto/desrfb.h"
#include "crypto/xts.h"
typedef struct QCryptoCipherBuiltinAESContext QCryptoCipherBuiltinAESContext;
struct QCryptoCipherBuiltinAESContext {
@ -32,7 +30,6 @@ typedef struct QCryptoCipherBuiltinAES QCryptoCipherBuiltinAES;
struct QCryptoCipherBuiltinAES {
QCryptoCipher base;
QCryptoCipherBuiltinAESContext key;
QCryptoCipherBuiltinAESContext key_tweak;
uint8_t iv[AES_BLOCK_SIZE];
};
@ -194,39 +191,6 @@ static int qcrypto_cipher_aes_decrypt_cbc(QCryptoCipher *cipher,
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)
{
@ -257,84 +221,16 @@ static const struct QCryptoCipherDriver qcrypto_cipher_aes_driver_cbc = {
.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;
@ -356,18 +252,6 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
}
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:
@ -382,9 +266,6 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
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;
}
@ -392,19 +273,6 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
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;

View File

@ -18,17 +18,13 @@
*
*/
#ifdef CONFIG_QEMU_PRIVATE_XTS
#include "crypto/xts.h"
#endif
#include <gcrypt.h>
bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
QCryptoCipherMode mode)
{
switch (alg) {
case QCRYPTO_CIPHER_ALG_DES_RFB:
case QCRYPTO_CIPHER_ALG_DES:
case QCRYPTO_CIPHER_ALG_3DES:
case QCRYPTO_CIPHER_ALG_AES_128:
case QCRYPTO_CIPHER_ALG_AES_192:
@ -59,10 +55,6 @@ typedef struct QCryptoCipherGcrypt {
QCryptoCipher base;
gcry_cipher_hd_t handle;
size_t blocksize;
#ifdef CONFIG_QEMU_PRIVATE_XTS
gcry_cipher_hd_t tweakhandle;
uint8_t iv[XTS_BLOCK_SIZE];
#endif
} QCryptoCipherGcrypt;
@ -178,90 +170,6 @@ static const struct QCryptoCipherDriver qcrypto_gcrypt_ctr_driver = {
.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,
@ -278,7 +186,7 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
}
switch (alg) {
case QCRYPTO_CIPHER_ALG_DES_RFB:
case QCRYPTO_CIPHER_ALG_DES:
gcryalg = GCRY_CIPHER_DES;
break;
case QCRYPTO_CIPHER_ALG_3DES:
@ -323,12 +231,7 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
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;
@ -354,44 +257,7 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
}
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",
gcry_strerror(err));
goto error;
}
}
#endif
if (alg == QCRYPTO_CIPHER_ALG_DES_RFB) {
/* We're using standard DES cipher from gcrypt, so we need
* to munge the key so that the results are the same as the
* bizarre RFB variant of DES :-)
*/
uint8_t *rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey);
err = gcry_cipher_setkey(ctx->handle, rfbkey, nkey);
g_free(rfbkey);
} else {
#ifdef CONFIG_QEMU_PRIVATE_XTS
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
nkey /= 2;
err = gcry_cipher_setkey(ctx->tweakhandle, key + nkey, nkey);
if (err != 0) {
error_setg(errp, "Cannot set key: %s", gcry_strerror(err));
goto error;
}
}
#endif
err = gcry_cipher_setkey(ctx->handle, key, nkey);
}
err = gcry_cipher_setkey(ctx->handle, key, nkey);
if (err != 0) {
error_setg(errp, "Cannot set key: %s", gcry_strerror(err));
goto error;
@ -400,9 +266,6 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
return &ctx->base;
error:
#ifdef CONFIG_QEMU_PRIVATE_XTS
gcry_cipher_close(ctx->tweakhandle);
#endif
gcry_cipher_close(ctx->handle);
g_free(ctx);
return NULL;

335
crypto/cipher-gnutls.c.inc Normal file
View File

@ -0,0 +1,335 @@
/*
* QEMU Crypto cipher gnutls algorithms
*
* Copyright (c) 2021 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 "cipherpriv.h"
#include <gnutls/crypto.h>
#if GNUTLS_VERSION_NUMBER >= 0x030608
#define QEMU_GNUTLS_XTS
#endif
bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
QCryptoCipherMode mode)
{
switch (mode) {
case QCRYPTO_CIPHER_MODE_ECB:
case QCRYPTO_CIPHER_MODE_CBC:
switch (alg) {
case QCRYPTO_CIPHER_ALG_AES_128:
case QCRYPTO_CIPHER_ALG_AES_192:
case QCRYPTO_CIPHER_ALG_AES_256:
case QCRYPTO_CIPHER_ALG_DES:
case QCRYPTO_CIPHER_ALG_3DES:
return true;
default:
return false;
}
#ifdef QEMU_GNUTLS_XTS
case QCRYPTO_CIPHER_MODE_XTS:
switch (alg) {
case QCRYPTO_CIPHER_ALG_AES_128:
case QCRYPTO_CIPHER_ALG_AES_256:
return true;
default:
return false;
}
#endif
default:
return false;
}
}
typedef struct QCryptoCipherGnutls QCryptoCipherGnutls;
struct QCryptoCipherGnutls {
QCryptoCipher base;
gnutls_cipher_hd_t handle; /* XTS & CBC mode */
gnutls_cipher_algorithm_t galg; /* ECB mode */
guint8 *key; /* ECB mode */
size_t nkey; /* ECB mode */
size_t blocksize;
};
static void
qcrypto_gnutls_cipher_free(QCryptoCipher *cipher)
{
QCryptoCipherGnutls *ctx = container_of(cipher, QCryptoCipherGnutls, base);
g_free(ctx->key);
if (ctx->handle) {
gnutls_cipher_deinit(ctx->handle);
}
g_free(ctx);
}
static int
qcrypto_gnutls_cipher_encrypt(QCryptoCipher *cipher,
const void *in,
void *out,
size_t len,
Error **errp)
{
QCryptoCipherGnutls *ctx = container_of(cipher, QCryptoCipherGnutls, base);
int err;
if (len % ctx->blocksize) {
error_setg(errp, "Length %zu must be a multiple of block size %zu",
len, ctx->blocksize);
return -1;
}
if (ctx->handle) { /* CBC / XTS mode */
err = gnutls_cipher_encrypt2(ctx->handle,
in, len,
out, len);
if (err != 0) {
error_setg(errp, "Cannot encrypt data: %s",
gnutls_strerror(err));
return -1;
}
} else { /* ECB mode very inefficiently faked with CBC */
g_autofree unsigned char *iv = g_new0(unsigned char, ctx->blocksize);
while (len) {
gnutls_cipher_hd_t handle;
gnutls_datum_t gkey = { (unsigned char *)ctx->key, ctx->nkey };
int err = gnutls_cipher_init(&handle, ctx->galg, &gkey, NULL);
if (err != 0) {
error_setg(errp, "Cannot initialize cipher: %s",
gnutls_strerror(err));
return -1;
}
gnutls_cipher_set_iv(handle, iv, ctx->blocksize);
err = gnutls_cipher_encrypt2(handle,
in, ctx->blocksize,
out, ctx->blocksize);
if (err != 0) {
gnutls_cipher_deinit(handle);
error_setg(errp, "Cannot encrypt data: %s",
gnutls_strerror(err));
return -1;
}
gnutls_cipher_deinit(handle);
len -= ctx->blocksize;
in += ctx->blocksize;
out += ctx->blocksize;
}
}
return 0;
}
static int
qcrypto_gnutls_cipher_decrypt(QCryptoCipher *cipher,
const void *in,
void *out,
size_t len,
Error **errp)
{
QCryptoCipherGnutls *ctx = container_of(cipher, QCryptoCipherGnutls, base);
int err;
if (len % ctx->blocksize) {
error_setg(errp, "Length %zu must be a multiple of block size %zu",
len, ctx->blocksize);
return -1;
}
if (ctx->handle) { /* CBC / XTS mode */
err = gnutls_cipher_decrypt2(ctx->handle,
in, len,
out, len);
if (err != 0) {
error_setg(errp, "Cannot decrypt data: %s",
gnutls_strerror(err));
return -1;
}
} else { /* ECB mode very inefficiently faked with CBC */
g_autofree unsigned char *iv = g_new0(unsigned char, ctx->blocksize);
while (len) {
gnutls_cipher_hd_t handle;
gnutls_datum_t gkey = { (unsigned char *)ctx->key, ctx->nkey };
int err = gnutls_cipher_init(&handle, ctx->galg, &gkey, NULL);
if (err != 0) {
error_setg(errp, "Cannot initialize cipher: %s",
gnutls_strerror(err));
return -1;
}
gnutls_cipher_set_iv(handle, iv, ctx->blocksize);
err = gnutls_cipher_decrypt2(handle,
in, ctx->blocksize,
out, ctx->blocksize);
if (err != 0) {
gnutls_cipher_deinit(handle);
error_setg(errp, "Cannot encrypt data: %s",
gnutls_strerror(err));
return -1;
}
gnutls_cipher_deinit(handle);
len -= ctx->blocksize;
in += ctx->blocksize;
out += ctx->blocksize;
}
}
return 0;
}
static int
qcrypto_gnutls_cipher_setiv(QCryptoCipher *cipher,
const uint8_t *iv, size_t niv,
Error **errp)
{
QCryptoCipherGnutls *ctx = container_of(cipher, QCryptoCipherGnutls, base);
if (niv != ctx->blocksize) {
error_setg(errp, "Expected IV size %zu not %zu",
ctx->blocksize, niv);
return -1;
}
gnutls_cipher_set_iv(ctx->handle, (unsigned char *)iv, niv);
return 0;
}
static struct QCryptoCipherDriver gnutls_driver = {
.cipher_encrypt = qcrypto_gnutls_cipher_encrypt,
.cipher_decrypt = qcrypto_gnutls_cipher_decrypt,
.cipher_setiv = qcrypto_gnutls_cipher_setiv,
.cipher_free = qcrypto_gnutls_cipher_free,
};
static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
QCryptoCipherMode mode,
const uint8_t *key,
size_t nkey,
Error **errp)
{
QCryptoCipherGnutls *ctx;
gnutls_datum_t gkey = { (unsigned char *)key, nkey };
gnutls_cipher_algorithm_t galg = GNUTLS_CIPHER_UNKNOWN;
int err;
switch (mode) {
#ifdef QEMU_GNUTLS_XTS
case QCRYPTO_CIPHER_MODE_XTS:
switch (alg) {
case QCRYPTO_CIPHER_ALG_AES_128:
galg = GNUTLS_CIPHER_AES_128_XTS;
break;
case QCRYPTO_CIPHER_ALG_AES_256:
galg = GNUTLS_CIPHER_AES_256_XTS;
break;
default:
break;
}
break;
#endif
case QCRYPTO_CIPHER_MODE_ECB:
case QCRYPTO_CIPHER_MODE_CBC:
switch (alg) {
case QCRYPTO_CIPHER_ALG_AES_128:
galg = GNUTLS_CIPHER_AES_128_CBC;
break;
case QCRYPTO_CIPHER_ALG_AES_192:
galg = GNUTLS_CIPHER_AES_192_CBC;
break;
case QCRYPTO_CIPHER_ALG_AES_256:
galg = GNUTLS_CIPHER_AES_256_CBC;
break;
case QCRYPTO_CIPHER_ALG_DES:
galg = GNUTLS_CIPHER_DES_CBC;
break;
case QCRYPTO_CIPHER_ALG_3DES:
galg = GNUTLS_CIPHER_3DES_CBC;
break;
default:
break;
}
break;
default:
break;
}
if (galg == GNUTLS_CIPHER_UNKNOWN) {
error_setg(errp, "Unsupported cipher algorithm %s with %s mode",
QCryptoCipherAlgorithm_str(alg),
QCryptoCipherMode_str(mode));
return NULL;
}
if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
return NULL;
}
ctx = g_new0(QCryptoCipherGnutls, 1);
ctx->base.driver = &gnutls_driver;
if (mode == QCRYPTO_CIPHER_MODE_ECB) {
ctx->key = g_new0(guint8, nkey);
memcpy(ctx->key, key, nkey);
ctx->nkey = nkey;
ctx->galg = galg;
} else {
err = gnutls_cipher_init(&ctx->handle, galg, &gkey, NULL);
if (err != 0) {
error_setg(errp, "Cannot initialize cipher: %s",
gnutls_strerror(err));
goto error;
}
}
if (alg == QCRYPTO_CIPHER_ALG_DES ||
alg == QCRYPTO_CIPHER_ALG_3DES)
ctx->blocksize = 8;
else
ctx->blocksize = 16;
/*
* Our API contract for requires iv to be optional
* but nettle gets unhappy when called by gnutls
* in this case, so we just force set a default
* all-zeros IV, to match behaviour of other backends.
*/
if (mode != QCRYPTO_CIPHER_MODE_ECB) {
g_autofree unsigned char *iv = g_new0(unsigned char, ctx->blocksize);
gnutls_cipher_set_iv(ctx->handle, iv, ctx->blocksize);
}
return &ctx->base;
error:
qcrypto_gnutls_cipher_free(&ctx->base);
return NULL;
}

View File

@ -235,11 +235,11 @@ static const struct QCryptoCipherDriver NAME##_driver_xts = { \
DEFINE_XTS(NAME, TYPE, BLEN, ENCRYPT, DECRYPT)
typedef struct QCryptoNettleDESRFB {
typedef struct QCryptoNettleDES {
QCryptoCipher base;
struct des_ctx key;
uint8_t iv[DES_BLOCK_SIZE];
} QCryptoNettleDESRFB;
} QCryptoNettleDES;
static void des_encrypt_native(const void *ctx, size_t length,
uint8_t *dst, const uint8_t *src)
@ -253,7 +253,7 @@ static void des_decrypt_native(const void *ctx, size_t length,
des_decrypt(ctx, length, dst, src);
}
DEFINE_ECB_CBC_CTR(qcrypto_nettle_des_rfb, QCryptoNettleDESRFB,
DEFINE_ECB_CBC_CTR(qcrypto_nettle_des, QCryptoNettleDES,
DES_BLOCK_SIZE, des_encrypt_native, des_decrypt_native)
@ -431,7 +431,7 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
QCryptoCipherMode mode)
{
switch (alg) {
case QCRYPTO_CIPHER_ALG_DES_RFB:
case QCRYPTO_CIPHER_ALG_DES:
case QCRYPTO_CIPHER_ALG_3DES:
case QCRYPTO_CIPHER_ALG_AES_128:
case QCRYPTO_CIPHER_ALG_AES_192:
@ -480,32 +480,28 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
}
switch (alg) {
case QCRYPTO_CIPHER_ALG_DES_RFB:
case QCRYPTO_CIPHER_ALG_DES:
{
QCryptoNettleDESRFB *ctx;
QCryptoNettleDES *ctx;
const QCryptoCipherDriver *drv;
uint8_t *rfbkey;
switch (mode) {
case QCRYPTO_CIPHER_MODE_ECB:
drv = &qcrypto_nettle_des_rfb_driver_ecb;
drv = &qcrypto_nettle_des_driver_ecb;
break;
case QCRYPTO_CIPHER_MODE_CBC:
drv = &qcrypto_nettle_des_rfb_driver_cbc;
drv = &qcrypto_nettle_des_driver_cbc;
break;
case QCRYPTO_CIPHER_MODE_CTR:
drv = &qcrypto_nettle_des_rfb_driver_ctr;
drv = &qcrypto_nettle_des_driver_ctr;
break;
default:
goto bad_cipher_mode;
}
ctx = g_new0(QCryptoNettleDESRFB, 1);
ctx = g_new0(QCryptoNettleDES, 1);
ctx->base.driver = drv;
rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey);
des_set_key(&ctx->key, rfbkey);
g_free(rfbkey);
des_set_key(&ctx->key, key);
return &ctx->base;
}

View File

@ -29,7 +29,7 @@ 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,
[QCRYPTO_CIPHER_ALG_DES_RFB] = 8,
[QCRYPTO_CIPHER_ALG_DES] = 8,
[QCRYPTO_CIPHER_ALG_3DES] = 24,
[QCRYPTO_CIPHER_ALG_CAST5_128] = 16,
[QCRYPTO_CIPHER_ALG_SERPENT_128] = 16,
@ -44,7 +44,7 @@ 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,
[QCRYPTO_CIPHER_ALG_DES_RFB] = 8,
[QCRYPTO_CIPHER_ALG_DES] = 8,
[QCRYPTO_CIPHER_ALG_3DES] = 8,
[QCRYPTO_CIPHER_ALG_CAST5_128] = 8,
[QCRYPTO_CIPHER_ALG_SERPENT_128] = 16,
@ -107,9 +107,9 @@ qcrypto_cipher_validate_key_length(QCryptoCipherAlgorithm alg,
}
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
if (alg == QCRYPTO_CIPHER_ALG_DES_RFB
|| alg == QCRYPTO_CIPHER_ALG_3DES) {
error_setg(errp, "XTS mode not compatible with DES-RFB/3DES");
if (alg == QCRYPTO_CIPHER_ALG_DES ||
alg == QCRYPTO_CIPHER_ALG_3DES) {
error_setg(errp, "XTS mode not compatible with DES/3DES");
return false;
}
if (nkey % 2) {
@ -132,28 +132,12 @@ qcrypto_cipher_validate_key_length(QCryptoCipherAlgorithm alg,
return true;
}
#if defined(CONFIG_GCRYPT) || defined(CONFIG_NETTLE)
static uint8_t *
qcrypto_cipher_munge_des_rfb_key(const uint8_t *key,
size_t nkey)
{
uint8_t *ret = g_new0(uint8_t, nkey);
size_t i;
for (i = 0; i < nkey; i++) {
uint8_t r = key[i];
r = (r & 0xf0) >> 4 | (r & 0x0f) << 4;
r = (r & 0xcc) >> 2 | (r & 0x33) << 2;
r = (r & 0xaa) >> 1 | (r & 0x55) << 1;
ret[i] = r;
}
return ret;
}
#endif /* CONFIG_GCRYPT || CONFIG_NETTLE */
#ifdef CONFIG_GCRYPT
#include "cipher-gcrypt.c.inc"
#elif defined CONFIG_NETTLE
#include "cipher-nettle.c.inc"
#elif defined CONFIG_GNUTLS_CRYPTO
#include "cipher-gnutls.c.inc"
#else
#include "cipher-builtin.c.inc"
#endif

View File

@ -1,416 +0,0 @@
/*
* This is D3DES (V5.09) by Richard Outerbridge with the double and
* triple-length support removed for use in VNC. Also the bytebit[] array
* has been reversed so that the most significant bit in each byte of the
* key is ignored, not the least significant.
*
* These changes are:
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
*
* This software 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.
*/
/* D3DES (V5.09) -
*
* A portable, public domain, version of the Data Encryption Standard.
*
* Written with Symantec's THINK (Lightspeed) C by Richard Outerbridge.
* Thanks to: Dan Hoey for his excellent Initial and Inverse permutation
* code; Jim Gillogly & Phil Karn for the DES key schedule code; Dennis
* Ferguson, Eric Young and Dana How for comparing notes; and Ray Lau,
* for humouring me on.
*
* Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge.
* (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992.
*/
#include "qemu/osdep.h"
#include "crypto/desrfb.h"
static void scrunch(unsigned char *, unsigned long *);
static void unscrun(unsigned long *, unsigned char *);
static void desfunc(unsigned long *, unsigned long *);
static void cookey(unsigned long *);
static unsigned long KnL[32] = { 0L };
static const unsigned short bytebit[8] = {
01, 02, 04, 010, 020, 040, 0100, 0200 };
static const unsigned long bigbyte[24] = {
0x800000L, 0x400000L, 0x200000L, 0x100000L,
0x80000L, 0x40000L, 0x20000L, 0x10000L,
0x8000L, 0x4000L, 0x2000L, 0x1000L,
0x800L, 0x400L, 0x200L, 0x100L,
0x80L, 0x40L, 0x20L, 0x10L,
0x8L, 0x4L, 0x2L, 0x1L };
/* Use the key schedule specified in the Standard (ANSI X3.92-1981). */
static const unsigned char pc1[56] = {
56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17,
9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35,
62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21,
13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3 };
static const unsigned char totrot[16] = {
1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28 };
static const unsigned char pc2[48] = {
13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9,
22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1,
40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 };
/* Thanks to James Gillogly & Phil Karn! */
void deskey(unsigned char *key, int edf)
{
register int i, j, l, m, n;
unsigned char pc1m[56], pcr[56];
unsigned long kn[32];
for ( j = 0; j < 56; j++ ) {
l = pc1[j];
m = l & 07;
pc1m[j] = (key[l >> 3] & bytebit[m]) ? 1 : 0;
}
for( i = 0; i < 16; i++ ) {
if( edf == DE1 ) m = (15 - i) << 1;
else m = i << 1;
n = m + 1;
kn[m] = kn[n] = 0L;
for( j = 0; j < 28; j++ ) {
l = j + totrot[i];
if( l < 28 ) pcr[j] = pc1m[l];
else pcr[j] = pc1m[l - 28];
}
for( j = 28; j < 56; j++ ) {
l = j + totrot[i];
if( l < 56 ) pcr[j] = pc1m[l];
else pcr[j] = pc1m[l - 28];
}
for( j = 0; j < 24; j++ ) {
if( pcr[pc2[j]] ) kn[m] |= bigbyte[j];
if( pcr[pc2[j + 24]] ) kn[n] |= bigbyte[j];
}
}
cookey(kn);
return;
}
static void cookey(register unsigned long *raw1)
{
register unsigned long *cook, *raw0;
unsigned long dough[32];
register int i;
cook = dough;
for( i = 0; i < 16; i++, raw1++ ) {
raw0 = raw1++;
*cook = (*raw0 & 0x00fc0000L) << 6;
*cook |= (*raw0 & 0x00000fc0L) << 10;
*cook |= (*raw1 & 0x00fc0000L) >> 10;
*cook++ |= (*raw1 & 0x00000fc0L) >> 6;
*cook = (*raw0 & 0x0003f000L) << 12;
*cook |= (*raw0 & 0x0000003fL) << 16;
*cook |= (*raw1 & 0x0003f000L) >> 4;
*cook++ |= (*raw1 & 0x0000003fL);
}
usekey(dough);
return;
}
void usekey(register unsigned long *from)
{
register unsigned long *to, *endp;
to = KnL, endp = &KnL[32];
while( to < endp ) *to++ = *from++;
return;
}
void des(unsigned char *inblock, unsigned char *outblock)
{
unsigned long work[2];
scrunch(inblock, work);
desfunc(work, KnL);
unscrun(work, outblock);
return;
}
static void scrunch(register unsigned char *outof, register unsigned long *into)
{
*into = (*outof++ & 0xffL) << 24;
*into |= (*outof++ & 0xffL) << 16;
*into |= (*outof++ & 0xffL) << 8;
*into++ |= (*outof++ & 0xffL);
*into = (*outof++ & 0xffL) << 24;
*into |= (*outof++ & 0xffL) << 16;
*into |= (*outof++ & 0xffL) << 8;
*into |= (*outof & 0xffL);
return;
}
static void unscrun(register unsigned long *outof, register unsigned char *into)
{
*into++ = (unsigned char)((*outof >> 24) & 0xffL);
*into++ = (unsigned char)((*outof >> 16) & 0xffL);
*into++ = (unsigned char)((*outof >> 8) & 0xffL);
*into++ = (unsigned char)(*outof++ & 0xffL);
*into++ = (unsigned char)((*outof >> 24) & 0xffL);
*into++ = (unsigned char)((*outof >> 16) & 0xffL);
*into++ = (unsigned char)((*outof >> 8) & 0xffL);
*into = (unsigned char)(*outof & 0xffL);
return;
}
static const unsigned long SP1[64] = {
0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L,
0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L,
0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L,
0x01000404L, 0x01010004L, 0x01000000L, 0x00000004L,
0x00000404L, 0x01000400L, 0x01000400L, 0x00010400L,
0x00010400L, 0x01010000L, 0x01010000L, 0x01000404L,
0x00010004L, 0x01000004L, 0x01000004L, 0x00010004L,
0x00000000L, 0x00000404L, 0x00010404L, 0x01000000L,
0x00010000L, 0x01010404L, 0x00000004L, 0x01010000L,
0x01010400L, 0x01000000L, 0x01000000L, 0x00000400L,
0x01010004L, 0x00010000L, 0x00010400L, 0x01000004L,
0x00000400L, 0x00000004L, 0x01000404L, 0x00010404L,
0x01010404L, 0x00010004L, 0x01010000L, 0x01000404L,
0x01000004L, 0x00000404L, 0x00010404L, 0x01010400L,
0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L,
0x00010004L, 0x00010400L, 0x00000000L, 0x01010004L };
static const unsigned long SP2[64] = {
0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L,
0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L,
0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L,
0x80008000L, 0x00100000L, 0x00000020L, 0x80100020L,
0x00108000L, 0x00100020L, 0x80008020L, 0x00000000L,
0x80000000L, 0x00008000L, 0x00108020L, 0x80100000L,
0x00100020L, 0x80000020L, 0x00000000L, 0x00108000L,
0x00008020L, 0x80108000L, 0x80100000L, 0x00008020L,
0x00000000L, 0x00108020L, 0x80100020L, 0x00100000L,
0x80008020L, 0x80100000L, 0x80108000L, 0x00008000L,
0x80100000L, 0x80008000L, 0x00000020L, 0x80108020L,
0x00108020L, 0x00000020L, 0x00008000L, 0x80000000L,
0x00008020L, 0x80108000L, 0x00100000L, 0x80000020L,
0x00100020L, 0x80008020L, 0x80000020L, 0x00100020L,
0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L,
0x80000000L, 0x80100020L, 0x80108020L, 0x00108000L };
static const unsigned long SP3[64] = {
0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L,
0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L,
0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L,
0x08020208L, 0x00020008L, 0x08020000L, 0x00000208L,
0x08000000L, 0x00000008L, 0x08020200L, 0x00000200L,
0x00020200L, 0x08020000L, 0x08020008L, 0x00020208L,
0x08000208L, 0x00020200L, 0x00020000L, 0x08000208L,
0x00000008L, 0x08020208L, 0x00000200L, 0x08000000L,
0x08020200L, 0x08000000L, 0x00020008L, 0x00000208L,
0x00020000L, 0x08020200L, 0x08000200L, 0x00000000L,
0x00000200L, 0x00020008L, 0x08020208L, 0x08000200L,
0x08000008L, 0x00000200L, 0x00000000L, 0x08020008L,
0x08000208L, 0x00020000L, 0x08000000L, 0x08020208L,
0x00000008L, 0x00020208L, 0x00020200L, 0x08000008L,
0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L,
0x00020208L, 0x00000008L, 0x08020008L, 0x00020200L };
static const unsigned long SP4[64] = {
0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L,
0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L,
0x00000081L, 0x00000000L, 0x00800080L, 0x00800001L,
0x00000001L, 0x00002000L, 0x00800000L, 0x00802001L,
0x00000080L, 0x00800000L, 0x00002001L, 0x00002080L,
0x00800081L, 0x00000001L, 0x00002080L, 0x00800080L,
0x00002000L, 0x00802080L, 0x00802081L, 0x00000081L,
0x00800080L, 0x00800001L, 0x00802000L, 0x00802081L,
0x00000081L, 0x00000000L, 0x00000000L, 0x00802000L,
0x00002080L, 0x00800080L, 0x00800081L, 0x00000001L,
0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
0x00802081L, 0x00000081L, 0x00000001L, 0x00002000L,
0x00800001L, 0x00002001L, 0x00802080L, 0x00800081L,
0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L,
0x00000080L, 0x00800000L, 0x00002000L, 0x00802080L };
static const unsigned long SP5[64] = {
0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L,
0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L,
0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L,
0x42000100L, 0x42080000L, 0x00080100L, 0x40000000L,
0x02000000L, 0x40080000L, 0x40080000L, 0x00000000L,
0x40000100L, 0x42080100L, 0x42080100L, 0x02000100L,
0x42080000L, 0x40000100L, 0x00000000L, 0x42000000L,
0x02080100L, 0x02000000L, 0x42000000L, 0x00080100L,
0x00080000L, 0x42000100L, 0x00000100L, 0x02000000L,
0x40000000L, 0x02080000L, 0x42000100L, 0x40080100L,
0x02000100L, 0x40000000L, 0x42080000L, 0x02080100L,
0x40080100L, 0x00000100L, 0x02000000L, 0x42080000L,
0x42080100L, 0x00080100L, 0x42000000L, 0x42080100L,
0x02080000L, 0x00000000L, 0x40080000L, 0x42000000L,
0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L,
0x00000000L, 0x40080000L, 0x02080100L, 0x40000100L };
static const unsigned long SP6[64] = {
0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L,
0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L,
0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L,
0x00400010L, 0x20004000L, 0x20000000L, 0x00004010L,
0x00000000L, 0x00400010L, 0x20004010L, 0x00004000L,
0x00404000L, 0x20004010L, 0x00000010L, 0x20400010L,
0x20400010L, 0x00000000L, 0x00404010L, 0x20404000L,
0x00004010L, 0x00404000L, 0x20404000L, 0x20000000L,
0x20004000L, 0x00000010L, 0x20400010L, 0x00404000L,
0x20404010L, 0x00400000L, 0x00004010L, 0x20000010L,
0x00400000L, 0x20004000L, 0x20000000L, 0x00004010L,
0x20000010L, 0x20404010L, 0x00404000L, 0x20400000L,
0x00404010L, 0x20404000L, 0x00000000L, 0x20400010L,
0x00000010L, 0x00004000L, 0x20400000L, 0x00404010L,
0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L,
0x20404000L, 0x20000000L, 0x00400010L, 0x20004010L };
static const unsigned long SP7[64] = {
0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L,
0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L,
0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L,
0x00000002L, 0x04000000L, 0x04200002L, 0x00000802L,
0x04000800L, 0x00200802L, 0x00200002L, 0x04000800L,
0x04000002L, 0x04200000L, 0x04200800L, 0x00200002L,
0x04200000L, 0x00000800L, 0x00000802L, 0x04200802L,
0x00200800L, 0x00000002L, 0x04000000L, 0x00200800L,
0x04000000L, 0x00200800L, 0x00200000L, 0x04000802L,
0x04000802L, 0x04200002L, 0x04200002L, 0x00000002L,
0x00200002L, 0x04000000L, 0x04000800L, 0x00200000L,
0x04200800L, 0x00000802L, 0x00200802L, 0x04200800L,
0x00000802L, 0x04000002L, 0x04200802L, 0x04200000L,
0x00200800L, 0x00000000L, 0x00000002L, 0x04200802L,
0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L,
0x04000002L, 0x04000800L, 0x00000800L, 0x00200002L };
static const unsigned long SP8[64] = {
0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L,
0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L,
0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L,
0x10041000L, 0x00041040L, 0x00001000L, 0x00000040L,
0x10040000L, 0x10000040L, 0x10001000L, 0x00001040L,
0x00041000L, 0x00040040L, 0x10040040L, 0x10041000L,
0x00001040L, 0x00000000L, 0x00000000L, 0x10040040L,
0x10000040L, 0x10001000L, 0x00041040L, 0x00040000L,
0x00041040L, 0x00040000L, 0x10041000L, 0x00001000L,
0x00000040L, 0x10040040L, 0x00001000L, 0x00041040L,
0x10001000L, 0x00000040L, 0x10000040L, 0x10040000L,
0x10040040L, 0x10000000L, 0x00040000L, 0x10001040L,
0x00000000L, 0x10041040L, 0x00040040L, 0x10000040L,
0x10040000L, 0x10001000L, 0x10001040L, 0x00000000L,
0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L,
0x00001040L, 0x00040040L, 0x10000000L, 0x10041000L };
static void desfunc(register unsigned long *block, register unsigned long *keys)
{
register unsigned long fval, work, right, leftt;
register int round;
leftt = block[0];
right = block[1];
work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL;
right ^= work;
leftt ^= (work << 4);
work = ((leftt >> 16) ^ right) & 0x0000ffffL;
right ^= work;
leftt ^= (work << 16);
work = ((right >> 2) ^ leftt) & 0x33333333L;
leftt ^= work;
right ^= (work << 2);
work = ((right >> 8) ^ leftt) & 0x00ff00ffL;
leftt ^= work;
right ^= (work << 8);
right = ((right << 1) | ((right >> 31) & 1L)) & 0xffffffffL;
work = (leftt ^ right) & 0xaaaaaaaaL;
leftt ^= work;
right ^= work;
leftt = ((leftt << 1) | ((leftt >> 31) & 1L)) & 0xffffffffL;
for( round = 0; round < 8; round++ ) {
work = (right << 28) | (right >> 4);
work ^= *keys++;
fval = SP7[ work & 0x3fL];
fval |= SP5[(work >> 8) & 0x3fL];
fval |= SP3[(work >> 16) & 0x3fL];
fval |= SP1[(work >> 24) & 0x3fL];
work = right ^ *keys++;
fval |= SP8[ work & 0x3fL];
fval |= SP6[(work >> 8) & 0x3fL];
fval |= SP4[(work >> 16) & 0x3fL];
fval |= SP2[(work >> 24) & 0x3fL];
leftt ^= fval;
work = (leftt << 28) | (leftt >> 4);
work ^= *keys++;
fval = SP7[ work & 0x3fL];
fval |= SP5[(work >> 8) & 0x3fL];
fval |= SP3[(work >> 16) & 0x3fL];
fval |= SP1[(work >> 24) & 0x3fL];
work = leftt ^ *keys++;
fval |= SP8[ work & 0x3fL];
fval |= SP6[(work >> 8) & 0x3fL];
fval |= SP4[(work >> 16) & 0x3fL];
fval |= SP2[(work >> 24) & 0x3fL];
right ^= fval;
}
right = (right << 31) | (right >> 1);
work = (leftt ^ right) & 0xaaaaaaaaL;
leftt ^= work;
right ^= work;
leftt = (leftt << 31) | (leftt >> 1);
work = ((leftt >> 8) ^ right) & 0x00ff00ffL;
right ^= work;
leftt ^= (work << 8);
work = ((leftt >> 2) ^ right) & 0x33333333L;
right ^= work;
leftt ^= (work << 2);
work = ((right >> 16) ^ leftt) & 0x0000ffffL;
leftt ^= work;
right ^= (work << 16);
work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL;
leftt ^= work;
right ^= (work << 4);
*block++ = right;
*block = leftt;
return;
}
/* Validation sets:
*
* Single-length key, single-length plaintext -
* Key : 0123 4567 89ab cdef
* Plain : 0123 4567 89ab cde7
* Cipher : c957 4425 6a5e d31d
*
* Double-length key, single-length plaintext -
* Key : 0123 4567 89ab cdef fedc ba98 7654 3210
* Plain : 0123 4567 89ab cde7
* Cipher : 7f1d 0a77 826b 8aff
*
* Double-length key, double-length plaintext -
* Key : 0123 4567 89ab cdef fedc ba98 7654 3210
* Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff
* Cipher : 27a0 8440 406a df60 278f 47cf 42d6 15d7
*
* Triple-length key, single-length plaintext -
* Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
* Plain : 0123 4567 89ab cde7
* Cipher : de0b 7c06 ae5e 0ed5
*
* Triple-length key, double-length plaintext -
* Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
* Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff
* Cipher : ad0d 1b30 ac17 cf07 0ed1 1c63 81e4 4de5
*
* d3des V5.0a rwo 9208.07 18:44 Graven Imagery
**********************************************************************/

104
crypto/hash-gnutls.c Normal file
View File

@ -0,0 +1,104 @@
/*
* QEMU Crypto hash algorithms
*
* Copyright (c) 2021 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 <gnutls/crypto.h>
#include "qapi/error.h"
#include "crypto/hash.h"
#include "hashpriv.h"
static int qcrypto_hash_alg_map[QCRYPTO_HASH_ALG__MAX] = {
[QCRYPTO_HASH_ALG_MD5] = GNUTLS_DIG_MD5,
[QCRYPTO_HASH_ALG_SHA1] = GNUTLS_DIG_SHA1,
[QCRYPTO_HASH_ALG_SHA224] = GNUTLS_DIG_SHA224,
[QCRYPTO_HASH_ALG_SHA256] = GNUTLS_DIG_SHA256,
[QCRYPTO_HASH_ALG_SHA384] = GNUTLS_DIG_SHA384,
[QCRYPTO_HASH_ALG_SHA512] = GNUTLS_DIG_SHA512,
[QCRYPTO_HASH_ALG_RIPEMD160] = GNUTLS_DIG_RMD160,
};
gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg)
{
size_t i;
const gnutls_digest_algorithm_t *algs;
if (alg >= G_N_ELEMENTS(qcrypto_hash_alg_map) ||
qcrypto_hash_alg_map[alg] == GNUTLS_DIG_UNKNOWN) {
return false;
}
algs = gnutls_digest_list();
for (i = 0; algs[i] != GNUTLS_DIG_UNKNOWN; i++) {
if (algs[i] == qcrypto_hash_alg_map[alg]) {
return true;
}
}
return false;
}
static int
qcrypto_gnutls_hash_bytesv(QCryptoHashAlgorithm alg,
const struct iovec *iov,
size_t niov,
uint8_t **result,
size_t *resultlen,
Error **errp)
{
int i, ret;
gnutls_hash_hd_t hash;
if (!qcrypto_hash_supports(alg)) {
error_setg(errp,
"Unknown hash algorithm %d",
alg);
return -1;
}
ret = gnutls_hash_get_len(qcrypto_hash_alg_map[alg]);
if (*resultlen == 0) {
*resultlen = ret;
*result = g_new0(uint8_t, *resultlen);
} else if (*resultlen != ret) {
error_setg(errp,
"Result buffer size %zu is smaller than hash %d",
*resultlen, ret);
return -1;
}
ret = gnutls_hash_init(&hash, qcrypto_hash_alg_map[alg]);
if (ret < 0) {
error_setg(errp,
"Unable to initialize hash algorithm: %s",
gnutls_strerror(ret));
return -1;
}
for (i = 0; i < niov; i++) {
gnutls_hash(hash, iov[i].iov_base, iov[i].iov_len);
}
gnutls_hash_deinit(hash, *result);
return 0;
}
QCryptoHashDriver qcrypto_hash_lib_driver = {
.hash_bytesv = qcrypto_gnutls_hash_bytesv,
};

139
crypto/hmac-gnutls.c Normal file
View File

@ -0,0 +1,139 @@
/*
* QEMU Crypto hmac algorithms
*
* Copyright (c) 2021 Red Hat, Inc.
*
* Derived from hmac-gcrypt.c:
*
* Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
*
* This work is licensed under the terms of the GNU GPL, version 2 or
* (at your option) any later version. See the COPYING file in the
* top-level directory.
*
*/
#include "qemu/osdep.h"
#include <gnutls/crypto.h>
#include "qapi/error.h"
#include "crypto/hmac.h"
#include "hmacpriv.h"
static int qcrypto_hmac_alg_map[QCRYPTO_HASH_ALG__MAX] = {
[QCRYPTO_HASH_ALG_MD5] = GNUTLS_MAC_MD5,
[QCRYPTO_HASH_ALG_SHA1] = GNUTLS_MAC_SHA1,
[QCRYPTO_HASH_ALG_SHA224] = GNUTLS_MAC_SHA224,
[QCRYPTO_HASH_ALG_SHA256] = GNUTLS_MAC_SHA256,
[QCRYPTO_HASH_ALG_SHA384] = GNUTLS_MAC_SHA384,
[QCRYPTO_HASH_ALG_SHA512] = GNUTLS_MAC_SHA512,
[QCRYPTO_HASH_ALG_RIPEMD160] = GNUTLS_MAC_RMD160,
};
typedef struct QCryptoHmacGnutls QCryptoHmacGnutls;
struct QCryptoHmacGnutls {
gnutls_hmac_hd_t handle;
};
bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg)
{
size_t i;
const gnutls_digest_algorithm_t *algs;
if (alg >= G_N_ELEMENTS(qcrypto_hmac_alg_map) ||
qcrypto_hmac_alg_map[alg] == GNUTLS_DIG_UNKNOWN) {
return false;
}
algs = gnutls_digest_list();
for (i = 0; algs[i] != GNUTLS_DIG_UNKNOWN; i++) {
if (algs[i] == qcrypto_hmac_alg_map[alg]) {
return true;
}
}
return false;
}
void *qcrypto_hmac_ctx_new(QCryptoHashAlgorithm alg,
const uint8_t *key, size_t nkey,
Error **errp)
{
QCryptoHmacGnutls *ctx;
int err;
if (!qcrypto_hmac_supports(alg)) {
error_setg(errp, "Unsupported hmac algorithm %s",
QCryptoHashAlgorithm_str(alg));
return NULL;
}
ctx = g_new0(QCryptoHmacGnutls, 1);
err = gnutls_hmac_init(&ctx->handle,
qcrypto_hmac_alg_map[alg],
(const void *)key, nkey);
if (err != 0) {
error_setg(errp, "Cannot initialize hmac: %s",
gnutls_strerror(err));
goto error;
}
return ctx;
error:
g_free(ctx);
return NULL;
}
static void
qcrypto_gnutls_hmac_ctx_free(QCryptoHmac *hmac)
{
QCryptoHmacGnutls *ctx;
ctx = hmac->opaque;
gnutls_hmac_deinit(ctx->handle, NULL);
g_free(ctx);
}
static int
qcrypto_gnutls_hmac_bytesv(QCryptoHmac *hmac,
const struct iovec *iov,
size_t niov,
uint8_t **result,
size_t *resultlen,
Error **errp)
{
QCryptoHmacGnutls *ctx;
uint32_t ret;
int i;
ctx = hmac->opaque;
for (i = 0; i < niov; i++) {
gnutls_hmac(ctx->handle, iov[i].iov_base, iov[i].iov_len);
}
ret = gnutls_hmac_get_len(qcrypto_hmac_alg_map[hmac->alg]);
if (ret <= 0) {
error_setg(errp, "Unable to get hmac length: %s",
gnutls_strerror(ret));
return -1;
}
if (*resultlen == 0) {
*resultlen = ret;
*result = g_new0(uint8_t, *resultlen);
} else if (*resultlen != ret) {
error_setg(errp, "Result buffer size %zu is smaller than hmac %d",
*resultlen, ret);
return -1;
}
gnutls_hmac_output(ctx->handle, *result);
return 0;
}
QCryptoHmacDriver qcrypto_hmac_lib_driver = {
.hmac_bytesv = qcrypto_gnutls_hmac_bytesv,
.hmac_free = qcrypto_gnutls_hmac_ctx_free,
};

View File

@ -35,21 +35,6 @@
#include "crypto/random.h"
/* #define DEBUG_GNUTLS */
/*
* We need to init gcrypt threading if
*
* - gcrypt < 1.6.0
*
*/
#if (defined(CONFIG_GCRYPT) && \
(GCRYPT_VERSION_NUMBER < 0x010600))
#define QCRYPTO_INIT_GCRYPT_THREADS
#else
#undef QCRYPTO_INIT_GCRYPT_THREADS
#endif
#ifdef DEBUG_GNUTLS
static void qcrypto_gnutls_log(int level, const char *str)
{
@ -57,55 +42,8 @@ static void qcrypto_gnutls_log(int level, const char *str)
}
#endif
#ifdef QCRYPTO_INIT_GCRYPT_THREADS
static int qcrypto_gcrypt_mutex_init(void **priv)
{ \
QemuMutex *lock = NULL;
lock = g_new0(QemuMutex, 1);
qemu_mutex_init(lock);
*priv = lock;
return 0;
}
static int qcrypto_gcrypt_mutex_destroy(void **priv)
{
QemuMutex *lock = *priv;
qemu_mutex_destroy(lock);
g_free(lock);
return 0;
}
static int qcrypto_gcrypt_mutex_lock(void **priv)
{
QemuMutex *lock = *priv;
qemu_mutex_lock(lock);
return 0;
}
static int qcrypto_gcrypt_mutex_unlock(void **priv)
{
QemuMutex *lock = *priv;
qemu_mutex_unlock(lock);
return 0;
}
static struct gcry_thread_cbs qcrypto_gcrypt_thread_impl = {
(GCRY_THREAD_OPTION_PTHREAD | (GCRY_THREAD_OPTION_VERSION << 8)),
NULL,
qcrypto_gcrypt_mutex_init,
qcrypto_gcrypt_mutex_destroy,
qcrypto_gcrypt_mutex_lock,
qcrypto_gcrypt_mutex_unlock,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
#endif /* QCRYPTO_INIT_GCRYPT */
int qcrypto_init(Error **errp)
{
#ifdef QCRYPTO_INIT_GCRYPT_THREADS
gcry_control(GCRYCTL_SET_THREAD_CBS, &qcrypto_gcrypt_thread_impl);
#endif /* QCRYPTO_INIT_GCRYPT_THREADS */
#ifdef CONFIG_GNUTLS
int ret;
ret = gnutls_global_init();

View File

@ -5,7 +5,6 @@ crypto_ss.add(files(
'block-qcow.c',
'block.c',
'cipher.c',
'desrfb.c',
'hash.c',
'hmac.c',
'ivgen-essiv.c',
@ -24,14 +23,16 @@ crypto_ss.add(files(
if nettle.found()
crypto_ss.add(nettle, files('hash-nettle.c', 'hmac-nettle.c', 'pbkdf-nettle.c'))
if xts == 'private'
crypto_ss.add(files('xts.c'))
endif
elif gcrypt.found()
crypto_ss.add(gcrypt, files('hash-gcrypt.c', 'hmac-gcrypt.c', 'pbkdf-gcrypt.c'))
elif gnutls_crypto.found()
crypto_ss.add(gnutls, files('hash-gnutls.c', 'hmac-gnutls.c', 'pbkdf-gnutls.c'))
else
crypto_ss.add(files('hash-glib.c', 'hmac-glib.c', 'pbkdf-stub.c'))
endif
if xts == 'private'
crypto_ss.add(files('xts.c'))
endif
crypto_ss.add(when: 'CONFIG_SECRET_KEYRING', if_true: files('secret_keyring.c'))
crypto_ss.add(when: 'CONFIG_AF_ALG', if_true: files('afalg.c', 'cipher-afalg.c', 'hash-afalg.c'))
@ -39,6 +40,9 @@ crypto_ss.add(when: gnutls, if_true: files('tls-cipher-suites.c'))
util_ss.add(files('aes.c'))
util_ss.add(files('init.c'))
if gnutls.found()
util_ss.add(gnutls)
endif
if gcrypt.found()
util_ss.add(gcrypt, files('random-gcrypt.c'))

90
crypto/pbkdf-gnutls.c Normal file
View File

@ -0,0 +1,90 @@
/*
* QEMU Crypto PBKDF support (Password-Based Key Derivation Function)
*
* Copyright (c) 2021 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 <gnutls/crypto.h>
#include "qapi/error.h"
#include "crypto/pbkdf.h"
bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash)
{
switch (hash) {
case QCRYPTO_HASH_ALG_MD5:
case QCRYPTO_HASH_ALG_SHA1:
case QCRYPTO_HASH_ALG_SHA224:
case QCRYPTO_HASH_ALG_SHA256:
case QCRYPTO_HASH_ALG_SHA384:
case QCRYPTO_HASH_ALG_SHA512:
case QCRYPTO_HASH_ALG_RIPEMD160:
return true;
default:
return false;
}
}
int qcrypto_pbkdf2(QCryptoHashAlgorithm hash,
const uint8_t *key, size_t nkey,
const uint8_t *salt, size_t nsalt,
uint64_t iterations,
uint8_t *out, size_t nout,
Error **errp)
{
static const int hash_map[QCRYPTO_HASH_ALG__MAX] = {
[QCRYPTO_HASH_ALG_MD5] = GNUTLS_DIG_MD5,
[QCRYPTO_HASH_ALG_SHA1] = GNUTLS_DIG_SHA1,
[QCRYPTO_HASH_ALG_SHA224] = GNUTLS_DIG_SHA224,
[QCRYPTO_HASH_ALG_SHA256] = GNUTLS_DIG_SHA256,
[QCRYPTO_HASH_ALG_SHA384] = GNUTLS_DIG_SHA384,
[QCRYPTO_HASH_ALG_SHA512] = GNUTLS_DIG_SHA512,
[QCRYPTO_HASH_ALG_RIPEMD160] = GNUTLS_DIG_RMD160,
};
int ret;
const gnutls_datum_t gkey = { (unsigned char *)key, nkey };
const gnutls_datum_t gsalt = { (unsigned char *)salt, nsalt };
if (iterations > ULONG_MAX) {
error_setg_errno(errp, ERANGE,
"PBKDF iterations %llu must be less than %lu",
(long long unsigned)iterations, ULONG_MAX);
return -1;
}
if (hash >= G_N_ELEMENTS(hash_map) ||
hash_map[hash] == GNUTLS_DIG_UNKNOWN) {
error_setg_errno(errp, ENOSYS,
"PBKDF does not support hash algorithm %s",
QCryptoHashAlgorithm_str(hash));
return -1;
}
ret = gnutls_pbkdf2(hash_map[hash],
&gkey,
&gsalt,
iterations,
out,
nout);
if (ret != 0) {
error_setg(errp, "Cannot derive password: %s",
gnutls_strerror(ret));
return -1;
}
return 0;
}

View File

@ -227,7 +227,7 @@ features are included if using "Host passthrough" or "Host model".
Preferred CPU models for AMD x86 hosts
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The following CPU models are preferred for use on Intel hosts.
The following CPU models are preferred for use on AMD hosts.
Administrators / applications are recommended to use the CPU model that
matches the generation of the host CPUs in use. In a deployment with a
mixture of host CPU models between machines, if live migration

View File

@ -25,14 +25,9 @@
#if defined(DEBUG_ROCKER)
# define DPRINTF(fmt, ...) \
do { \
struct timeval tv; \
char timestr[64]; \
time_t now; \
gettimeofday(&tv, NULL); \
now = tv.tv_sec; \
strftime(timestr, sizeof(timestr), "%T", localtime(&now)); \
fprintf(stderr, "%s.%06ld ", timestr, tv.tv_usec); \
fprintf(stderr, "ROCKER: " fmt, ## __VA_ARGS__); \
g_autoptr(GDateTime) now = g_date_time_new_now_local(); \
g_autofree char *nowstr = g_date_time_format(now, "%T.%f");\
fprintf(stderr, "%s ROCKER: " fmt, nowstr, ## __VA_ARGS__);\
} while (0)
#else
static inline GCC_FMT_ATTR(1, 2) int DPRINTF(const char *fmt, ...)

View File

@ -177,15 +177,9 @@ qio_channel_websock_handshake_send_res(QIOChannelWebsock *ioc,
static gchar *qio_channel_websock_date_str(void)
{
struct tm tm;
time_t now = time(NULL);
char datebuf[128];
g_autoptr(GDateTime) now = g_date_time_new_now_utc();
gmtime_r(&now, &tm);
strftime(datebuf, sizeof(datebuf), "%a, %d %b %Y %H:%M:%S GMT", &tm);
return g_strdup(datebuf);
return g_date_time_format(now, "%a, %d %b %Y %H:%M:%S GMT");
}
static void qio_channel_websock_handshake_send_res_err(QIOChannelWebsock *ioc,

View File

@ -823,50 +823,77 @@ if 'CONFIG_OPENGL' in config_host
endif
gnutls = not_found
gnutls_crypto = not_found
if not get_option('gnutls').auto() or have_system
gnutls = dependency('gnutls', version: '>=3.5.18',
method: 'pkg-config',
required: get_option('gnutls'),
kwargs: static_kwargs)
# For general TLS support our min gnutls matches
# that implied by our platform support matrix
#
# For the crypto backends, we look for a newer
# gnutls:
#
# Version 3.6.8 is needed to get XTS
# Version 3.6.13 is needed to get PBKDF
# Version 3.6.14 is needed to get HW accelerated XTS
#
# If newer enough gnutls isn't available, we can
# still use a different crypto backend to satisfy
# the platform support requirements
gnutls_crypto = dependency('gnutls', version: '>=3.6.14',
method: 'pkg-config',
required: false,
kwargs: static_kwargs)
if gnutls_crypto.found()
gnutls = gnutls_crypto
else
# Our min version if all we need is TLS
gnutls = dependency('gnutls', version: '>=3.5.18',
method: 'pkg-config',
required: get_option('gnutls'),
kwargs: static_kwargs)
endif
endif
# Nettle has priority over gcrypt
# We prefer use of gnutls for crypto, unless the options
# explicitly asked for nettle or gcrypt.
#
# If gnutls isn't available for crypto, then we'll prefer
# gcrypt over nettle for performance reasons.
gcrypt = not_found
nettle = not_found
xts = 'private'
xts = 'none'
if get_option('nettle').enabled() and get_option('gcrypt').enabled()
error('Only one of gcrypt & nettle can be enabled')
elif (not get_option('nettle').auto() or have_system) and not get_option('gcrypt').enabled()
nettle = dependency('nettle', version: '>=3.4',
method: 'pkg-config',
required: get_option('nettle'),
kwargs: static_kwargs)
if nettle.found() and cc.has_header('nettle/xts.h', dependencies: nettle)
xts = 'nettle'
endif
endif
if (not get_option('gcrypt').auto() or have_system) and not nettle.found()
gcrypt = dependency('libgcrypt', version: '>=1.5',
method: 'config-tool',
required: get_option('gcrypt'),
kwargs: static_kwargs)
if gcrypt.found() and cc.compiles('''
#include <gcrypt.h>
int main(void) {
gcry_cipher_hd_t handle;
gcry_cipher_open(&handle, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_XTS, 0);
return 0;
}
''', dependencies: gcrypt)
xts = 'gcrypt'
# Explicit nettle/gcrypt request, so ignore gnutls for crypto
if get_option('nettle').enabled() or get_option('gcrypt').enabled()
gnutls_crypto = not_found
endif
if not gnutls_crypto.found()
if (not get_option('gcrypt').auto() or have_system) and not get_option('nettle').enabled()
gcrypt = dependency('libgcrypt', version: '>=1.8',
method: 'config-tool',
required: get_option('gcrypt'),
kwargs: static_kwargs)
# Debian has removed -lgpg-error from libgcrypt-config
# as it "spreads unnecessary dependencies" which in
# turn breaks static builds...
if gcrypt.found() and enable_static
gcrypt = declare_dependency(dependencies: [
gcrypt,
cc.find_library('gpg-error', required: true, kwargs: static_kwargs)])
endif
endif
# Debian has removed -lgpg-error from libgcrypt-config
# as it "spreads unnecessary dependencies" which in
# turn breaks static builds...
if gcrypt.found() and enable_static
gcrypt = declare_dependency(dependencies: [
gcrypt,
cc.find_library('gpg-error', required: true, kwargs: static_kwargs)])
if (not get_option('nettle').auto() or have_system) and not gcrypt.found()
nettle = dependency('nettle', version: '>=3.4',
method: 'pkg-config',
required: get_option('nettle'),
kwargs: static_kwargs)
if nettle.found() and not cc.has_header('nettle/xts.h', dependencies: nettle)
xts = 'private'
endif
endif
endif
@ -1253,6 +1280,7 @@ config_host_data.set('CONFIG_XKBCOMMON', xkbcommon.found())
config_host_data.set('CONFIG_KEYUTILS', keyutils.found())
config_host_data.set('CONFIG_GETTID', has_gettid)
config_host_data.set('CONFIG_GNUTLS', gnutls.found())
config_host_data.set('CONFIG_GNUTLS_CRYPTO', gnutls_crypto.found())
config_host_data.set('CONFIG_GCRYPT', gcrypt.found())
config_host_data.set('CONFIG_NETTLE', nettle.found())
config_host_data.set('CONFIG_QEMU_PRIVATE_XTS', xts == 'private')
@ -2988,11 +3016,9 @@ summary(summary_info, bool_yn: true, section: 'Block layer support')
summary_info = {}
summary_info += {'TLS priority': config_host['CONFIG_TLS_PRIORITY']}
summary_info += {'GNUTLS support': gnutls.found()}
summary_info += {'GNUTLS crypto': gnutls_crypto.found()}
# TODO: add back version
summary_info += {'libgcrypt': gcrypt.found()}
if gcrypt.found()
summary_info += {' XTS': xts != 'private'}
endif
# TODO: add back version
summary_info += {'nettle': nettle.found()}
if nettle.found()

View File

@ -66,7 +66,7 @@
# @aes-128: AES with 128 bit / 16 byte keys
# @aes-192: AES with 192 bit / 24 byte keys
# @aes-256: AES with 256 bit / 32 byte keys
# @des-rfb: RFB specific variant of single DES. Do not use except in VNC.
# @des: DES with 56 bit / 8 byte keys. Do not use except in VNC. (since 6.1)
# @3des: 3DES(EDE) with 192 bit / 24 byte keys (since 2.9)
# @cast5-128: Cast5 with 128 bit / 16 byte keys
# @serpent-128: Serpent with 128 bit / 16 byte keys
@ -80,7 +80,7 @@
{ 'enum': 'QCryptoCipherAlgorithm',
'prefix': 'QCRYPTO_CIPHER_ALG',
'data': ['aes-128', 'aes-192', 'aes-256',
'des-rfb', '3des',
'des', '3des',
'cast5-128',
'serpent-128', 'serpent-192', 'serpent-256',
'twofish-128', 'twofish-192', 'twofish-256']}

View File

@ -196,25 +196,38 @@ SRST
ERST
DEF("smp", HAS_ARG, QEMU_OPTION_smp,
"-smp [cpus=]n[,maxcpus=cpus][,cores=cores][,threads=threads][,dies=dies][,sockets=sockets]\n"
"-smp [[cpus=]n][,maxcpus=cpus][,sockets=sockets][,dies=dies][,cores=cores][,threads=threads]\n"
" set the number of CPUs to 'n' [default=1]\n"
" maxcpus= maximum number of total cpus, including\n"
" maxcpus= maximum number of total CPUs, including\n"
" offline CPUs for hotplug, etc\n"
" cores= number of CPU cores on one socket (for PC, it's on one die)\n"
" threads= number of threads on one CPU core\n"
" sockets= number of discrete sockets in the system\n"
" dies= number of CPU dies on one socket (for PC only)\n"
" sockets= number of discrete sockets in the system\n",
" cores= number of CPU cores on one socket (for PC, it's on one die)\n"
" threads= number of threads on one CPU core\n",
QEMU_ARCH_ALL)
SRST
``-smp [cpus=]n[,cores=cores][,threads=threads][,dies=dies][,sockets=sockets][,maxcpus=maxcpus]``
Simulate an SMP system with n CPUs. On the PC target, up to 255 CPUs
are supported. On Sparc32 target, Linux limits the number of usable
CPUs to 4. For the PC target, the number of cores per die, the
number of threads per cores, the number of dies per packages and the
total number of sockets can be specified. Missing values will be
computed. If any on the three values is given, the total number of
CPUs n can be omitted. maxcpus specifies the maximum number of
hotpluggable CPUs.
``-smp [[cpus=]n][,maxcpus=maxcpus][,sockets=sockets][,dies=dies][,cores=cores][,threads=threads]``
Simulate a SMP system with '\ ``n``\ ' CPUs initially present on
the machine type board. On boards supporting CPU hotplug, the optional
'\ ``maxcpus``\ ' parameter can be set to enable further CPUs to be
added at runtime. If omitted the maximum number of CPUs will be
set to match the initial CPU count. Both parameters are subject to
an upper limit that is determined by the specific machine type chosen.
To control reporting of CPU topology information, the number of sockets,
dies per socket, cores per die, and threads per core can be specified.
The sum `` sockets * cores * dies * threads `` must be equal to the
maximum CPU count. CPU targets may only support a subset of the topology
parameters. Where a CPU target does not support use of a particular
topology parameter, its value should be assumed to be 1 for the purpose
of computing the CPU maximum count.
Either the initial CPU count, or at least one of the topology parameters
must be specified. Values for any omitted parameters will be computed
from those which are given. Historically preference was given to the
coarsest topology parameters when computing missing values (ie sockets
preferred over cores, which were preferred over threads), however, this
behaviour is considered liable to change.
ERST
DEF("numa", HAS_ARG, QEMU_OPTION_numa,

View File

@ -97,17 +97,11 @@ static const struct QemuSeccompSyscall denylist[] = {
{ SCMP_SYS(vfork), QEMU_SECCOMP_SET_SPAWN },
{ SCMP_SYS(execve), QEMU_SECCOMP_SET_SPAWN },
/* resource control */
{ SCMP_SYS(getpriority), QEMU_SECCOMP_SET_RESOURCECTL },
{ SCMP_SYS(setpriority), QEMU_SECCOMP_SET_RESOURCECTL },
{ SCMP_SYS(sched_setparam), QEMU_SECCOMP_SET_RESOURCECTL },
{ SCMP_SYS(sched_getparam), QEMU_SECCOMP_SET_RESOURCECTL },
{ SCMP_SYS(sched_setscheduler), QEMU_SECCOMP_SET_RESOURCECTL,
ARRAY_SIZE(sched_setscheduler_arg), sched_setscheduler_arg },
{ SCMP_SYS(sched_getscheduler), QEMU_SECCOMP_SET_RESOURCECTL },
{ SCMP_SYS(sched_setaffinity), QEMU_SECCOMP_SET_RESOURCECTL },
{ SCMP_SYS(sched_getaffinity), QEMU_SECCOMP_SET_RESOURCECTL },
{ SCMP_SYS(sched_get_priority_max), QEMU_SECCOMP_SET_RESOURCECTL },
{ SCMP_SYS(sched_get_priority_min), QEMU_SECCOMP_SET_RESOURCECTL },
};
static inline __attribute__((unused)) int

View File

@ -423,7 +423,7 @@ class Engine(object):
progress_history = ret[0]
qemu_timings = ret[1]
vcpu_timings = ret[2]
if uri[0:5] == "unix:":
if uri[0:5] == "unix:" and os.path.exists(uri[5:]):
os.remove(uri[5:])
if os.path.exists(srcmonaddr):

View File

@ -150,10 +150,33 @@ static QCryptoCipherTestData test_data[] = {
"b2eb05e2c39be9fcda6c19078c6a9d1b",
},
{
.path = "/crypto/cipher/des-rfb-ecb-56",
.alg = QCRYPTO_CIPHER_ALG_DES_RFB,
/*
* Testing 'password' as plaintext fits
* in single AES block, and gives identical
* ciphertext in ECB and CBC modes
*/
.path = "/crypto/cipher/des-ecb-56-one-block",
.alg = QCRYPTO_CIPHER_ALG_DES,
.mode = QCRYPTO_CIPHER_MODE_ECB,
.key = "0123456789abcdef",
.key = "80c4a2e691d5b3f7",
.plaintext = "70617373776f7264",
.ciphertext = "73fa80b66134e403",
},
{
/* See previous comment */
.path = "/crypto/cipher/des-cbc-56-one-block",
.alg = QCRYPTO_CIPHER_ALG_DES,
.mode = QCRYPTO_CIPHER_MODE_CBC,
.key = "80c4a2e691d5b3f7",
.iv = "0000000000000000",
.plaintext = "70617373776f7264",
.ciphertext = "73fa80b66134e403",
},
{
.path = "/crypto/cipher/des-ecb-56",
.alg = QCRYPTO_CIPHER_ALG_DES,
.mode = QCRYPTO_CIPHER_MODE_ECB,
.key = "80c4a2e691d5b3f7",
.plaintext =
"6bc1bee22e409f96e93d7e117393172a"
"ae2d8a571e03ac9c9eb76fac45af8e51"
@ -165,7 +188,6 @@ static QCryptoCipherTestData test_data[] = {
"ffd29f1bb5596ad94ea2d8e6196b7f09"
"30d8ed0bf2773af36dd82a6280c20926",
},
#if defined(CONFIG_NETTLE) || defined(CONFIG_GCRYPT)
{
/* Borrowed from linux-kernel crypto/testmgr.h */
.path = "/crypto/cipher/3des-cbc",
@ -283,7 +305,6 @@ static QCryptoCipherTestData test_data[] = {
"407772c2ea0e3a7846b991b6e73d5142"
"fd51b0c62c6313785ceefccfc4700034",
},
#endif
{
/* RFC 2144, Appendix B.1 */
.path = "/crypto/cipher/cast5-128",

View File

@ -104,7 +104,7 @@ static void test_hash_alloc(void)
strlen(INPUT_TEXT),
&result,
&resultlen,
NULL);
&error_fatal);
g_assert(ret == 0);
g_assert(resultlen == expected_lens[i]);
@ -139,7 +139,7 @@ static void test_hash_prealloc(void)
strlen(INPUT_TEXT),
&result,
&resultlen,
NULL);
&error_fatal);
g_assert(ret == 0);
g_assert(resultlen == expected_lens[i]);
@ -176,7 +176,7 @@ static void test_hash_iov(void)
iov, 3,
&result,
&resultlen,
NULL);
&error_fatal);
g_assert(ret == 0);
g_assert(resultlen == expected_lens[i]);
for (j = 0; j < resultlen; j++) {
@ -210,7 +210,7 @@ static void test_hash_digest(void)
INPUT_TEXT,
strlen(INPUT_TEXT),
&digest,
NULL);
&error_fatal);
g_assert(ret == 0);
g_assert_cmpstr(digest, ==, expected_outputs[i]);
g_free(digest);
@ -234,7 +234,7 @@ static void test_hash_base64(void)
INPUT_TEXT,
strlen(INPUT_TEXT),
&digest,
NULL);
&error_fatal);
g_assert(ret == 0);
g_assert_cmpstr(digest, ==, expected_outputs_b64[i]);
g_free(digest);
@ -243,7 +243,8 @@ static void test_hash_base64(void)
int main(int argc, char **argv)
{
g_assert(qcrypto_init(NULL) == 0);
int ret = qcrypto_init(&error_fatal);
g_assert(ret == 0);
g_test_init(&argc, &argv, NULL);
g_test_add_func("/crypto/hash/iov", test_hash_iov);

View File

@ -89,7 +89,6 @@ static void test_hmac_alloc(void)
QCryptoHmac *hmac = NULL;
uint8_t *result = NULL;
size_t resultlen = 0;
Error *err = NULL;
const char *exp_output = NULL;
int ret;
size_t j;
@ -101,14 +100,12 @@ static void test_hmac_alloc(void)
exp_output = data->hex_digest;
hmac = qcrypto_hmac_new(data->alg, (const uint8_t *)KEY,
strlen(KEY), &err);
g_assert(err == NULL);
strlen(KEY), &error_fatal);
g_assert(hmac != NULL);
ret = qcrypto_hmac_bytes(hmac, (const char *)INPUT_TEXT,
strlen(INPUT_TEXT), &result,
&resultlen, &err);
g_assert(err == NULL);
&resultlen, &error_fatal);
g_assert(ret == 0);
for (j = 0; j < resultlen; j++) {
@ -131,7 +128,6 @@ static void test_hmac_prealloc(void)
QCryptoHmac *hmac = NULL;
uint8_t *result = NULL;
size_t resultlen = 0;
Error *err = NULL;
const char *exp_output = NULL;
int ret;
size_t j;
@ -146,14 +142,12 @@ static void test_hmac_prealloc(void)
result = g_new0(uint8_t, resultlen);
hmac = qcrypto_hmac_new(data->alg, (const uint8_t *)KEY,
strlen(KEY), &err);
g_assert(err == NULL);
strlen(KEY), &error_fatal);
g_assert(hmac != NULL);
ret = qcrypto_hmac_bytes(hmac, (const char *)INPUT_TEXT,
strlen(INPUT_TEXT), &result,
&resultlen, &err);
g_assert(err == NULL);
&resultlen, &error_fatal);
g_assert(ret == 0);
exp_output = data->hex_digest;
@ -177,7 +171,6 @@ static void test_hmac_iov(void)
QCryptoHmac *hmac = NULL;
uint8_t *result = NULL;
size_t resultlen = 0;
Error *err = NULL;
const char *exp_output = NULL;
int ret;
size_t j;
@ -194,13 +187,11 @@ static void test_hmac_iov(void)
exp_output = data->hex_digest;
hmac = qcrypto_hmac_new(data->alg, (const uint8_t *)KEY,
strlen(KEY), &err);
g_assert(err == NULL);
strlen(KEY), &error_fatal);
g_assert(hmac != NULL);
ret = qcrypto_hmac_bytesv(hmac, iov, 3, &result,
&resultlen, &err);
g_assert(err == NULL);
&resultlen, &error_fatal);
g_assert(ret == 0);
for (j = 0; j < resultlen; j++) {
@ -222,7 +213,6 @@ static void test_hmac_digest(void)
QCryptoHmacTestData *data = &test_data[i];
QCryptoHmac *hmac = NULL;
uint8_t *result = NULL;
Error *err = NULL;
const char *exp_output = NULL;
int ret;
@ -233,14 +223,12 @@ static void test_hmac_digest(void)
exp_output = data->hex_digest;
hmac = qcrypto_hmac_new(data->alg, (const uint8_t *)KEY,
strlen(KEY), &err);
g_assert(err == NULL);
strlen(KEY), &error_fatal);
g_assert(hmac != NULL);
ret = qcrypto_hmac_digest(hmac, (const char *)INPUT_TEXT,
strlen(INPUT_TEXT), (char **)&result,
&err);
g_assert(err == NULL);
&error_fatal);
g_assert(ret == 0);
g_assert_cmpstr((const char *)result, ==, exp_output);

View File

@ -136,8 +136,15 @@ struct QCryptoIVGenTestData {
static void test_ivgen(const void *opaque)
{
const struct QCryptoIVGenTestData *data = opaque;
uint8_t *iv = g_new0(uint8_t, data->niv);
QCryptoIVGen *ivgen = qcrypto_ivgen_new(
g_autofree uint8_t *iv = g_new0(uint8_t, data->niv);
g_autoptr(QCryptoIVGen) ivgen = NULL;
if (!qcrypto_cipher_supports(data->cipheralg,
QCRYPTO_CIPHER_MODE_ECB)) {
return;
}
ivgen = qcrypto_ivgen_new(
data->ivalg,
data->cipheralg,
data->hashalg,
@ -152,9 +159,6 @@ static void test_ivgen(const void *opaque)
&error_abort);
g_assert(memcmp(iv, data->iv, data->niv) == 0);
qcrypto_ivgen_free(ivgen);
g_free(iv);
}
int main(int argc, char **argv)

View File

@ -229,10 +229,8 @@ static QCryptoPbkdfTestData test_data[] = {
},
/* non-RFC misc test data */
#ifdef CONFIG_NETTLE
{
/* empty password test.
* Broken with libgcrypt <= 1.5.0, hence CONFIG_NETTLE */
/* empty password test. */
.path = "/crypto/pbkdf/nonrfc/sha1/iter2",
.hash = QCRYPTO_HASH_ALG_SHA1,
.iterations = 2,
@ -244,7 +242,6 @@ static QCryptoPbkdfTestData test_data[] = {
"\xbf\x03\xe1\x1c\x71\xca\x79\x4e\x07\x97",
.nout = 20
},
#endif
{
/* Password exceeds block size test */
.path = "/crypto/pbkdf/nonrfc/sha256/iter1200",

View File

@ -2733,6 +2733,19 @@ static void authentication_failed(VncState *vs)
vnc_client_error(vs);
}
static void
vnc_munge_des_rfb_key(unsigned char *key, size_t nkey)
{
size_t i;
for (i = 0; i < nkey; i++) {
uint8_t r = key[i];
r = (r & 0xf0) >> 4 | (r & 0x0f) << 4;
r = (r & 0xcc) >> 2 | (r & 0x33) << 2;
r = (r & 0xaa) >> 1 | (r & 0x55) << 1;
key[i] = r;
}
}
static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
{
unsigned char response[VNC_AUTH_CHALLENGE_SIZE];
@ -2757,9 +2770,10 @@ static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
pwlen = strlen(vs->vd->password);
for (i=0; i<sizeof(key); i++)
key[i] = i<pwlen ? vs->vd->password[i] : 0;
vnc_munge_des_rfb_key(key, sizeof(key));
cipher = qcrypto_cipher_new(
QCRYPTO_CIPHER_ALG_DES_RFB,
QCRYPTO_CIPHER_ALG_DES,
QCRYPTO_CIPHER_MODE_ECB,
key, G_N_ELEMENTS(key),
&err);
@ -4045,9 +4059,9 @@ void vnc_display_open(const char *id, Error **errp)
goto fail;
}
if (!qcrypto_cipher_supports(
QCRYPTO_CIPHER_ALG_DES_RFB, QCRYPTO_CIPHER_MODE_ECB)) {
QCRYPTO_CIPHER_ALG_DES, QCRYPTO_CIPHER_MODE_ECB)) {
error_setg(errp,
"Cipher backend does not support DES RFB algorithm");
"Cipher backend does not support DES algorithm");
goto fail;
}
}