Merge qcrypto 2016/09/19 v2

-----BEGIN PGP SIGNATURE-----
 
 iQIcBAABCAAGBQJX4ASsAAoJEL6G67QVEE/fmG8P/RQ83VIPoktWbzW7EqINSUgU
 zKInEnFpCVC7OyzORQMItAMAzlStODQ5PWzhn6dK3W3co8CRHLIsJoxb1dcxzuQb
 G5Do7+n5tu8o92F48KZFsZL7FJ0NAgC/mwyBeg1K21spHF7wm9Fq+w47+wC8/06T
 +NzhQunnHBmwuvL+UPsf6v2W5hgWkREBkDr77may+lYIby6YBstyo0R7GXW2ZZNX
 hDU1XEKabHe/GRVx5LIRzIVP2L+DsdX6Ls+NtoQWernmTGWrd4O0Y7KEHZBxGoxu
 BqL47yWwVilSZz8JYDiZOPFfnXqQi/WgfBD8sZ4OQY3aH0H93rnPUFoLgWv6giZh
 SlNgIq5r9IC+6LXyPa+bgGOVYG7lGnQ9Gi9fvaTbtO8dDFRRNwhpStfe28nbwGNr
 Is6ereCk6DbmADsZX1D9GMWGz5VUEBWwMFcyU11bkQN6natdJcrv+fUZ/bo4scu0
 fJLEFRKJPMhLmoz3ZzwPw6jFhcXzGxs8apuP1RQLl2DPJZMhFOSQjiu9ekPIo475
 BXSdjzPrk6UsLffocIc7x7K4xKrCHAoiXbOYTg1xltB1EVkCutKe8e2Q8jFkltLa
 kT2w0kiqKg4p73nm/iT04vcpuomCP6Q+/5kAGtQ/2sqIcVp12Prl9d+r+4/APoSE
 rU8WGNuMdtTCmzFAuXtc
 =/jXc
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/berrange/tags/pull-qcrypto-2016-09-19-2' into staging

Merge qcrypto 2016/09/19 v2

# gpg: Signature made Mon 19 Sep 2016 16:30:52 BST
# gpg:                using RSA key 0xBE86EBB415104FDF
# gpg: Good signature from "Daniel P. Berrange <dan@berrange.com>"
# gpg:                 aka "Daniel P. Berrange <berrange@redhat.com>"
# Primary key fingerprint: DAF3 A6FD B26B 6291 2D0E  8E3F BE86 EBB4 1510 4FDF

* remotes/berrange/tags/pull-qcrypto-2016-09-19-2:
  crypto: add trace points for TLS cert verification
  crypto: support more hash algorithms for pbkdf
  crypto: increase default pbkdf2 time for luks to 2 seconds
  crypto: remove bogus /= 2 for pbkdf iterations
  crypto: use correct derived key size when timing pbkdf
  crypto: clear out buffer after timing pbkdf algorithm
  crypto: make PBKDF iterations configurable for LUKS format
  crypto: use uint64_t for pbkdf iteration count parameters

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2016-09-19 17:10:06 +01:00
commit 3d47a1390b
11 changed files with 238 additions and 62 deletions

View File

@ -33,6 +33,7 @@
#define BLOCK_CRYPTO_OPT_LUKS_IVGEN_ALG "ivgen-alg"
#define BLOCK_CRYPTO_OPT_LUKS_IVGEN_HASH_ALG "ivgen-hash-alg"
#define BLOCK_CRYPTO_OPT_LUKS_HASH_ALG "hash-alg"
#define BLOCK_CRYPTO_OPT_LUKS_ITER_TIME "iter-time"
typedef struct BlockCrypto BlockCrypto;
@ -183,6 +184,11 @@ static QemuOptsList block_crypto_create_opts_luks = {
.type = QEMU_OPT_STRING,
.help = "Name of encryption hash algorithm",
},
{
.name = BLOCK_CRYPTO_OPT_LUKS_ITER_TIME,
.type = QEMU_OPT_NUMBER,
.help = "Time to spend in PBKDF in milliseconds",
},
{ /* end of list */ }
},
};

View File

@ -917,8 +917,12 @@ qcrypto_block_luks_create(QCryptoBlock *block,
const char *hash_alg;
char *cipher_mode_spec = NULL;
QCryptoCipherAlgorithm ivcipheralg = 0;
uint64_t iters;
memcpy(&luks_opts, &options->u.luks, sizeof(luks_opts));
if (!luks_opts.has_iter_time) {
luks_opts.iter_time = 2000;
}
if (!luks_opts.has_cipher_alg) {
luks_opts.cipher_alg = QCRYPTO_CIPHER_ALG_AES_256;
}
@ -1064,26 +1068,40 @@ qcrypto_block_luks_create(QCryptoBlock *block,
/* Determine how many iterations we need to hash the master
* key, in order to have 1 second of compute time used
*/
luks->header.master_key_iterations =
qcrypto_pbkdf2_count_iters(luks_opts.hash_alg,
iters = qcrypto_pbkdf2_count_iters(luks_opts.hash_alg,
masterkey, luks->header.key_bytes,
luks->header.master_key_salt,
QCRYPTO_BLOCK_LUKS_SALT_LEN,
QCRYPTO_BLOCK_LUKS_DIGEST_LEN,
&local_err);
if (local_err) {
error_propagate(errp, local_err);
goto error;
}
if (iters > (ULLONG_MAX / luks_opts.iter_time)) {
error_setg_errno(errp, ERANGE,
"PBKDF iterations %llu too large to scale",
(unsigned long long)iters);
goto error;
}
/* iter_time was in millis, but count_iters reported for secs */
iters = iters * luks_opts.iter_time / 1000;
/* Why /= 8 ? That matches cryptsetup, but there's no
* explanation why they chose /= 8... Probably so that
* if all 8 keyslots are active we only spend 1 second
* in total time to check all keys */
luks->header.master_key_iterations /= 8;
luks->header.master_key_iterations = MAX(
luks->header.master_key_iterations,
QCRYPTO_BLOCK_LUKS_MIN_MASTER_KEY_ITERS);
iters /= 8;
if (iters > UINT32_MAX) {
error_setg_errno(errp, ERANGE,
"PBKDF iterations %llu larger than %u",
(unsigned long long)iters, UINT32_MAX);
goto error;
}
iters = MAX(iters, QCRYPTO_BLOCK_LUKS_MIN_MASTER_KEY_ITERS);
luks->header.master_key_iterations = iters;
/* Hash the master key, saving the result in the LUKS
* header. This hash is used when opening the encrypted
@ -1131,22 +1149,36 @@ qcrypto_block_luks_create(QCryptoBlock *block,
/* Again we determine how many iterations are required to
* hash the user password while consuming 1 second of compute
* time */
luks->header.key_slots[0].iterations =
qcrypto_pbkdf2_count_iters(luks_opts.hash_alg,
iters = qcrypto_pbkdf2_count_iters(luks_opts.hash_alg,
(uint8_t *)password, strlen(password),
luks->header.key_slots[0].salt,
QCRYPTO_BLOCK_LUKS_SALT_LEN,
luks->header.key_bytes,
&local_err);
if (local_err) {
error_propagate(errp, local_err);
goto error;
}
/* Why /= 2 ? That matches cryptsetup, but there's no
* explanation why they chose /= 2... */
luks->header.key_slots[0].iterations /= 2;
luks->header.key_slots[0].iterations = MAX(
luks->header.key_slots[0].iterations,
QCRYPTO_BLOCK_LUKS_MIN_SLOT_KEY_ITERS);
if (iters > (ULLONG_MAX / luks_opts.iter_time)) {
error_setg_errno(errp, ERANGE,
"PBKDF iterations %llu too large to scale",
(unsigned long long)iters);
goto error;
}
/* iter_time was in millis, but count_iters reported for secs */
iters = iters * luks_opts.iter_time / 1000;
if (iters > UINT32_MAX) {
error_setg_errno(errp, ERANGE,
"PBKDF iterations %llu larger than %u",
(unsigned long long)iters, UINT32_MAX);
goto error;
}
luks->header.key_slots[0].iterations =
MAX(iters, QCRYPTO_BLOCK_LUKS_MIN_SLOT_KEY_ITERS);
/* Generate a key that we'll use to encrypt the master

View File

@ -28,7 +28,11 @@ 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;
@ -38,20 +42,33 @@ bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash)
int qcrypto_pbkdf2(QCryptoHashAlgorithm hash,
const uint8_t *key, size_t nkey,
const uint8_t *salt, size_t nsalt,
unsigned int iterations,
uint64_t iterations,
uint8_t *out, size_t nout,
Error **errp)
{
static const int hash_map[QCRYPTO_HASH_ALG__MAX] = {
[QCRYPTO_HASH_ALG_MD5] = GCRY_MD_MD5,
[QCRYPTO_HASH_ALG_SHA1] = GCRY_MD_SHA1,
[QCRYPTO_HASH_ALG_SHA224] = GCRY_MD_SHA224,
[QCRYPTO_HASH_ALG_SHA256] = GCRY_MD_SHA256,
[QCRYPTO_HASH_ALG_SHA384] = GCRY_MD_SHA384,
[QCRYPTO_HASH_ALG_SHA512] = GCRY_MD_SHA512,
[QCRYPTO_HASH_ALG_RIPEMD160] = GCRY_MD_RMD160,
};
int ret;
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] == GCRY_MD_NONE) {
error_setg(errp, "Unexpected hash algorithm %d", hash);
error_setg_errno(errp, ENOSYS,
"PBKDF does not support hash algorithm %s",
QCryptoHashAlgorithm_lookup[hash]);
return -1;
}

View File

@ -20,6 +20,7 @@
#include "qemu/osdep.h"
#include <nettle/pbkdf2.h>
#include <nettle/hmac.h>
#include "qapi/error.h"
#include "crypto/pbkdf.h"
@ -28,7 +29,11 @@ bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash)
{
switch (hash) {
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;
@ -38,28 +43,74 @@ bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash)
int qcrypto_pbkdf2(QCryptoHashAlgorithm hash,
const uint8_t *key, size_t nkey,
const uint8_t *salt, size_t nsalt,
unsigned int iterations,
uint64_t iterations,
uint8_t *out, size_t nout,
Error **errp)
{
union {
struct hmac_md5_ctx md5;
struct hmac_sha1_ctx sha1;
struct hmac_sha224_ctx sha224;
struct hmac_sha256_ctx sha256;
struct hmac_sha384_ctx sha384;
struct hmac_sha512_ctx sha512;
struct hmac_ripemd160_ctx ripemd160;
} ctx;
if (iterations > UINT_MAX) {
error_setg_errno(errp, ERANGE,
"PBKDF iterations %llu must be less than %u",
(long long unsigned)iterations, UINT_MAX);
return -1;
}
switch (hash) {
case QCRYPTO_HASH_ALG_MD5:
hmac_md5_set_key(&ctx.md5, nkey, key);
PBKDF2(&ctx.md5, hmac_md5_update, hmac_md5_digest,
MD5_DIGEST_SIZE, iterations, nsalt, salt, nout, out);
break;
case QCRYPTO_HASH_ALG_SHA1:
pbkdf2_hmac_sha1(nkey, key,
iterations,
nsalt, salt,
nout, out);
hmac_sha1_set_key(&ctx.sha1, nkey, key);
PBKDF2(&ctx.sha1, hmac_sha1_update, hmac_sha1_digest,
SHA1_DIGEST_SIZE, iterations, nsalt, salt, nout, out);
break;
case QCRYPTO_HASH_ALG_SHA224:
hmac_sha224_set_key(&ctx.sha224, nkey, key);
PBKDF2(&ctx.sha224, hmac_sha224_update, hmac_sha224_digest,
SHA224_DIGEST_SIZE, iterations, nsalt, salt, nout, out);
break;
case QCRYPTO_HASH_ALG_SHA256:
pbkdf2_hmac_sha256(nkey, key,
iterations,
nsalt, salt,
nout, out);
hmac_sha256_set_key(&ctx.sha256, nkey, key);
PBKDF2(&ctx.sha256, hmac_sha256_update, hmac_sha256_digest,
SHA256_DIGEST_SIZE, iterations, nsalt, salt, nout, out);
break;
case QCRYPTO_HASH_ALG_SHA384:
hmac_sha384_set_key(&ctx.sha384, nkey, key);
PBKDF2(&ctx.sha384, hmac_sha384_update, hmac_sha384_digest,
SHA384_DIGEST_SIZE, iterations, nsalt, salt, nout, out);
break;
case QCRYPTO_HASH_ALG_SHA512:
hmac_sha512_set_key(&ctx.sha512, nkey, key);
PBKDF2(&ctx.sha512, hmac_sha512_update, hmac_sha512_digest,
SHA512_DIGEST_SIZE, iterations, nsalt, salt, nout, out);
break;
case QCRYPTO_HASH_ALG_RIPEMD160:
hmac_ripemd160_set_key(&ctx.ripemd160, nkey, key);
PBKDF2(&ctx.ripemd160, hmac_ripemd160_update, hmac_ripemd160_digest,
RIPEMD160_DIGEST_SIZE, iterations, nsalt, salt, nout, out);
break;
default:
error_setg_errno(errp, ENOSYS,
"PBKDF does not support hash algorithm %d", hash);
"PBKDF does not support hash algorithm %s",
QCryptoHashAlgorithm_lookup[hash]);
return -1;
}
return 0;

View File

@ -32,7 +32,7 @@ int qcrypto_pbkdf2(QCryptoHashAlgorithm hash G_GNUC_UNUSED,
size_t nkey G_GNUC_UNUSED,
const uint8_t *salt G_GNUC_UNUSED,
size_t nsalt G_GNUC_UNUSED,
unsigned int iterations G_GNUC_UNUSED,
uint64_t iterations G_GNUC_UNUSED,
uint8_t *out G_GNUC_UNUSED,
size_t nout G_GNUC_UNUSED,
Error **errp)

View File

@ -62,29 +62,33 @@ static int qcrypto_pbkdf2_get_thread_cpu(unsigned long long *val_ms,
#endif
}
int qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash,
uint64_t qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash,
const uint8_t *key, size_t nkey,
const uint8_t *salt, size_t nsalt,
size_t nout,
Error **errp)
{
uint8_t out[32];
long long int iterations = (1 << 15);
uint64_t ret = -1;
uint8_t *out;
uint64_t iterations = (1 << 15);
unsigned long long delta_ms, start_ms, end_ms;
out = g_new(uint8_t, nout);
while (1) {
if (qcrypto_pbkdf2_get_thread_cpu(&start_ms, errp) < 0) {
return -1;
goto cleanup;
}
if (qcrypto_pbkdf2(hash,
key, nkey,
salt, nsalt,
iterations,
out, sizeof(out),
out, nout,
errp) < 0) {
return -1;
goto cleanup;
}
if (qcrypto_pbkdf2_get_thread_cpu(&end_ms, errp) < 0) {
return -1;
goto cleanup;
}
delta_ms = end_ms - start_ms;
@ -100,11 +104,10 @@ int qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash,
iterations = iterations * 1000 / delta_ms;
if (iterations > INT32_MAX) {
error_setg(errp, "Iterations %lld too large for a 32-bit int",
iterations);
return -1;
}
ret = iterations;
return iterations;
cleanup:
memset(out, 0, nout);
g_free(out);
return ret;
}

View File

@ -351,16 +351,22 @@ qcrypto_tls_session_check_credentials(QCryptoTLSSession *session,
{
if (object_dynamic_cast(OBJECT(session->creds),
TYPE_QCRYPTO_TLS_CREDS_ANON)) {
trace_qcrypto_tls_session_check_creds(session, "nop");
return 0;
} else if (object_dynamic_cast(OBJECT(session->creds),
TYPE_QCRYPTO_TLS_CREDS_X509)) {
if (session->creds->verifyPeer) {
return qcrypto_tls_session_check_certificate(session,
int ret = qcrypto_tls_session_check_certificate(session,
errp);
trace_qcrypto_tls_session_check_creds(session,
ret == 0 ? "pass" : "fail");
return ret;
} else {
trace_qcrypto_tls_session_check_creds(session, "skip");
return 0;
}
} else {
trace_qcrypto_tls_session_check_creds(session, "error");
error_setg(errp, "Unexpected credential type %s",
object_get_typename(OBJECT(session->creds)));
return -1;

View File

@ -17,3 +17,4 @@ qcrypto_tls_creds_x509_load_cert_list(void *creds, const char *file) "TLS creds
# crypto/tlssession.c
qcrypto_tls_session_new(void *session, void *creds, const char *hostname, const char *aclname, int endpoint) "TLS session new session=%p creds=%p hostname=%s aclname=%s endpoint=%d"
qcrypto_tls_session_check_creds(void *session, const char *status) "TLS session check creds session=%p status=%s"

View File

@ -122,7 +122,7 @@ bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash);
int qcrypto_pbkdf2(QCryptoHashAlgorithm hash,
const uint8_t *key, size_t nkey,
const uint8_t *salt, size_t nsalt,
unsigned int iterations,
uint64_t iterations,
uint8_t *out, size_t nout,
Error **errp);
@ -133,6 +133,7 @@ int qcrypto_pbkdf2(QCryptoHashAlgorithm hash,
* @nkey: the length of @key in bytes
* @salt: a random salt
* @nsalt: length of @salt in bytes
* @nout: size of desired derived key
* @errp: pointer to a NULL-initialized error object
*
* Time the PBKDF2 algorithm to determine how many
@ -140,13 +141,16 @@ int qcrypto_pbkdf2(QCryptoHashAlgorithm hash,
* key from a user password provided in @key in 1
* second of compute time. The result of this can
* be used as a the @iterations parameter of a later
* call to qcrypto_pbkdf2().
* call to qcrypto_pbkdf2(). The value of @nout should
* match that value that will later be provided with
* a call to qcrypto_pbkdf2().
*
* Returns: number of iterations in 1 second, -1 on error
*/
int qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash,
uint64_t qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash,
const uint8_t *key, size_t nkey,
const uint8_t *salt, size_t nsalt,
size_t nout,
Error **errp);
#endif /* QCRYPTO_PBKDF_H */

View File

@ -185,6 +185,9 @@
# Currently defaults to 'sha256'
# @hash-alg: #optional the master key hash algorithm
# Currently defaults to 'sha256'
# @iter-time: #optional number of milliseconds to spend in
# PBKDF passphrase processing. Currently defaults
# to 2000. (since 2.8)
# Since: 2.6
##
{ 'struct': 'QCryptoBlockCreateOptionsLUKS',
@ -193,7 +196,8 @@
'*cipher-mode': 'QCryptoCipherMode',
'*ivgen-alg': 'QCryptoIVGenAlgorithm',
'*ivgen-hash-alg': 'QCryptoHashAlgorithm',
'*hash-alg': 'QCryptoHashAlgorithm'}}
'*hash-alg': 'QCryptoHashAlgorithm',
'*iter-time': 'int'}}
##

View File

@ -261,7 +261,6 @@ static QCryptoPbkdfTestData test_data[] = {
"\xcc\x4a\x5e\x6d\xca\x04\xec\x58",
.nout = 32
},
#if 0
{
.path = "/crypto/pbkdf/nonrfc/sha512/iter1200",
.hash = QCRYPTO_HASH_ALG_SHA512,
@ -279,6 +278,58 @@ static QCryptoPbkdfTestData test_data[] = {
"\x76\x14\x80\xf3\xe3\x7a\x22\xb9",
.nout = 32
},
{
.path = "/crypto/pbkdf/nonrfc/sha224/iter1200",
.hash = QCRYPTO_HASH_ALG_SHA224,
.iterations = 1200,
.key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
.nkey = 129,
.salt = "pass phrase exceeds block size",
.nsalt = 30,
.out = "\x13\x3b\x88\x0c\x0e\x52\xa2\x41"
"\x49\x33\x35\xa6\xc3\x83\xae\x23"
"\xf6\x77\x43\x9e\x5b\x30\x92\x3e"
"\x4a\x3a\xaa\x24\x69\x3c\xed\x20",
.nout = 32
},
{
.path = "/crypto/pbkdf/nonrfc/sha384/iter1200",
.hash = QCRYPTO_HASH_ALG_SHA384,
.iterations = 1200,
.key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
.nkey = 129,
.salt = "pass phrase exceeds block size",
.nsalt = 30,
.out = "\xfe\xe3\xe1\x84\xc9\x25\x3e\x10"
"\x47\xc8\x7d\x53\xc6\xa5\xe3\x77"
"\x29\x41\x76\xbd\x4b\xe3\x9b\xac"
"\x05\x6c\x11\xdd\x17\xc5\x93\x80",
.nout = 32
},
{
.path = "/crypto/pbkdf/nonrfc/ripemd160/iter1200",
.hash = QCRYPTO_HASH_ALG_RIPEMD160,
.iterations = 1200,
.key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
.nkey = 129,
.salt = "pass phrase exceeds block size",
.nsalt = 30,
.out = "\xd6\xcb\xd8\xa7\xdb\x0c\xa2\x2a"
"\x23\x5e\x47\xaf\xdb\xda\xa8\xef"
"\xe4\x01\x0d\x6f\xb5\x33\xc8\xbd"
"\xce\xbf\x91\x14\x8b\x5c\x48\x41",
.nout = 32
},
#if 0
{
.path = "/crypto/pbkdf/nonrfc/whirlpool/iter1200",
.hash = QCRYPTO_HASH_ALG_WHIRLPOOL,
@ -358,6 +409,7 @@ static void test_pbkdf_timing(void)
iters = qcrypto_pbkdf2_count_iters(QCRYPTO_HASH_ALG_SHA256,
key, sizeof(key),
salt, sizeof(salt),
32,
&error_abort);
g_assert(iters >= (1 << 15));