/* 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) { if (cfg) { char *random_places[] = { "/dev/srandom", "/dev/urandom", "/dev/random", 0 }; 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); if (_salt_len > 8) _salt_len = 8; memcpy(_salt, salt, _salt_len); } else { for (random_place = random_places; *random_place; random_place++) { FILE *random_file = fopen(*random_place, "r"); if (random_file) { size_t read_bytes = 0; while (read_bytes < sizeof(_salt)) { size_t n = fread(&_salt[read_bytes], 1, sizeof (_salt) - read_bytes, random_file); read_bytes += n; } fclose(random_file); _salt_len = sizeof(_salt); break; /* from for loop */ } } } if (_salt_len == 0) { /* There was no randomness files, so create a cheap salt from time */ # include <ykpbkdf2.h> time_t t = time(NULL); uint8_t output[256]; /* 2048 bits is a lot! */ yk_hmac_sha1.prf_fn(passphrase, strlen(passphrase), (char *)&t, sizeof(t), output, sizeof(output)); memcpy(_salt, output, sizeof(_salt)); _salt_len = sizeof(_salt); } 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; }
int ykp_write_config(const YKP_CONFIG *cfg, int (*writer)(const char *buf, size_t count, void *userdata), void *userdata) { if (cfg) { char buffer[256]; struct map_st *p; unsigned char t_flags; bool key_bits_in_uid = false; /* for OATH-HOTP and HMAC-SHA1 challenge response, there is four bytes * additional key data in the uid field */ key_bits_in_uid = (_get_supported_key_length(cfg) == 20); /* fixed: */ writer(str_fixed, strlen(str_fixed), userdata); writer(str_key_value_separator, strlen(str_key_value_separator), userdata); /* XXX print OATH-HOTP fixed differently based on oath-fixed-modhex etc. */ writer(str_modhex_prefix, strlen(str_key_value_separator), userdata); yubikey_modhex_encode(buffer, (char *)cfg->ykcore_config.fixed, cfg->ykcore_config.fixedSize); writer(buffer, strlen(buffer), userdata); writer("\n", 1, userdata); /* uid: */ writer(str_uid, strlen(str_uid), userdata); writer(str_key_value_separator, strlen(str_key_value_separator), userdata); if (key_bits_in_uid) { writer("n/a", 3, userdata); } else { writer(str_hex_prefix, strlen(str_key_value_separator), userdata); yubikey_hex_encode(buffer, (char *)cfg->ykcore_config.uid, UID_SIZE); writer(buffer, strlen(buffer), userdata); } writer("\n", 1, userdata); /* key: */ writer(str_key, strlen(str_key), userdata); writer(str_key_value_separator, strlen(str_key_value_separator), userdata); writer(str_hex_prefix, strlen(str_key_value_separator), userdata); yubikey_hex_encode(buffer, (char *)cfg->ykcore_config.key, KEY_SIZE); if (key_bits_in_uid) { yubikey_hex_encode(buffer + KEY_SIZE * 2, (char *)cfg->ykcore_config.uid, 4); } writer(buffer, strlen(buffer), userdata); writer("\n", 1, userdata); /* acc_code: */ writer(str_acc_code, strlen(str_acc_code), userdata); writer(str_key_value_separator, strlen(str_key_value_separator), userdata); writer(str_hex_prefix, strlen(str_key_value_separator), userdata); yubikey_hex_encode(buffer, (char *)cfg->ykcore_config.accCode, ACC_CODE_SIZE); writer(buffer, strlen(buffer), userdata); writer("\n", 1, userdata); /* ticket_flags: */ buffer[0] = '\0'; for (p = ticket_flags_map; p->flag; p++) { if ((cfg->ykcore_config.tktFlags & p->flag) == p->flag && p->vcheck(cfg)) { if (*buffer) { strcat(buffer, str_flags_separator); strcat(buffer, p->flag_text); } else { strcpy(buffer, p->flag_text); } } } writer(str_ticket_flags, strlen(str_ticket_flags), userdata); writer(str_key_value_separator, strlen(str_key_value_separator), userdata); writer(buffer, strlen(buffer), userdata); writer("\n", 1, userdata); /* config_flags: */ buffer[0] = '\0'; t_flags = cfg->ykcore_config.cfgFlags; for (p = config_flags_map; p->flag; p++) { if ((t_flags & p->flag) == p->flag && p->vcheck(cfg) && (cfg->ykcore_config.tktFlags & p->tkt_context) == p->tkt_context) { if (*buffer) { strcat(buffer, str_flags_separator); strcat(buffer, p->flag_text); } else { strcpy(buffer, p->flag_text); } /* make sure we don't show more than one cfgFlag per value - some cfgflags share value in different contexts */ t_flags -= p->flag; } } writer(str_config_flags, strlen(str_config_flags), userdata); writer(str_key_value_separator, strlen(str_key_value_separator), userdata); writer(buffer, strlen(buffer), userdata); writer("\n", 1, userdata); /* extended_flags: */ buffer[0] = '\0'; for (p = extended_flags_map; p->flag; p++) { if ((cfg->ykcore_config.extFlags & p->flag) == p->flag && p->vcheck(cfg)) { if (*buffer) { strcat(buffer, str_flags_separator); strcat(buffer, p->flag_text); } else { strcpy(buffer, p->flag_text); } } } writer(str_extended_flags, strlen(str_extended_flags), userdata); writer(str_key_value_separator, strlen(str_key_value_separator), userdata); writer(buffer, strlen(buffer), userdata); writer("\n", 1, userdata); return 1; } return 0; }
static int _ykp_legacy_export_config(const YKP_CONFIG *cfg, char *buf, size_t len) { if (cfg) { char buffer[256]; struct map_st *p; unsigned char t_flags; bool key_bits_in_uid = false; YK_CONFIG ycfg = cfg->ykcore_config; int mode = MODE_OTP_YUBICO; int pos = 0; if((ycfg.tktFlags & TKTFLAG_OATH_HOTP) == TKTFLAG_OATH_HOTP){ if((ycfg.cfgFlags & CFGFLAG_CHAL_HMAC) == CFGFLAG_CHAL_HMAC) { mode = MODE_CHAL_HMAC; } else if((ycfg.cfgFlags & CFGFLAG_CHAL_YUBICO) == CFGFLAG_CHAL_YUBICO) { mode = MODE_CHAL_YUBICO; } else { mode = MODE_OATH_HOTP; } } else if((ycfg.cfgFlags & CFGFLAG_STATIC_TICKET) == CFGFLAG_STATIC_TICKET) { mode = MODE_STATIC_TICKET; } /* for OATH-HOTP and HMAC-SHA1 challenge response, there is four bytes * additional key data in the uid field */ key_bits_in_uid = (_get_supported_key_length(cfg) == 20); /* fixed: or OATH id: */ if ((ycfg.tktFlags & TKTFLAG_OATH_HOTP) == TKTFLAG_OATH_HOTP && ycfg.fixedSize) { /* First byte (vendor id) */ if ((ycfg.cfgFlags & CFGFLAG_OATH_FIXED_MODHEX1) == CFGFLAG_OATH_FIXED_MODHEX1 || (ycfg.cfgFlags & CFGFLAG_OATH_FIXED_MODHEX2) == CFGFLAG_OATH_FIXED_MODHEX2 || (ycfg.cfgFlags & CFGFLAG_OATH_FIXED_MODHEX) == CFGFLAG_OATH_FIXED_MODHEX) { yubikey_modhex_encode(buffer, (const char *)ycfg.fixed, 1); } else { yubikey_hex_encode(buffer, (const char *)ycfg.fixed, 1); } /* Second byte (token type) */ if ((ycfg.cfgFlags & CFGFLAG_OATH_FIXED_MODHEX2) == CFGFLAG_OATH_FIXED_MODHEX2 || (ycfg.cfgFlags & CFGFLAG_OATH_FIXED_MODHEX) == CFGFLAG_OATH_FIXED_MODHEX) { yubikey_modhex_encode(buffer + 2, (const char *)ycfg.fixed + 1, 1); } else { yubikey_hex_encode(buffer + 2, (const char *)ycfg.fixed + 1, 1); } /* bytes 3-12 - MUI */ if ((ycfg.cfgFlags & CFGFLAG_OATH_FIXED_MODHEX) == CFGFLAG_OATH_FIXED_MODHEX) { yubikey_modhex_encode(buffer + 4, (const char *)ycfg.fixed + 2, 8); } else { yubikey_hex_encode(buffer + 4, (const char *)ycfg.fixed + 2, 8); } buffer[12] = 0; pos += snprintf(buf, len - (size_t)pos, "%s%s%s\n", str_oath_id, str_key_value_separator, buffer); } else { yubikey_modhex_encode(buffer, (const char *)ycfg.fixed, ycfg.fixedSize); pos += snprintf(buf, len - (size_t)pos, "%s%s%s%s\n", str_fixed, str_key_value_separator, str_modhex_prefix, buffer); } /* uid: */ if (key_bits_in_uid) { strncpy(buffer, "n/a", 3); } else { yubikey_hex_encode(buffer, (const char *)ycfg.uid, UID_SIZE); } pos += snprintf(buf + pos, len - (size_t)pos, "%s%s%s\n", str_uid, str_key_value_separator, buffer); /* key: */ yubikey_hex_encode(buffer, (const char *)ycfg.key, KEY_SIZE); if (key_bits_in_uid) { yubikey_hex_encode(buffer + KEY_SIZE * 2, (const char *)ycfg.uid, 4); } pos += snprintf(buf + pos, len - (size_t)pos, "%s%s%s%s\n", str_key, str_key_value_separator, str_hex_prefix, buffer); /* acc_code: */ yubikey_hex_encode(buffer, (const char*)ycfg.accCode, ACC_CODE_SIZE); pos += snprintf(buf + pos, len - (size_t)pos, "%s%s%s%s\n", str_acc_code, str_key_value_separator, str_hex_prefix, buffer); /* OATH IMF: */ if ((ycfg.tktFlags & TKTFLAG_OATH_HOTP) == TKTFLAG_OATH_HOTP && capability_has_oath_imf(cfg)) { pos += snprintf(buf + pos, len - (size_t)pos, "%s%s%s%lx\n", str_oath_imf, str_key_value_separator, str_hex_prefix, ykp_get_oath_imf(cfg)); } /* ticket_flags: */ buffer[0] = '\0'; for (p = _ticket_flags_map; p->flag; p++) { if ((ycfg.tktFlags & p->flag) == p->flag && p->capability(cfg) && (mode & p->mode) == mode) { if (*buffer) { strcat(buffer, str_flags_separator); strcat(buffer, p->flag_text); } else { strcpy(buffer, p->flag_text); } } } pos += snprintf(buf + pos, len - (size_t)pos, "%s%s%s\n", str_ticket_flags, str_key_value_separator, buffer); /* config_flags: */ buffer[0] = '\0'; t_flags = ycfg.cfgFlags; for (p = _config_flags_map; p->flag; p++) { if ((t_flags & p->flag) == p->flag && p->capability(cfg) && (mode & p->mode) == mode) { if (*buffer) { strcat(buffer, str_flags_separator); strcat(buffer, p->flag_text); } else { strcpy(buffer, p->flag_text); } /* make sure we don't show more than one cfgFlag per value - some cfgflags share value in different contexts */ t_flags -= p->flag; } } pos += snprintf(buf + pos, len - (size_t)pos, "%s%s%s\n", str_config_flags, str_key_value_separator, buffer); /* extended_flags: */ buffer[0] = '\0'; for (p = _extended_flags_map; p->flag; p++) { if ((ycfg.extFlags & p->flag) == p->flag && p->capability(cfg) && (mode & p->mode) == mode) { if (*buffer) { strcat(buffer, str_flags_separator); strcat(buffer, p->flag_text); } else { strcpy(buffer, p->flag_text); } } } pos += snprintf(buf + pos, len - (size_t)pos, "%s%s%s\n", str_extended_flags, str_key_value_separator, buffer); return pos; } return 0; }