]> err.no Git - yubikey-personalization/commitdiff
Make ykp_AES_key_from_passphrase() handle 160 bit keys too.
authorFredrik Thulin <fredrik@yubico.com>
Mon, 31 Jan 2011 12:44:06 +0000 (13:44 +0100)
committerFredrik Thulin <fredrik@yubico.com>
Mon, 31 Jan 2011 12:54:02 +0000 (13:54 +0100)
tests/Makefile.am
tests/test_key_generation.c [new file with mode: 0644]
ykpers.c

index ece6e63ca586b800bfa448ab20efa2c2d38e1d40..9f07a1ff8facf4be6670dfc09d9656a648141ecc 100644 (file)
@@ -33,7 +33,7 @@ LDADD = ../libykpers-1.la
 
 ykpersonalize_LDADD = ../libykpers-1.la ../ykcore/libykcore.la
 
-ctests = selftest$(EXEEXT) test_args_to_config$(EXEEXT)
+ctests = selftest$(EXEEXT) test_args_to_config$(EXEEXT) test_key_generation$(EXEEXT)
 check_PROGRAMS = $(ctests)
 TESTS = $(ctests)
 
diff --git a/tests/test_key_generation.c b/tests/test_key_generation.c
new file mode 100644 (file)
index 0000000..57c226d
--- /dev/null
@@ -0,0 +1,96 @@
+/* -*- mode:C; c-file-style: "bsd" -*- */
+/*
+ * Copyright (c) 2011, Yubico AB
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include <ykpers.h>
+#include <ykdef.h>
+
+void _test_128_bits_key(YKP_CONFIG *ykp, struct config_st *cfg)
+{
+       unsigned char empty[256];
+
+       memset (empty, 0, sizeof(empty));
+       memset (cfg, 0, sizeof(cfg));
+       cfg->tktFlags = TKTFLAG_APPEND_CR;
+
+       ykp_AES_key_from_passphrase(ykp, "test", "ABCDEF");
+
+       /* make sure config.key now has non-zero bytes in it */
+       assert(memcmp(cfg->key, empty, sizeof(cfg->key)) != 0);
+       /* make sure config.uid is still zero for 128 bits config */
+       assert(memcmp(cfg->uid, empty, sizeof(cfg->uid)) == 0);
+}
+
+void _test_160_bits_key(YKP_CONFIG *ykp, struct config_st *cfg)
+{
+       unsigned char empty[256];
+
+       memset (empty, 0, sizeof(empty));
+       memset (cfg, 0, sizeof(cfg));
+       cfg->tktFlags = TKTFLAG_APPEND_CR | TKTFLAG_OATH_HOTP;
+
+       ykp_AES_key_from_passphrase(ykp, "test", "ABCDEF");
+
+       /* make sure config.key now has non-zero bytes in it */
+       assert(memcmp(cfg->key, empty, sizeof(cfg->key)) != 0);
+       /* make sure config.uid is NOT zero for 160 bits config */
+       assert(memcmp(cfg->uid, empty, sizeof(cfg->uid)) != 0);
+}
+
+int main (void)
+{
+       YKP_CONFIG *ykp;
+       struct config_st *ycfg;
+       int rc;
+
+       ykp = ykp_create_config ();
+       if (!ykp)
+       {
+               printf ("ykp_create_config returned NULL\n");
+               return 1;
+       }
+
+       ycfg = (struct config_st *) ykp_core_config(ykp);
+
+       _test_128_bits_key(ykp, ycfg);
+       _test_160_bits_key(ykp, ycfg);
+
+       rc = ykp_free_config(ykp);
+       if (!rc)
+       {
+               printf ("ykp_free_config => %d\n", rc);
+               return 1;
+       }
+
+       return 0;
+}
index b5c88cd8d1c98d3df02de97facb2e7da7151069f..5a1a718873fe077f6c30dad86858107e27416e94 100644 (file)
--- a/ykpers.c
+++ b/ykpers.c
@@ -1,6 +1,6 @@
 /* -*- mode:C; c-file-style: "bsd" -*- */
 /*
- * Copyright (c) 2008, 2009, 2010, Yubico AB
+ * Copyright (c) 2008, 2009, 2010, 2011 Yubico AB
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -38,6 +38,7 @@
 #include <string.h>
 #include <time.h>
 #include <ctype.h>
+#include <assert.h>
 
 #include <yubikey.h>
 
@@ -126,6 +127,27 @@ int ykp_configure_for(YKP_CONFIG *cfg, int confnum, YK_STATUS *st)
        return 0;
 }
 
+/* Return number of bytes of key data for this configuration.
+ * 20 bytes is 160 bits, 16 bytes is 128.
+ */
+int _get_supported_key_length(const YKP_CONFIG *cfg)
+{
+       bool key_bits_in_uid = false;
+
+       /* OATH-HOTP and HMAC-SHA1 challenge response support 20 byte (160 bits)
+        * keys, holding the last four bytes in the uid field.
+        */
+       if ((cfg->ykcore_config.tktFlags & TKTFLAG_OATH_HOTP) == TKTFLAG_OATH_HOTP)
+               return 20;
+               
+       if ((cfg->ykcore_config.tktFlags & TKTFLAG_CHAL_RESP) == TKTFLAG_CHAL_RESP &&
+           (cfg->ykcore_config.cfgFlags & CFGFLAG_CHAL_HMAC) == CFGFLAG_CHAL_HMAC) {
+               return 20;
+       }
+
+       return 16;
+}
+
 /* Decode 128 bit AES key into cfg->ykcore_config.key */
 int ykp_AES_key_from_hex(YKP_CONFIG *cfg, const char *hexkey) {
        char aesbin[256];
@@ -171,6 +193,13 @@ int ykp_HMAC_key_from_hex(YKP_CONFIG *cfg, const char *hexkey) {
        return 0;
 }
 
+/* Generate an AES (128 bits) or HMAC (despite the function name) (160 bits)
+ * key from user entered input.
+ *
+ * Use user provided salt, or use salt from an available random device.
+ * If no random device is available we fall back to using 2048 bits of
+ * system time data, together with the user input, as salt.
+ */
 int ykp_AES_key_from_passphrase(YKP_CONFIG *cfg, const char *passphrase,
                                const char *salt)
 {
@@ -184,6 +213,11 @@ int ykp_AES_key_from_passphrase(YKP_CONFIG *cfg, const char *passphrase,
                char **random_place;
                uint8_t _salt[8];
                size_t _salt_len = 0;
+               unsigned char buf[sizeof(cfg->ykcore_config.key) + 4];
+               int rc;
+               int key_bytes = _get_supported_key_length(cfg);
+               
+               assert (key_bytes <= sizeof(buf));
 
                if (salt) {
                        _salt_len = strlen(salt);
@@ -228,11 +262,22 @@ int ykp_AES_key_from_passphrase(YKP_CONFIG *cfg, const char *passphrase,
                        _salt_len = sizeof(_salt);
                }
 
-               return yk_pbkdf2(passphrase,
-                                _salt, _salt_len,
-                                1024,
-                                cfg->ykcore_config.key, sizeof(cfg->ykcore_config.key),
-                                &yk_hmac_sha1);
+               rc = yk_pbkdf2(passphrase,
+                              _salt, _salt_len,
+                              1024,
+                              buf, key_bytes,
+                              &yk_hmac_sha1);
+
+               if (rc) {
+                       memcpy(cfg->ykcore_config.key, buf, sizeof(cfg->ykcore_config.key));
+
+                       if (key_bytes == 20) {
+                               memcpy(cfg->ykcore_config.uid, buf + sizeof(cfg->ykcore_config.key), 4);
+                       }
+               }
+
+               memset (buf, 0, sizeof(buf));
+               return rc;
        }
        return 0;
 }
@@ -466,13 +511,7 @@ int ykp_write_config(const YKP_CONFIG *cfg,
                /* for OATH-HOTP and HMAC-SHA1 challenge response, there is four bytes
                 *  additional key data in the uid field
                 */
-               if ((cfg->ykcore_config.tktFlags & TKTFLAG_OATH_HOTP) == TKTFLAG_OATH_HOTP)
-                       key_bits_in_uid = true;
-               
-               if ((cfg->ykcore_config.tktFlags & TKTFLAG_CHAL_RESP) == TKTFLAG_CHAL_RESP &&
-                   (cfg->ykcore_config.cfgFlags & CFGFLAG_CHAL_HMAC) == CFGFLAG_CHAL_HMAC) {
-                       key_bits_in_uid = true;
-               }
+               key_bits_in_uid = (_get_supported_key_length(cfg) == 20);
 
                /* fixed: */
                writer(str_fixed, strlen(str_fixed), userdata);