--- /dev/null
+/* -*- 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;
+}
/* -*- 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
#include <string.h>
#include <time.h>
#include <ctype.h>
+#include <assert.h>
#include <yubikey.h>
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];
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)
{
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);
_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;
}
/* 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);