diff options
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | crypto/cipher.c | 54 | ||||
-rw-r--r-- | crypto/hash.c | 17 | ||||
-rw-r--r-- | include/crypto/cipher.h | 54 | ||||
-rw-r--r-- | include/crypto/hash.h | 20 | ||||
-rw-r--r-- | qapi/crypto.json | 45 | ||||
-rw-r--r-- | tests/test-crypto-cipher.c | 10 | ||||
-rw-r--r-- | tests/test-crypto-hash.c | 5 |
8 files changed, 180 insertions, 28 deletions
@@ -271,7 +271,8 @@ $(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py) qapi-modules = $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/qapi/common.json \ $(SRC_PATH)/qapi/block.json $(SRC_PATH)/qapi/block-core.json \ - $(SRC_PATH)/qapi/event.json $(SRC_PATH)/qapi/introspect.json + $(SRC_PATH)/qapi/event.json $(SRC_PATH)/qapi/introspect.json \ + $(SRC_PATH)/qapi/crypto.json qapi-types.c qapi-types.h :\ $(qapi-modules) $(SRC_PATH)/scripts/qapi-types.py $(qapi-py) diff --git a/crypto/cipher.c b/crypto/cipher.c index c8bd180532..7c333486d2 100644 --- a/crypto/cipher.c +++ b/crypto/cipher.c @@ -21,19 +21,67 @@ #include "crypto/cipher.h" -static size_t alg_key_len[QCRYPTO_CIPHER_ALG_LAST] = { +static 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, }; +static 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, +}; + +static bool mode_need_iv[QCRYPTO_CIPHER_MODE__MAX] = { + [QCRYPTO_CIPHER_MODE_ECB] = false, + [QCRYPTO_CIPHER_MODE_CBC] = true, +}; + + +size_t qcrypto_cipher_get_block_len(QCryptoCipherAlgorithm alg) +{ + if (alg >= G_N_ELEMENTS(alg_key_len)) { + return 0; + } + return alg_block_len[alg]; +} + + +size_t qcrypto_cipher_get_key_len(QCryptoCipherAlgorithm alg) +{ + if (alg >= G_N_ELEMENTS(alg_key_len)) { + return 0; + } + return alg_key_len[alg]; +} + + +size_t qcrypto_cipher_get_iv_len(QCryptoCipherAlgorithm alg, + QCryptoCipherMode mode) +{ + if (alg >= G_N_ELEMENTS(alg_block_len)) { + return 0; + } + if (mode >= G_N_ELEMENTS(mode_need_iv)) { + return 0; + } + + if (mode_need_iv[mode]) { + return alg_block_len[alg]; + } + return 0; +} + + static bool qcrypto_cipher_validate_key_length(QCryptoCipherAlgorithm alg, size_t nkey, Error **errp) { - if ((unsigned)alg >= QCRYPTO_CIPHER_ALG_LAST) { + if ((unsigned)alg >= QCRYPTO_CIPHER_ALG__MAX) { error_setg(errp, "Cipher algorithm %d out of range", alg); return false; @@ -41,7 +89,7 @@ qcrypto_cipher_validate_key_length(QCryptoCipherAlgorithm alg, if (alg_key_len[alg] != nkey) { error_setg(errp, "Cipher key length %zu should be %zu", - alg_key_len[alg], nkey); + nkey, alg_key_len[alg]); return false; } return true; diff --git a/crypto/hash.c b/crypto/hash.c index 81e74de868..6e83f43e4a 100644 --- a/crypto/hash.c +++ b/crypto/hash.c @@ -24,12 +24,18 @@ #include <gnutls/gnutls.h> #include <gnutls/crypto.h> -static int qcrypto_hash_alg_map[QCRYPTO_HASH_ALG_LAST] = { +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_SHA256] = GNUTLS_DIG_SHA256, }; +static size_t qcrypto_hash_alg_size[QCRYPTO_HASH_ALG__MAX] = { + [QCRYPTO_HASH_ALG_MD5] = 16, + [QCRYPTO_HASH_ALG_SHA1] = 20, + [QCRYPTO_HASH_ALG_SHA256] = 32, +}; + gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg) { if (alg < G_N_ELEMENTS(qcrypto_hash_alg_map)) { @@ -38,6 +44,15 @@ gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg) return false; } +size_t qcrypto_hash_digest_len(QCryptoHashAlgorithm alg) +{ + if (alg >= G_N_ELEMENTS(qcrypto_hash_alg_size)) { + return 0; + } + return qcrypto_hash_alg_size[alg]; +} + + int qcrypto_hash_bytesv(QCryptoHashAlgorithm alg, const struct iovec *iov, size_t niov, diff --git a/include/crypto/cipher.h b/include/crypto/cipher.h index b4d714f269..a812803df1 100644 --- a/include/crypto/cipher.h +++ b/include/crypto/cipher.h @@ -26,21 +26,8 @@ typedef struct QCryptoCipher QCryptoCipher; -typedef enum { - QCRYPTO_CIPHER_ALG_AES_128, - QCRYPTO_CIPHER_ALG_AES_192, - QCRYPTO_CIPHER_ALG_AES_256, - QCRYPTO_CIPHER_ALG_DES_RFB, /* A stupid variant on DES for VNC */ - - QCRYPTO_CIPHER_ALG_LAST -} QCryptoCipherAlgorithm; - -typedef enum { - QCRYPTO_CIPHER_MODE_ECB, - QCRYPTO_CIPHER_MODE_CBC, - - QCRYPTO_CIPHER_MODE_LAST -} QCryptoCipherMode; +/* See also "QCryptoCipherAlgorithm" and "QCryptoCipherMode" + * enums defined in qapi/crypto.json */ /** * QCryptoCipher: @@ -107,6 +94,43 @@ struct QCryptoCipher { */ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg); +/** + * qcrypto_cipher_get_block_len: + * @alg: the cipher algorithm + * + * Get the required data block size in bytes. When + * encrypting data, it must be a multiple of the + * block size. + * + * Returns: the block size in bytes + */ +size_t qcrypto_cipher_get_block_len(QCryptoCipherAlgorithm alg); + + +/** + * qcrypto_cipher_get_key_len: + * @alg: the cipher algorithm + * + * Get the required key size in bytes. + * + * Returns: the key size in bytes + */ +size_t qcrypto_cipher_get_key_len(QCryptoCipherAlgorithm alg); + + +/** + * qcrypto_cipher_get_iv_len: + * @alg: the cipher algorithm + * @mode: the cipher mode + * + * Get the required initialization vector size + * in bytes, if one is required. + * + * Returns: the IV size in bytes, or 0 if no IV is permitted + */ +size_t qcrypto_cipher_get_iv_len(QCryptoCipherAlgorithm alg, + QCryptoCipherMode mode); + /** * qcrypto_cipher_new: diff --git a/include/crypto/hash.h b/include/crypto/hash.h index b5acbf638c..41822c0a4e 100644 --- a/include/crypto/hash.h +++ b/include/crypto/hash.h @@ -24,14 +24,7 @@ #include "qemu-common.h" #include "qapi/error.h" -typedef enum { - QCRYPTO_HASH_ALG_MD5, - QCRYPTO_HASH_ALG_SHA1, - QCRYPTO_HASH_ALG_SHA256, - - QCRYPTO_HASH_ALG_LAST -} QCryptoHashAlgorithm; - +/* See also "QCryptoHashAlgorithm" defined in qapi/crypto.json */ /** * qcrypto_hash_supports: @@ -44,6 +37,17 @@ typedef enum { */ gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg); + +/** + * qcrypto_hash_digest_len: + * @alg: the hash algorithm + * + * Determine the size of the hash digest in bytes + * + * Returns: the digest length in bytes + */ +size_t qcrypto_hash_digest_len(QCryptoHashAlgorithm alg); + /** * qcrypto_hash_bytesv: * @alg: the hash algorithm diff --git a/qapi/crypto.json b/qapi/crypto.json index 4012659169..4bd690fcfb 100644 --- a/qapi/crypto.json +++ b/qapi/crypto.json @@ -33,3 +33,48 @@ { 'enum': 'QCryptoSecretFormat', 'prefix': 'QCRYPTO_SECRET_FORMAT', 'data': ['raw', 'base64']} + + +## +# QCryptoHashAlgorithm: +# +# The supported algorithms for computing content digests +# +# @md5: MD5. Should not be used in any new code, legacy compat only +# @sha1: SHA-1. Should not be used in any new code, legacy compat only +# @sha256: SHA-256. Current recommended strong hash. +# Since: 2.6 +## +{ 'enum': 'QCryptoHashAlgorithm', + 'prefix': 'QCRYPTO_HASH_ALG', + 'data': ['md5', 'sha1', 'sha256']} + + +## +# QCryptoCipherAlgorithm: +# +# The supported algorithms for content encryption ciphers +# +# @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. +# Since: 2.6 +## +{ 'enum': 'QCryptoCipherAlgorithm', + 'prefix': 'QCRYPTO_CIPHER_ALG', + 'data': ['aes-128', 'aes-192', 'aes-256', 'des-rfb']} + + +## +# QCryptoCipherMode: +# +# The supported modes for content encryption ciphers +# +# @ecb: Electronic Code Book +# @cbc: Cipher Block Chaining +# Since: 2.6 +## +{ 'enum': 'QCryptoCipherMode', + 'prefix': 'QCRYPTO_CIPHER_MODE', + 'data': ['ecb', 'cbc']} diff --git a/tests/test-crypto-cipher.c b/tests/test-crypto-cipher.c index f4946a0af0..c687307bcd 100644 --- a/tests/test-crypto-cipher.c +++ b/tests/test-crypto-cipher.c @@ -229,6 +229,7 @@ static void test_cipher(const void *opaque) uint8_t *key, *iv, *ciphertext, *plaintext, *outtext; size_t nkey, niv, nciphertext, nplaintext; char *outtexthex; + size_t ivsize, keysize, blocksize; nkey = unhex_string(data->key, &key); niv = unhex_string(data->iv, &iv); @@ -245,6 +246,15 @@ static void test_cipher(const void *opaque) &error_abort); g_assert(cipher != NULL); + keysize = qcrypto_cipher_get_key_len(data->alg); + blocksize = qcrypto_cipher_get_block_len(data->alg); + ivsize = qcrypto_cipher_get_iv_len(data->alg, data->mode); + + g_assert_cmpint(keysize, ==, nkey); + g_assert_cmpint(ivsize, ==, niv); + if (niv) { + g_assert_cmpint(blocksize, ==, niv); + } if (iv) { g_assert(qcrypto_cipher_setiv(cipher, diff --git a/tests/test-crypto-hash.c b/tests/test-crypto-hash.c index 911437e60d..3ec31dde7b 100644 --- a/tests/test-crypto-hash.c +++ b/tests/test-crypto-hash.c @@ -163,6 +163,11 @@ static void test_hash_digest(void) for (i = 0; i < G_N_ELEMENTS(expected_outputs) ; i++) { int ret; char *digest; + size_t digestsize; + + digestsize = qcrypto_hash_digest_len(i); + + g_assert_cmpint(digestsize * 2, ==, strlen(expected_outputs[i])); ret = qcrypto_hash_digest(i, INPUT_TEXT, |