void yubikey_parse (const uint8_t token[32], const uint8_t key[16], yubikey_token_t out) { memset (out, 0, sizeof (*out)); yubikey_modhex_decode ((void *) out, (char *) token, sizeof (*out)); yubikey_aes_decrypt ((void *) out, key); }
/* Called by: zx_password_authn */ int zx_yubikey_authn(const char* cpath, char* uid, const char* passw, const char* pin) { unsigned char uidpath[256]; unsigned char pw_buf[256]; unsigned char pw_hash[120]; yubikey_token_st yktok; int len = strlen(uid); strcpy((char*)pw_hash, uid + len - 32); uid[len - 32] = 0; D("yubikey user(%s) ticket(%s) pin(%s)", uid, pw_hash, STRNULLCHK(pin)); snprintf((char*)uidpath, sizeof(uidpath)-1, "%s" ZXID_UID_DIR "%s", cpath, uid); uidpath[sizeof(uidpath)-1] = 0; len = read_all(sizeof(pw_buf), (char*)pw_buf, "ykspent", 0, "%s/.ykspent/%s", uidpath, pw_hash); if (len) { ERR("The One Time Password has already been spent. ticket(%s%s) pw_buf(%.*s)", uid, pw_hash, len, pw_buf); return 0; } if (!write_all_path("ykspent", "%s/.ykspent/%s", (char*)uidpath, (char*)pw_hash, 1, "1")) return 0; len = read_all(sizeof(pw_buf), (char*)pw_buf, "ykaes", 1, "%s/.yk", uidpath); D("buf (%s) got=%d", pw_buf, len); if (len < 32) { ERR("User's %s/.yk file must contain aes128 key as 32 hexadecimal characters. Too few characters %d ticket(%s)", uid, len, pw_hash); return 0; } if (len > 32) { INFO("User's %s/.yk file must contain aes128 key as 32 hexadecimal characters. Too many characters %d ticket(%s). Truncating.", uid, len, pw_hash); len = 32; pw_buf[len] = 0; } zx_hexdec((char*)pw_buf, (char*)pw_buf, len, hex_trans); ZERO(&yktok, sizeof(yktok)); zx_hexdec((void*)&yktok, (char*)pw_hash, 32, ykmodhex_trans); yubikey_aes_decrypt((void*)&yktok, pw_buf); D("internal uid %02x %02x %02x %02x %02x %02x counter=%d 0x%x timestamp=%d (hi=%x lo=%x) use=%d 0x%x rnd=0x%x crc=0x%x", yktok.uid[0], yktok.uid[1], yktok.uid[2], yktok.uid[3], yktok.uid[4], yktok.uid[5], yktok.ctr, yktok.ctr, (yktok.tstph << 16) | yktok.tstpl, yktok.tstph, yktok.tstpl, yktok.use, yktok.use, yktok.rnd, yktok.crc); if (!yubikey_crc_ok_p((unsigned char*)&yktok)) { ERR("yubikey ticket validation failure %d", 0); return 0; } if (pin && *pin) { /* Pin supplied, may be we can perform two factor authn? */ len = read_all(sizeof(pw_buf), (char*)pw_buf, "pin", 1, "%s/.pin", uidpath); if (zx_pw_chk(uid, (char*)pw_buf, pin, 0)) { D("Two factor pin+yubikey successful. %d", 1); return 4; } ERR("pin validation failure (after successful yubikey) %d", 0); return 0; } return 3; }
int yubikey_parse(const uint8_t *password, const uint8_t key[YUBIKEY_KEY_SIZE], yubikey_token_t out, int index) { wchar_t *wpassword, *pp; char token[YUBIKEY_TOKEN_SIZE + 1], *lc_ctype; int len; if (index < 0 || index >= YUBIKEY_KEYMAP_COUNT) return -1; len = strlen(password); pp = wpassword = malloc(sizeof(wchar_t) * (len + 1)); if (pp == NULL) return ENOMEM; memset(out, 0, sizeof(*out)); memset(token, 0, YUBIKEY_TOKEN_SIZE + 1); lc_ctype = getenv("LC_CTYPE"); setlocale(LC_CTYPE, lc_ctype ? lc_ctype : "C.UTF-8"); len = mbstowcs(wpassword, password, len); if (len < 0) { return errno; } setlocale(LC_CTYPE, "C"); if (len > YUBIKEY_TOKEN_SIZE) pp = pp + len - YUBIKEY_TOKEN_SIZE; if (len < YUBIKEY_TOKEN_SIZE) return EMSGSIZE; if (yubikey_keymap_decode(pp, token, index)) return EINVAL; yubikey_modhex_decode((void *)out, token, sizeof(*out)); yubikey_aes_decrypt((void *)out, key); return 0; }
static void aes_test1 (void) { size_t i; uint8_t buf[1024]; uint8_t key[16 + 1]; memcpy (buf, "0123456789abcdef\0", 17); memcpy (key, "abcdef0123456789\0", 17); printf ("aes-decrypt (data=%s, key=%s)\n => ", (char *) buf, (char *) key); yubikey_aes_decrypt (buf, key); for (i = 0; i < 16; i++) printf ("%02x", buf[i] & 0xFF); printf ("\n"); assert (memcmp (buf, "\x83\x8a\x46\x7f\x34\x63\x95\x51" "\x75\x5b\xd3\x2a\x4a\x2f\x15\xe1", 16) == 0); printf ("AES-1.1 success\n"); yubikey_aes_encrypt (buf, key); assert (memcmp (buf, "0123456789abcdef", 16) == 0); printf ("AES-1.2 success\n"); }
int main (void) { char buf[1024]; size_t i; int rc; yubikey_token_st tok; /* Test Modhex */ yubikey_modhex_encode (buf, "test", 4); printf ("modhex-encode(\"test\") = %s\n", buf); if (strcmp (buf, "ifhgieif") != 0) { printf ("ModHex failure\n"); return 1; } printf ("Modhex-1 success\n"); printf ("modhex-decode(\"%s\") = ", buf); yubikey_modhex_decode (buf, buf, strlen ((char *) buf)); printf ("%.*s\n", 4, buf); if (memcmp (buf, "test", 4) != 0) { printf ("ModHex failure\n"); return 1; } printf ("Modhex-2 success\n"); strcpy (buf, "cbdefghijklnrtuv"); rc = yubikey_modhex_p (buf); printf ("hex-p(\"%s\") = %d\n", buf, rc); if (!rc) { printf ("Hex_p failure\n"); return 1; } printf ("Hex-3 success\n"); strcpy (buf, "0123Xabc"); rc = yubikey_hex_p (buf); printf ("hex-p(\"%s\") = %d\n", buf, rc); if (rc) { printf ("Hex_p failure\n"); return 1; } printf ("Hex-3 success\n"); /* Test Hex */ yubikey_hex_encode (buf, "test", 4); printf ("hex-encode(\"test\") = %s\n", buf); if (strcmp (buf, "74657374") != 0) { printf ("Hex failure\n"); return 1; } printf ("Hex-1 success\n"); printf ("hex-decode(\"%s\") = ", buf); yubikey_hex_decode (buf, buf, strlen ((char *) buf)); printf ("%.*s\n", 4, buf); if (memcmp (buf, "test", 4) != 0) { printf ("Hex failure\n"); return 1; } printf ("Hex-2 success\n"); strcpy (buf, "0123456789abcdef"); rc = yubikey_hex_p (buf); printf ("hex-p(\"%s\") = %d\n", buf, rc); if (!rc) { printf ("Hex_p failure\n"); return 1; } printf ("Hex-3 success\n"); strcpy (buf, "0123Xabc"); rc = yubikey_hex_p (buf); printf ("hex-p(\"%s\") = %d\n", buf, rc); if (rc) { printf ("Hex_p failure\n"); return 1; } printf ("Hex-3 success\n"); /* Test AES */ { uint8_t buf[1024]; char out[1024]; uint8_t key[16 + 1]; memcpy (buf, "0123456789abcdef\0", 17); memcpy (key, "abcdef0123456789\0", 17); printf ("aes-decrypt (data=%s, key=%s)\n => ", (char *) buf, (char *) key); yubikey_aes_decrypt (buf, key); for (i = 0; i < 16; i++) printf ("%02x", buf[i] & 0xFF); printf ("\n"); if (memcmp (buf, "\x83\x8a\x46\x7f\x34\x63\x95\x51" "\x75\x5b\xd3\x2a\x4a\x2f\x15\xe1", 16) != 0) { printf ("AES failure\n"); return 1; } printf ("AES-1 success\n"); yubikey_aes_encrypt (buf, key); if (memcmp (buf, "0123456789abcdef", 16) != 0) { printf ("AES encryption failure\n"); return 1; } printf ("AES-2 success\n"); /* Test OTP */ memcpy ((void *) &tok, "\x16\xe1\xe5\xd9\xd3\x99\x10\x04\x45\x20\x07\xe3\x02\x00\x00", 16); memcpy (key, "abcdef0123456789", 16); yubikey_generate ((void *) &tok, key, out); yubikey_parse ((uint8_t *) out, key, &tok); if (memcmp (&tok, "\x16\xe1\xe5\xd9\xd3\x99\x10\x04\x45\x20\x07\xe3\x02\x00\x00", 16) != 0) { printf ("OTP generation - parse failure\n"); return 1; } printf ("OTP-1 success\n"); } return 0; }