diff options
Diffstat (limited to 'egg/test-symkey.c')
-rw-r--r-- | egg/test-symkey.c | 668 |
1 files changed, 668 insertions, 0 deletions
diff --git a/egg/test-symkey.c b/egg/test-symkey.c new file mode 100644 index 00000000..90211d68 --- /dev/null +++ b/egg/test-symkey.c @@ -0,0 +1,668 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* unit-test-crypto.c: Test crypto stuff + + Copyright (C) 2007 Stefan Walter + + The Gnome Keyring Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Gnome Keyring 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Gnome Library; see the file COPYING.LIB. If not, + <http://www.gnu.org/licenses/>. + + Author: Stef Walter <stef@memberwebs.com> +*/ + +#include "config.h" + +#include "egg/egg-asn1x.h" +#include "egg/egg-asn1-defs.h" +#include "egg/egg-libgcrypt.h" +#include "egg/egg-secure-memory.h" +#include "egg/egg-symkey.h" +#include "egg/egg-testing.h" + +typedef struct _EggAsn1xDef ASN1_ARRAY_TYPE; +typedef struct _EggAsn1xDef asn1_static_node; +#include "test.asn.h" + +#include <gcrypt.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +EGG_SECURE_DEFINE_GLIB_GLOBALS (); + +static const struct { + const gchar *password; + int cipher_algo; + int hash_algo; + int iterations; + const gchar *salt; + + const gchar *result_simple; + const gchar *result_pkcs12; + const gchar *result_pbkdf2; + const gchar *result_pbe; +} all_generation_tests[] = { + + { /* 24 byte output */ + "booo", GCRY_CIPHER_3DES, GCRY_MD_MD5, 1, + "\x70\x4C\xFF\xD6\x2F\xBA\x03\xE9", + "\x84\x12\xBB\x34\x94\x8C\x40\xAD\x97\x57\x96\x74\x5B\x6A\xFB\xF8\xD6\x61\x33\x51\xEA\x8C\xCF\xD8", + NULL, + NULL, + NULL + }, + + { /* 5 byte output */ + "booo", GCRY_CIPHER_RFC2268_40, GCRY_MD_SHA1, 2048, + "\x8A\x58\xC2\xE8\x7C\x1D\x80\x11", + NULL, + "\xD6\xA6\xF0\x76\x66", + NULL, + NULL + }, + + { /* Null Password, 5 byte output */ + NULL, GCRY_CIPHER_RFC2268_40, GCRY_MD_SHA1, 2000, + "\x04\xE0\x1C\x3E\xF8\xF2\xE9\xFD", + NULL, + "\x98\x7F\x20\x97\x1E", + NULL, + NULL + }, + + { /* 24 byte output */ + "booo", GCRY_CIPHER_3DES, GCRY_MD_SHA1, 2048, + "\xBD\xEE\x0B\xC6\xCF\x43\xAC\x25", + NULL, + "\x3F\x38\x1B\x0E\x87\xEB\x19\xBE\xD1\x39\xDC\x5B\xC2\xD2\xB3\x3C\x35\xA8\xB8\xF9\xEE\x66\x48\x94", + "\x20\x25\x90\xD8\xD6\x98\x3E\x71\x10\x17\x1F\x51\x49\x87\x27\xCA\x97\x27\xD1\xC9\x72\xF8\x11\xBB", + NULL + }, + + { /* Empty password, 24 byte output */ + "", GCRY_CIPHER_3DES, GCRY_MD_SHA1, 2048, + "\xF7\xCF\xD9\xCF\x1F\xF3\xAD\xF6", + NULL, + NULL, + "\x53\xE3\x35\x9E\x5D\xC1\x85\x1A\x71\x3A\x67\x4E\x80\x56\x13\xD6\x4E\x3E\x89\x43\xB7\x1D\x5F\x7F", + NULL + }, + + { /* Empty password, 24 byte output */ + "", GCRY_CIPHER_3DES, GCRY_MD_SHA1, 2048, + "\xD9\xB3\x2E\xC7\xBA\x1A\x8E\x15", + NULL, + "\x39\x70\x75\x7C\xF5\xE2\x13\x0B\x5D\xC2\x9D\x96\x8B\x71\xC7\xFC\x5B\x97\x1F\x79\x9F\x06\xFC\xA2", + NULL, + NULL + }, + + { /* 8 byte output */ + "booo", GCRY_CIPHER_DES, GCRY_MD_MD5, 2048, + "\x93\x4C\x3D\x29\xA2\x42\xB0\xF5", + NULL, + NULL, + NULL, + "\x8C\x67\x19\x7F\xB9\x23\xE2\x8D" + } +}; + +#define N_GENERATION_TESTS (sizeof (all_generation_tests) / sizeof (all_generation_tests[0])) + +static void +test_generate_key_simple (void) +{ + int i; + gboolean ret; + guchar *key; + + for (i = 0; i < N_GENERATION_TESTS; ++i) { + + if (!all_generation_tests[i].result_simple) + continue; + + ret = egg_symkey_generate_simple (all_generation_tests[i].cipher_algo, + all_generation_tests[i].hash_algo, + all_generation_tests[i].password, -1, + (guchar*)all_generation_tests[i].salt, 8, + all_generation_tests[i].iterations, + &key, NULL); + g_assert (ret && "key generation failed"); + + ret = (memcmp (key, all_generation_tests[i].result_simple, + gcry_cipher_get_algo_keylen (all_generation_tests[i].cipher_algo)) == 0); + + g_assert (ret && "invalid simple key generated"); + + egg_secure_free (key); + } +} + +static void +test_generate_key_pkcs12 (void) +{ + int i; + gboolean ret; + guchar *key; + + for (i = 0; i < N_GENERATION_TESTS; ++i) { + + if (!all_generation_tests[i].result_pkcs12) + continue; + + ret = egg_symkey_generate_pkcs12 (all_generation_tests[i].cipher_algo, + all_generation_tests[i].hash_algo, + all_generation_tests[i].password, -1, + (guchar*)all_generation_tests[i].salt, 8, + all_generation_tests[i].iterations, + &key, NULL); + g_assert ("failed to generate pkcs12 key" && ret); + + ret = (memcmp (key, all_generation_tests[i].result_pkcs12, + gcry_cipher_get_algo_keylen (all_generation_tests[i].cipher_algo)) == 0); + + g_assert ("invalid pkcs12 key generated" && ret); + + egg_secure_free (key); + } +} + +static void +test_generate_key_pbkdf2 (void) +{ + int i; + gboolean ret; + guchar *key; + + for (i = 0; i < N_GENERATION_TESTS; ++i) { + + if (!all_generation_tests[i].result_pbkdf2) + continue; + + ret = egg_symkey_generate_pbkdf2 (all_generation_tests[i].cipher_algo, + all_generation_tests[i].hash_algo, + all_generation_tests[i].password, -1, + (guchar*)all_generation_tests[i].salt, 8, + all_generation_tests[i].iterations, + &key, NULL); + g_assert ("failed to generate pbkdf2 key" && ret); + + ret = (memcmp (key, all_generation_tests[i].result_pbkdf2, + gcry_cipher_get_algo_keylen (all_generation_tests[i].cipher_algo)) == 0); + + g_assert ("invalid pbkdf2 key generated" && ret); + + egg_secure_free (key); + } +} + +static void +test_generate_key_pbe (void) +{ + int i; + gboolean ret; + guchar *key; + + for (i = 0; i < N_GENERATION_TESTS; ++i) { + + if (!all_generation_tests[i].result_pbe) + continue; + + ret = egg_symkey_generate_pbe (all_generation_tests[i].cipher_algo, + all_generation_tests[i].hash_algo, + all_generation_tests[i].password, -1, + (guchar*)all_generation_tests[i].salt, 8, + all_generation_tests[i].iterations, + &key, NULL); + g_assert ("failed to generate pbe key" && ret); + + ret = (memcmp (key, all_generation_tests[i].result_pbe, + gcry_cipher_get_algo_keylen (all_generation_tests[i].cipher_algo)) == 0); + + g_assert ("invalid pbe key generated" && ret); + + egg_secure_free (key); + } +} + +typedef struct { + const gchar *name; + const gchar *scheme; + + /* Info to use with cipher */ + const gchar *password; + const gchar *salt; + gsize iterations; + + /* DER representation of cipher */ + gsize n_der; + const gchar *der; + + /* Data to encrypt and test with */ + gsize n_text_length; + const gchar *plain_text; + const gchar *cipher_text; +} ReadCipher; + +static const ReadCipher cipher_tests[] = { + { + "pbe-sha1-des-cbc", "1.2.840.113549.1.5.10", + "password", "saltsalt", 33, + 15, "\x30\x0D" + "\x04\x08""saltsalt" + "\x02\x01\x2A", + 8, "plaintex", "\x69\xe2\x88\x4c\x31\xcf\x0e\x2a" + }, + { + "pkcs12-pbe-3des-sha1", "1.2.840.113549.1.12.1.3", + "password", "saltsalt", 33, + 15, "\x30\x0D" + "\x04\x08""saltsalt" + "\x02\x01\x2A", + 8, "plaintex", "\xcf\xfb\x49\x2e\x42\x75\x15\x56" + }, + { + "pkcs5-pbes2", "1.2.840.113549.1.5.13", + "password", "salt", 33, + 48, "\x30\x2e" + "\x30\x16" + "\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x05\x0c" + "\x30\x09" + "\x04\x04\x73\x61\x6c\x74" + "\x02\x01\x21" + "\x30\x14" + "\x06\x08\x2a\x86\x48\x86\xf7\x0d\x03\x07" + "\x04\x08\x73\x61\x6c\x74\x73\x61\x6c\x74", + 8, "plaintex", "\x46\x1A\x3A\x39\xD0\xF5\x21\x5C" + }, + { + "pkcs5-pbes2-des-cbc", "1.2.840.113549.1.5.13", + "password", "salt", 33, + 0x2d, "\x30\x2b" + "\x30\x16" + "\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x05\x0c" + "\x30\x09" + "\x04\x04\x73\x61\x6c\x74" + "\x02\x01\x21" + "\x30\x11" + "\x06\x05\x2b\x0e\x03\x02\x07" + "\x04\x08\x73\x61\x6c\x74\x73\x61\x6c\x74", + 8, "plaintex", "\xB7\x7B\x54\xBF\x29\x4D\x31\x7D" + } +}; + +typedef struct { + const gchar *name; + const gchar *scheme; + + /* Info to use with cipher */ + const gchar *password; + + /* DER representation of cipher */ + gsize n_der; + const gchar *der; +} InvalidCipher; + +#if 0 +#include "egg/egg-hex.h" + +static void +create_pkcs5_pbes2 (void) +{ + GNode *asn; + GNode *param; + GBytes *bytes; + gconstpointer data; + gsize size; + + asn = egg_asn1x_create (pkix_asn1_tab, "pkcs-5-PBES2-params"); + + egg_asn1x_set_oid_as_string (egg_asn1x_node (asn, "keyDerivationFunc", "algorithm", NULL), "1.2.840.113549.1.5.12"); + param = egg_asn1x_create (pkix_asn1_tab, "pkcs-5-PBKDF2-params"); + egg_asn1x_set_integer_as_ulong (egg_asn1x_node (param, "iterationCount", NULL), 33); +#if 1 + egg_asn1x_set_choice (egg_asn1x_node (param, "salt", NULL), egg_asn1x_node (param, "salt", "specified", NULL)); + egg_asn1x_set_string_as_raw (egg_asn1x_node (param, "salt", "specified", NULL), (guchar *)"salt", 4, NULL); +#else + egg_asn1x_set_choice (egg_asn1x_node (param, "salt", NULL), egg_asn1x_node (param, "salt", "otherSource", NULL)); */ + egg_asn1x_set_oid_as_string (egg_asn1x_node (param, "salt", "otherSource", "algorithm", NULL), "1.2.1"); */ +#endif + egg_asn1x_set_any_from (egg_asn1x_node (asn, "keyDerivationFunc", "parameters", NULL), param); + egg_asn1x_destroy (param); + + egg_asn1x_set_oid_as_string (egg_asn1x_node (asn, "encryptionScheme", "algorithm", NULL), "1.3.14.3.2.7"); + param = egg_asn1x_create (pkix_asn1_tab, "pkcs-5-des-EDE3-CBC-params"); + egg_asn1x_set_string_as_raw (param, (guchar *)"saltsalt", 8, NULL); + egg_asn1x_set_any_from (egg_asn1x_node (asn, "encryptionScheme", "parameters", NULL), param); + egg_asn1x_destroy (param); + + bytes = egg_asn1x_encode (asn, NULL); + egg_asn1x_assert (bytes != NULL, asn); + egg_asn1x_destroy (asn); + + data = g_bytes_get_data (bytes, &size); + g_printerr ("%s: \\x%s\n", __FUNCTION__, egg_hex_encode_full (data, size, FALSE, "\\x", 1)); + g_bytes_unref (bytes); +} +#endif + +static void +test_read_cipher (gconstpointer data) +{ + const ReadCipher *test = data; + gcry_cipher_hd_t cih; + gcry_error_t gcry; + GNode *asn; + gboolean ret; + GBytes *bytes; + gpointer block; + + bytes = g_bytes_new_static (test->der, test->n_der); + asn = egg_asn1x_create_and_decode (test_asn1_tab, "TestAny", bytes); + g_assert (asn != NULL); + g_bytes_unref (bytes); + + ret = egg_symkey_read_cipher (g_quark_from_static_string (test->scheme), + test->password, strlen (test->password), + asn, &cih); + + egg_asn1x_destroy (asn); + g_assert (ret == TRUE); + + block = g_memdup (test->plain_text, test->n_text_length); + gcry = gcry_cipher_encrypt (cih, block, test->n_text_length, NULL, 0); + g_assert_cmpint (gcry, ==, 0); + + egg_assert_cmpmem (test->cipher_text, test->n_text_length, ==, + block, test->n_text_length); + + gcry_cipher_close (cih); + g_free (block); +} + +static const InvalidCipher cipher_invalid[] = { + { + "pbe-bad-der", "1.2.840.113549.1.12.1.3", + "password", + /* Valid DER, but not pkcs-12-PbeParams */ + 11, "\x30\x09\x04\x07""invalid" + }, + { + "pkcs5-pbe-bad-der", "1.2.840.113549.1.5.10", + "password", + /* Valid DER, but not pkcs-5-PBE-params */ + 11, "\x30\x09\x04\x07""invalid" + }, + { + "pkcs5-pbes2-bad-der", "1.2.840.113549.1.5.13", + "password", + /* Valid DER, but not pkcs-5-PBES2-params */ + 11, "\x30\x09\x04\x07""invalid" + }, + { + "pkcs5-pbes2-missing-key-parameters", "1.2.840.113549.1.5.13", + "password", + 0x25, "\x30\x23" + "\x30\x0b" + "\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x05\x0c" + /* Missing OPTIONAL parameters here */ + "\x30\x14" + "\x06\x08\x2a\x86\x48\x86\xf7\x0d\x03\x07" + "\x04\x08\x73\x61\x6c\x74\x73\x61\x6c\x74", + }, + { + "pkcs5-pbes2-missing-scheme-parameters", "1.2.840.113549.1.5.13", + "password", + 0x26, "\x30\x24" + "\x30\x16" + "\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x05\x0c" + "\x30\x09" + "\x04\x04\x73\x61\x6c\x74" + "\x02\x01\x21" + "\x30\x0a" + "\x06\x08\x2a\x86\x48\x86\xf7\x0d\x03\x07" + /* Missing OPTIONAL parameters here */ + }, + { + "pkcs5-pbes2-bad-key-derivation-algo", "1.2.840.113549.1.5.13", + "password", + 48, "\x30\x2e" + "\x30\x16" /* An unsupported keyDerivation algorithm oid */ + "\x06\x09\x2a\x86\x48\x86\xf7\x0c\x01\x04\x0b" + "\x30\x09" + "\x04\x04\x73\x61\x6c\x74" + "\x02\x01\x21" + "\x30\x14" + "\x06\x08\x2a\x86\x48\x86\xf7\x0d\x03\x07" + "\x04\x08\x73\x61\x6c\x74\x73\x61\x6c\x74", + }, + { + "pkcs5-pbes2-salt-not-specified", "1.2.840.113549.1.5.13", + "password", + 0x30, "\x30\x2e" + "\x30\x16" + "\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x05\x0c" + "\x30\x09" + "\x30\x04" + "\x06\x02\x2a\x01" + "\x02\x01\x21" + "\x30\x14" + "\x06\x08\x2a\x86\x48\x86\xf7\x0d\x03\x07" + "\x04\x08\x73\x61\x6c\x74\x73\x61\x6c\x74" + }, + { + "pkcs5-pbes2-unsupported-des-rc5-cbc", "1.2.840.113549.1.5.13", + "password", + 0x30, "\x30\x2e" + "\x30\x16" + "\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x05\x0c" + "\x30\x09" + "\x04\x04\x73\x61\x6c\x74" + "\x02\x01\x21" + "\x30\x14" + "\x06\x08\x2a\x86\x48\x86\xf7\x0d\x03\x09" + "\x04\x08\x73\x61\x6c\x74\x73\x61\x6c\x74" + } +}; + +static void +test_read_cipher_invalid (gconstpointer data) +{ + const InvalidCipher *test = data; + gcry_cipher_hd_t cih; + GNode *asn; + gboolean ret; + GBytes *bytes; + + bytes = g_bytes_new_static (test->der, test->n_der); + asn = egg_asn1x_create_and_decode (test_asn1_tab, "TestAny", bytes); + g_assert (asn != NULL); + g_bytes_unref (bytes); + + ret = egg_symkey_read_cipher (g_quark_from_static_string (test->scheme), + test->password, strlen (test->password), + asn, &cih); + + egg_asn1x_destroy (asn); + g_assert (ret == FALSE); +} + +static void +test_read_cipher_unsupported_pbe (void) +{ + gcry_cipher_hd_t cih; + GNode *asn; + gboolean ret; + GBytes *bytes; + + /* + * On many test systems RC2 is no longer supported by libgcrypt, but + * in case these tests are run elsewhere, double check. + */ + if (gcry_cipher_algo_info (GCRY_CIPHER_RFC2268_128, GCRYCTL_TEST_ALGO, NULL, 0) == 0) + return; + + bytes = g_bytes_new_static ("\x30\x09\x04\x07""invalid", 11); + asn = egg_asn1x_create_and_decode (test_asn1_tab, "TestAny", bytes); + g_assert (asn != NULL); + g_bytes_unref (bytes); + + ret = egg_symkey_read_cipher (g_quark_from_static_string ("1.2.840.113549.1.12.1.5"), + "blah", 4, asn, &cih); + + g_assert (ret == FALSE); + + egg_asn1x_destroy (asn); +} + +typedef struct { + const gchar *name; + const gchar *scheme; + gsize digest_len; + + /* Info to use with cipher */ + const gchar *password; + const gchar *salt; + gsize iterations; + + /* DER representation of cipher */ + gsize n_der; + const gchar *der; + + /* Data to encrypt and test with */ + gsize n_plain_length; + const gchar *plain_text; + const gchar *digest; +} ReadMac; + +static const ReadMac mac_tests[] = { + { + "sha1", "1.3.14.3.2.26", 20, + "password", "saltsalt", 33, + 31, "\x30\x1d" + "\x30\x12" + "\x30\x07" + "\x06\x05\x2b\x0e\x03\x02\x1a" + "\x04\x07""invalid" + "\x04\x04""salt" + "\x02\x01\x21", + 8, "plaintex", "\x8b\x96\x7f\xa2\xf4\x4f\x2d\x70\xcb\x59\x7e\x8f\xad\xf3\x92\x18\x70\x08\x5c\x57" + } +}; + +static void +test_read_mac (gconstpointer data) +{ + const ReadMac *test = data; + gcry_md_hd_t mdh; + gpointer digest; + gsize digest_len; + GNode *asn; + gboolean ret; + GBytes *bytes; + + bytes = g_bytes_new_static (test->der, test->n_der); + asn = egg_asn1x_create_and_decode (test_asn1_tab, "TestAny", bytes); + g_assert (asn != NULL); + g_bytes_unref (bytes); + + ret = egg_symkey_read_mac (g_quark_from_static_string (test->scheme), + test->password, strlen (test->password), + asn, &mdh, &digest_len); + + g_assert_cmpint (digest_len, ==, test->digest_len); + + egg_asn1x_destroy (asn); + g_assert (ret == TRUE); + + gcry_md_write (mdh, test->plain_text, test->n_plain_length); + digest = gcry_md_read (mdh, 0); + + egg_assert_cmpmem (test->digest, digest_len, ==, + digest, digest_len); + + gcry_md_close (mdh); +} + +static void +test_read_mac_invalid (void) +{ + gcry_md_hd_t mdh; + gsize digest_len; + GNode *asn; + gboolean ret; + GBytes *bytes; + + bytes = g_bytes_new_static ("\x30\x09\x04\x07""invalid", 11); + asn = egg_asn1x_create_and_decode (test_asn1_tab, "TestAny", bytes); + g_assert (asn != NULL); + g_bytes_unref (bytes); + + ret = egg_symkey_read_mac (g_quark_from_static_string ("1.3.14.3.2.26"), + "blah", 4, asn, &mdh, &digest_len); + + g_assert (ret == FALSE); + + egg_asn1x_destroy (asn); +} + +static void +null_log_handler (const gchar *log_domain, GLogLevelFlags log_level, + const gchar *message, gpointer user_data) +{ + +} + +int +main (int argc, char **argv) +{ + gchar *name; + gint i; + + g_test_init (&argc, &argv, NULL); + egg_libgcrypt_initialize (); + + /* Suppress these messages in tests */ + g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO, + null_log_handler, NULL); + + g_test_add_func ("/symkey/generate_key_simple", test_generate_key_simple); + g_test_add_func ("/symkey/generate_key_pkcs12", test_generate_key_pkcs12); + g_test_add_func ("/symkey/generate_key_pbkdf2", test_generate_key_pbkdf2); + g_test_add_func ("/symkey/generate_key_pbe", test_generate_key_pbe); + + for (i = 0; i < G_N_ELEMENTS (cipher_tests); i++) { + name = g_strdup_printf ("/symkey/read-cipher/%s", cipher_tests[i].name); + g_test_add_data_func (name, cipher_tests + i, test_read_cipher); + g_free (name); + } + + for (i = 0; i < G_N_ELEMENTS (cipher_invalid); i++) { + name = g_strdup_printf ("/symkey/read-cipher-invalid/%s", cipher_invalid[i].name); + g_test_add_data_func (name, cipher_invalid + i, test_read_cipher_invalid); + g_free (name); + } + + g_test_add_func ("/symkey/read-cipher-unsupported/pbe", test_read_cipher_unsupported_pbe); + + for (i = 0; i < G_N_ELEMENTS (mac_tests); i++) { + name = g_strdup_printf ("/symkey/read-mac/%s", mac_tests[i].name); + g_test_add_data_func (name, mac_tests + i, test_read_mac); + g_free (name); + } + + g_test_add_func ("/symkey/read-mac-invalid", test_read_mac_invalid); + + return g_test_run (); +} |