diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2015-07-08 20:46:35 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2015-07-08 20:46:35 +0100 |
commit | acf7b7fdf31fa76b53803790917c8acf23a2badb (patch) | |
tree | 999bae49ca3a0ea7ef5476c1764c6166b17a0c12 /tests | |
parent | c8e84287da7dd6a46c0bb0e53190e79ba4eedf24 (diff) | |
parent | 2828a307232ffceeddec9feb6a87ac660b68b693 (diff) |
Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging
Bugfixes and Daniel Berrange's crypto library.
# gpg: Signature made Wed Jul 8 12:12:29 2015 BST using RSA key ID 78C7AE83
# gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>"
# gpg: aka "Paolo Bonzini <pbonzini@redhat.com>"
# gpg: WARNING: This key is not certified with sufficiently trusted signatures!
# gpg: It is not certain that the signature belongs to the owner.
# Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4 E2F7 7E15 100C CD36 69B1
# Subkey fingerprint: F133 3857 4B66 2389 866C 7682 BFFB D25F 78C7 AE83
* remotes/bonzini/tags/for-upstream:
ossaudio: fix memory leak
ui: convert VNC to use generic cipher API
block: convert qcow/qcow2 to use generic cipher API
ui: convert VNC websockets to use crypto APIs
block: convert quorum blockdrv to use crypto APIs
crypto: add a nettle cipher implementation
crypto: add a gcrypt cipher implementation
crypto: introduce generic cipher API & built-in implementation
crypto: move built-in D3DES implementation into crypto/
crypto: move built-in AES implementation into crypto/
crypto: introduce new module for computing hash digests
vl: move rom_load_all after machine init done
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'tests')
-rw-r--r-- | tests/.gitignore | 2 | ||||
-rw-r--r-- | tests/Makefile | 4 | ||||
-rw-r--r-- | tests/test-crypto-cipher.c | 290 | ||||
-rw-r--r-- | tests/test-crypto-hash.c | 209 |
4 files changed, 505 insertions, 0 deletions
diff --git a/tests/.gitignore b/tests/.gitignore index dc813c2713..ccc92e4761 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -10,6 +10,8 @@ rcutorture test-aio test-bitops test-coroutine +test-crypto-cipher +test-crypto-hash test-cutils test-hbitmap test-int128 diff --git a/tests/Makefile b/tests/Makefile index e843a7e229..2c4b8dc5ec 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -74,6 +74,8 @@ check-unit-y += tests/test-qemu-opts$(EXESUF) gcov-files-test-qemu-opts-y = qom/test-qemu-opts.c check-unit-y += tests/test-write-threshold$(EXESUF) gcov-files-test-write-threshold-y = block/write-threshold.c +check-unit-$(CONFIG_GNUTLS_HASH) += tests/test-crypto-hash$(EXESUF) +check-unit-y += tests/test-crypto-cipher$(EXESUF) check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh @@ -343,6 +345,8 @@ tests/test-opts-visitor$(EXESUF): tests/test-opts-visitor.o $(test-qapi-obj-y) l tests/test-mul64$(EXESUF): tests/test-mul64.o libqemuutil.a tests/test-bitops$(EXESUF): tests/test-bitops.o libqemuutil.a +tests/test-crypto-hash$(EXESUF): tests/test-crypto-hash.o libqemuutil.a libqemustub.a +tests/test-crypto-cipher$(EXESUF): tests/test-crypto-cipher.o libqemuutil.a libqemustub.a libqos-obj-y = tests/libqos/pci.o tests/libqos/fw_cfg.o tests/libqos/malloc.o libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o diff --git a/tests/test-crypto-cipher.c b/tests/test-crypto-cipher.c new file mode 100644 index 0000000000..f9b1a03a02 --- /dev/null +++ b/tests/test-crypto-cipher.c @@ -0,0 +1,290 @@ +/* + * QEMU Crypto cipher algorithms + * + * Copyright (c) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 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 <glib.h> + +#include "crypto/init.h" +#include "crypto/cipher.h" + +typedef struct QCryptoCipherTestData QCryptoCipherTestData; +struct QCryptoCipherTestData { + const char *path; + QCryptoCipherAlgorithm alg; + QCryptoCipherMode mode; + const char *key; + const char *plaintext; + const char *ciphertext; + const char *iv; +}; + +/* AES test data comes from appendix F of: + * + * http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf + */ +static QCryptoCipherTestData test_data[] = { + { + /* NIST F.1.1 ECB-AES128.Encrypt */ + .path = "/crypto/cipher/aes-ecb-128", + .alg = QCRYPTO_CIPHER_ALG_AES_128, + .mode = QCRYPTO_CIPHER_MODE_ECB, + .key = "2b7e151628aed2a6abf7158809cf4f3c", + .plaintext = + "6bc1bee22e409f96e93d7e117393172a" + "ae2d8a571e03ac9c9eb76fac45af8e51" + "30c81c46a35ce411e5fbc1191a0a52ef" + "f69f2445df4f9b17ad2b417be66c3710", + .ciphertext = + "3ad77bb40d7a3660a89ecaf32466ef97" + "f5d3d58503b9699de785895a96fdbaaf" + "43b1cd7f598ece23881b00e3ed030688" + "7b0c785e27e8ad3f8223207104725dd4" + }, + { + /* NIST F.1.3 ECB-AES192.Encrypt */ + .path = "/crypto/cipher/aes-ecb-192", + .alg = QCRYPTO_CIPHER_ALG_AES_192, + .mode = QCRYPTO_CIPHER_MODE_ECB, + .key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b", + .plaintext = + "6bc1bee22e409f96e93d7e117393172a" + "ae2d8a571e03ac9c9eb76fac45af8e51" + "30c81c46a35ce411e5fbc1191a0a52ef" + "f69f2445df4f9b17ad2b417be66c3710", + .ciphertext = + "bd334f1d6e45f25ff712a214571fa5cc" + "974104846d0ad3ad7734ecb3ecee4eef" + "ef7afd2270e2e60adce0ba2face6444e" + "9a4b41ba738d6c72fb16691603c18e0e" + }, + { + /* NIST F.1.5 ECB-AES256.Encrypt */ + .path = "/crypto/cipher/aes-ecb-256", + .alg = QCRYPTO_CIPHER_ALG_AES_256, + .mode = QCRYPTO_CIPHER_MODE_ECB, + .key = + "603deb1015ca71be2b73aef0857d7781" + "1f352c073b6108d72d9810a30914dff4", + .plaintext = + "6bc1bee22e409f96e93d7e117393172a" + "ae2d8a571e03ac9c9eb76fac45af8e51" + "30c81c46a35ce411e5fbc1191a0a52ef" + "f69f2445df4f9b17ad2b417be66c3710", + .ciphertext = + "f3eed1bdb5d2a03c064b5a7e3db181f8" + "591ccb10d410ed26dc5ba74a31362870" + "b6ed21b99ca6f4f9f153e7b1beafed1d" + "23304b7a39f9f3ff067d8d8f9e24ecc7", + }, + { + /* NIST F.2.1 CBC-AES128.Encrypt */ + .path = "/crypto/cipher/aes-cbc-128", + .alg = QCRYPTO_CIPHER_ALG_AES_128, + .mode = QCRYPTO_CIPHER_MODE_CBC, + .key = "2b7e151628aed2a6abf7158809cf4f3c", + .iv = "000102030405060708090a0b0c0d0e0f", + .plaintext = + "6bc1bee22e409f96e93d7e117393172a" + "ae2d8a571e03ac9c9eb76fac45af8e51" + "30c81c46a35ce411e5fbc1191a0a52ef" + "f69f2445df4f9b17ad2b417be66c3710", + .ciphertext = + "7649abac8119b246cee98e9b12e9197d" + "5086cb9b507219ee95db113a917678b2" + "73bed6b8e3c1743b7116e69e22229516" + "3ff1caa1681fac09120eca307586e1a7", + }, + { + /* NIST F.2.3 CBC-AES128.Encrypt */ + .path = "/crypto/cipher/aes-cbc-192", + .alg = QCRYPTO_CIPHER_ALG_AES_192, + .mode = QCRYPTO_CIPHER_MODE_CBC, + .key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b", + .iv = "000102030405060708090a0b0c0d0e0f", + .plaintext = + "6bc1bee22e409f96e93d7e117393172a" + "ae2d8a571e03ac9c9eb76fac45af8e51" + "30c81c46a35ce411e5fbc1191a0a52ef" + "f69f2445df4f9b17ad2b417be66c3710", + .ciphertext = + "4f021db243bc633d7178183a9fa071e8" + "b4d9ada9ad7dedf4e5e738763f69145a" + "571b242012fb7ae07fa9baac3df102e0" + "08b0e27988598881d920a9e64f5615cd", + }, + { + /* NIST F.2.5 CBC-AES128.Encrypt */ + .path = "/crypto/cipher/aes-cbc-256", + .alg = QCRYPTO_CIPHER_ALG_AES_256, + .mode = QCRYPTO_CIPHER_MODE_CBC, + .key = + "603deb1015ca71be2b73aef0857d7781" + "1f352c073b6108d72d9810a30914dff4", + .iv = "000102030405060708090a0b0c0d0e0f", + .plaintext = + "6bc1bee22e409f96e93d7e117393172a" + "ae2d8a571e03ac9c9eb76fac45af8e51" + "30c81c46a35ce411e5fbc1191a0a52ef" + "f69f2445df4f9b17ad2b417be66c3710", + .ciphertext = + "f58c4c04d6e5f1ba779eabfb5f7bfbd6" + "9cfc4e967edb808d679f777bc6702c7d" + "39f23369a9d9bacfa530e26304231461" + "b2eb05e2c39be9fcda6c19078c6a9d1b", + }, + { + .path = "/crypto/cipher/des-rfb-ecb-56", + .alg = QCRYPTO_CIPHER_ALG_DES_RFB, + .mode = QCRYPTO_CIPHER_MODE_ECB, + .key = "0123456789abcdef", + .plaintext = + "6bc1bee22e409f96e93d7e117393172a" + "ae2d8a571e03ac9c9eb76fac45af8e51" + "30c81c46a35ce411e5fbc1191a0a52ef" + "f69f2445df4f9b17ad2b417be66c3710", + .ciphertext = + "8f346aaf64eaf24040720d80648c52e7" + "aefc616be53ab1a3d301e69d91e01838" + "ffd29f1bb5596ad94ea2d8e6196b7f09" + "30d8ed0bf2773af36dd82a6280c20926", + }, +}; + + +static inline int unhex(char c) +{ + if (c >= 'a' && c <= 'f') { + return 10 + (c - 'a'); + } + if (c >= 'A' && c <= 'F') { + return 10 + (c - 'A'); + } + return c - '0'; +} + +static inline char hex(int i) +{ + if (i < 10) { + return '0' + i; + } + return 'a' + (i - 10); +} + +static size_t unhex_string(const char *hexstr, + uint8_t **data) +{ + size_t len; + size_t i; + + if (!hexstr) { + *data = NULL; + return 0; + } + + len = strlen(hexstr); + *data = g_new0(uint8_t, len / 2); + + for (i = 0; i < len; i += 2) { + (*data)[i/2] = (unhex(hexstr[i]) << 4) | unhex(hexstr[i+1]); + } + return len / 2; +} + +static char *hex_string(const uint8_t *bytes, + size_t len) +{ + char *hexstr = g_new0(char, len * 2 + 1); + size_t i; + + for (i = 0; i < len; i++) { + hexstr[i*2] = hex((bytes[i] >> 4) & 0xf); + hexstr[i*2+1] = hex(bytes[i] & 0xf); + } + hexstr[len*2] = '\0'; + + return hexstr; +} + +static void test_cipher(const void *opaque) +{ + const QCryptoCipherTestData *data = opaque; + + QCryptoCipher *cipher; + Error *err = NULL; + uint8_t *key, *iv, *ciphertext, *plaintext, *outtext; + size_t nkey, niv, nciphertext, nplaintext; + char *outtexthex; + + g_test_message("foo"); + nkey = unhex_string(data->key, &key); + niv = unhex_string(data->iv, &iv); + nciphertext = unhex_string(data->ciphertext, &ciphertext); + nplaintext = unhex_string(data->plaintext, &plaintext); + + g_assert(nciphertext == nplaintext); + + outtext = g_new0(uint8_t, nciphertext); + + cipher = qcrypto_cipher_new( + data->alg, data->mode, + key, nkey, + &err); + g_assert(cipher != NULL); + g_assert(err == NULL); + + + if (iv) { + g_assert(qcrypto_cipher_setiv(cipher, + iv, niv, + &err) == 0); + g_assert(err == NULL); + } + g_assert(qcrypto_cipher_encrypt(cipher, + plaintext, + outtext, + nplaintext, + &err) == 0); + g_assert(err == NULL); + + outtexthex = hex_string(outtext, nciphertext); + + g_assert_cmpstr(outtexthex, ==, data->ciphertext); + + g_free(outtext); + g_free(outtexthex); + g_free(key); + g_free(iv); + g_free(ciphertext); + g_free(plaintext); + qcrypto_cipher_free(cipher); +} + +int main(int argc, char **argv) +{ + size_t i; + + g_test_init(&argc, &argv, NULL); + + g_assert(qcrypto_init(NULL) == 0); + + for (i = 0; i < G_N_ELEMENTS(test_data); i++) { + g_test_add_data_func(test_data[i].path, &test_data[i], test_cipher); + } + return g_test_run(); +} diff --git a/tests/test-crypto-hash.c b/tests/test-crypto-hash.c new file mode 100644 index 0000000000..911437e60d --- /dev/null +++ b/tests/test-crypto-hash.c @@ -0,0 +1,209 @@ +/* + * QEMU Crypto hash algorithms + * + * Copyright (c) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 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 <glib.h> + +#include "crypto/init.h" +#include "crypto/hash.h" + +#define INPUT_TEXT "Hiss hisss Hissss hiss Hiss hisss Hiss hiss" +#define INPUT_TEXT1 "Hiss hisss " +#define INPUT_TEXT2 "Hissss hiss " +#define INPUT_TEXT3 "Hiss hisss Hiss hiss" + +#define OUTPUT_MD5 "628d206371563035ab8ef62f492bdec9" +#define OUTPUT_SHA1 "b2e74f26758a3a421e509cee045244b78753cc02" +#define OUTPUT_SHA256 "bc757abb0436586f392b437e5dd24096" \ + "f7f224de6b74d4d86e2abc6121b160d0" + +#define OUTPUT_MD5_B64 "Yo0gY3FWMDWrjvYvSSveyQ==" +#define OUTPUT_SHA1_B64 "sudPJnWKOkIeUJzuBFJEt4dTzAI=" +#define OUTPUT_SHA256_B64 "vHV6uwQ2WG85K0N+XdJAlvfyJN5rdNTYbiq8YSGxYNA=" + +static const char *expected_outputs[] = { + [QCRYPTO_HASH_ALG_MD5] = OUTPUT_MD5, + [QCRYPTO_HASH_ALG_SHA1] = OUTPUT_SHA1, + [QCRYPTO_HASH_ALG_SHA256] = OUTPUT_SHA256, +}; +static const char *expected_outputs_b64[] = { + [QCRYPTO_HASH_ALG_MD5] = OUTPUT_MD5_B64, + [QCRYPTO_HASH_ALG_SHA1] = OUTPUT_SHA1_B64, + [QCRYPTO_HASH_ALG_SHA256] = OUTPUT_SHA256_B64, +}; +static const int expected_lens[] = { + [QCRYPTO_HASH_ALG_MD5] = 16, + [QCRYPTO_HASH_ALG_SHA1] = 20, + [QCRYPTO_HASH_ALG_SHA256] = 32, +}; + +static const char hex[] = "0123456789abcdef"; + +/* Test with dynamic allocation */ +static void test_hash_alloc(void) +{ + size_t i; + + g_assert(qcrypto_init(NULL) == 0); + + for (i = 0; i < G_N_ELEMENTS(expected_outputs) ; i++) { + uint8_t *result = NULL; + size_t resultlen = 0; + int ret; + size_t j; + + ret = qcrypto_hash_bytes(i, + INPUT_TEXT, + strlen(INPUT_TEXT), + &result, + &resultlen, + NULL); + g_assert(ret == 0); + g_assert(resultlen == expected_lens[i]); + + for (j = 0; j < resultlen; j++) { + g_assert(expected_outputs[i][j * 2] == hex[(result[j] >> 4) & 0xf]); + g_assert(expected_outputs[i][j * 2 + 1] == hex[result[j] & 0xf]); + } + g_free(result); + } +} + +/* Test with caller preallocating */ +static void test_hash_prealloc(void) +{ + size_t i; + + g_assert(qcrypto_init(NULL) == 0); + + for (i = 0; i < G_N_ELEMENTS(expected_outputs) ; i++) { + uint8_t *result; + size_t resultlen; + int ret; + size_t j; + + resultlen = expected_lens[i]; + result = g_new0(uint8_t, resultlen); + + ret = qcrypto_hash_bytes(i, + INPUT_TEXT, + strlen(INPUT_TEXT), + &result, + &resultlen, + NULL); + g_assert(ret == 0); + + g_assert(resultlen == expected_lens[i]); + for (j = 0; j < resultlen; j++) { + g_assert(expected_outputs[i][j * 2] == hex[(result[j] >> 4) & 0xf]); + g_assert(expected_outputs[i][j * 2 + 1] == hex[result[j] & 0xf]); + } + g_free(result); + } +} + + +/* Test with dynamic allocation */ +static void test_hash_iov(void) +{ + size_t i; + + g_assert(qcrypto_init(NULL) == 0); + + for (i = 0; i < G_N_ELEMENTS(expected_outputs) ; i++) { + struct iovec iov[3] = { + { .iov_base = (char *)INPUT_TEXT1, .iov_len = strlen(INPUT_TEXT1) }, + { .iov_base = (char *)INPUT_TEXT2, .iov_len = strlen(INPUT_TEXT2) }, + { .iov_base = (char *)INPUT_TEXT3, .iov_len = strlen(INPUT_TEXT3) }, + }; + uint8_t *result = NULL; + size_t resultlen = 0; + int ret; + size_t j; + + ret = qcrypto_hash_bytesv(i, + iov, 3, + &result, + &resultlen, + NULL); + g_assert(ret == 0); + g_assert(resultlen == expected_lens[i]); + for (j = 0; j < resultlen; j++) { + g_assert(expected_outputs[i][j * 2] == hex[(result[j] >> 4) & 0xf]); + g_assert(expected_outputs[i][j * 2 + 1] == hex[result[j] & 0xf]); + } + g_free(result); + } +} + + +/* Test with printable hashing */ +static void test_hash_digest(void) +{ + size_t i; + + g_assert(qcrypto_init(NULL) == 0); + + for (i = 0; i < G_N_ELEMENTS(expected_outputs) ; i++) { + int ret; + char *digest; + + ret = qcrypto_hash_digest(i, + INPUT_TEXT, + strlen(INPUT_TEXT), + &digest, + NULL); + g_assert(ret == 0); + g_assert(g_str_equal(digest, expected_outputs[i])); + g_free(digest); + } +} + +/* Test with base64 encoding */ +static void test_hash_base64(void) +{ + size_t i; + + g_assert(qcrypto_init(NULL) == 0); + + for (i = 0; i < G_N_ELEMENTS(expected_outputs) ; i++) { + int ret; + char *digest; + + ret = qcrypto_hash_base64(i, + INPUT_TEXT, + strlen(INPUT_TEXT), + &digest, + NULL); + g_assert(ret == 0); + g_assert(g_str_equal(digest, expected_outputs_b64[i])); + g_free(digest); + } +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + g_test_add_func("/crypto/hash/iov", test_hash_iov); + g_test_add_func("/crypto/hash/alloc", test_hash_alloc); + g_test_add_func("/crypto/hash/prealloc", test_hash_prealloc); + g_test_add_func("/crypto/hash/digest", test_hash_digest); + g_test_add_func("/crypto/hash/base64", test_hash_base64); + return g_test_run(); +} |