xref: /openbsd-src/libexec/login_yubikey/yubikey.c (revision 6cc4e57d498809f6ec364f1c10349bb4b55a87d8)
1*6cc4e57dSanton /* $OpenBSD: yubikey.c,v 1.6 2017/09/16 08:07:15 anton Exp $ */
25e4064a0Sdhill 
35e4064a0Sdhill /*
45e4064a0Sdhill  * Written by Simon Josefsson <simon@josefsson.org>.
55e4064a0Sdhill  * Copyright (c) 2006, 2007, 2008, 2009 Yubico AB
65e4064a0Sdhill  * Copyright (c) 2010 Daniel Hartmeier <daniel@benzedrine.cx>
75e4064a0Sdhill  * All rights reserved.
85e4064a0Sdhill  *
95e4064a0Sdhill  * Redistribution and use in source and binary forms, with or without
105e4064a0Sdhill  * modification, are permitted provided that the following conditions are
115e4064a0Sdhill  * met:
125e4064a0Sdhill  *
135e4064a0Sdhill  * * Redistributions of source code must retain the above copyright
145e4064a0Sdhill  *   notice, this list of conditions and the following disclaimer.
155e4064a0Sdhill  *
165e4064a0Sdhill  * * Redistributions in binary form must reproduce the above
175e4064a0Sdhill  *   copyright notice, this list of conditions and the following
185e4064a0Sdhill  *   disclaimer in the documentation and/or other materials provided
195e4064a0Sdhill  *   with the distribution.
205e4064a0Sdhill  *
215e4064a0Sdhill  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
225e4064a0Sdhill  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
235e4064a0Sdhill  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
245e4064a0Sdhill  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
255e4064a0Sdhill  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
265e4064a0Sdhill  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
275e4064a0Sdhill  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
285e4064a0Sdhill  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
295e4064a0Sdhill  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
305e4064a0Sdhill  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
315e4064a0Sdhill  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
325e4064a0Sdhill  *
335e4064a0Sdhill  */
345e4064a0Sdhill 
356e526c06Shalex #include <ctype.h>
363ef0233cSmcbride #include <stdlib.h>
373ef0233cSmcbride #include <wchar.h>
383ef0233cSmcbride #include <locale.h>
393ef0233cSmcbride #include <errno.h>
406e526c06Shalex 
415e4064a0Sdhill #include "yubikey.h"
423ef0233cSmcbride #include "keymaps.h"
435e4064a0Sdhill 
445e4064a0Sdhill static const uint8_t RC[] = {
455e4064a0Sdhill 	0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36
465e4064a0Sdhill };
475e4064a0Sdhill 
485e4064a0Sdhill static const uint8_t rijndael_sbox[] = {
495e4064a0Sdhill 	0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5,
505e4064a0Sdhill 	0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
515e4064a0Sdhill 	0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0,
525e4064a0Sdhill 	0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
535e4064a0Sdhill 	0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC,
545e4064a0Sdhill 	0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
555e4064a0Sdhill 	0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A,
565e4064a0Sdhill 	0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
575e4064a0Sdhill 	0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0,
585e4064a0Sdhill 	0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
595e4064a0Sdhill 	0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B,
605e4064a0Sdhill 	0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
615e4064a0Sdhill 	0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85,
625e4064a0Sdhill 	0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
635e4064a0Sdhill 	0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5,
645e4064a0Sdhill 	0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
655e4064a0Sdhill 	0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17,
665e4064a0Sdhill 	0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
675e4064a0Sdhill 	0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88,
685e4064a0Sdhill 	0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
695e4064a0Sdhill 	0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C,
705e4064a0Sdhill 	0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
715e4064a0Sdhill 	0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9,
725e4064a0Sdhill 	0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
735e4064a0Sdhill 	0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6,
745e4064a0Sdhill 	0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
755e4064a0Sdhill 	0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E,
765e4064a0Sdhill 	0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
775e4064a0Sdhill 	0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94,
785e4064a0Sdhill 	0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
795e4064a0Sdhill 	0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68,
805e4064a0Sdhill 	0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
815e4064a0Sdhill };
825e4064a0Sdhill 
835e4064a0Sdhill static const uint8_t rijndael_inv_sbox[] = {
845e4064a0Sdhill 	0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38,
855e4064a0Sdhill 	0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
865e4064a0Sdhill 	0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87,
875e4064a0Sdhill 	0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
885e4064a0Sdhill 	0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D,
895e4064a0Sdhill 	0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
905e4064a0Sdhill 	0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2,
915e4064a0Sdhill 	0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
925e4064a0Sdhill 	0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16,
935e4064a0Sdhill 	0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
945e4064a0Sdhill 	0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA,
955e4064a0Sdhill 	0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
965e4064a0Sdhill 	0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A,
975e4064a0Sdhill 	0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
985e4064a0Sdhill 	0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02,
995e4064a0Sdhill 	0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
1005e4064a0Sdhill 	0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA,
1015e4064a0Sdhill 	0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
1025e4064a0Sdhill 	0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85,
1035e4064a0Sdhill 	0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
1045e4064a0Sdhill 	0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89,
1055e4064a0Sdhill 	0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
1065e4064a0Sdhill 	0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20,
1075e4064a0Sdhill 	0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
1085e4064a0Sdhill 	0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31,
1095e4064a0Sdhill 	0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
1105e4064a0Sdhill 	0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D,
1115e4064a0Sdhill 	0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
1125e4064a0Sdhill 	0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0,
1135e4064a0Sdhill 	0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
1145e4064a0Sdhill 	0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26,
1155e4064a0Sdhill 	0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
1165e4064a0Sdhill };
1175e4064a0Sdhill 
1185e4064a0Sdhill static inline uint8_t
xtime(uint8_t b)1195e4064a0Sdhill xtime(uint8_t b)
1205e4064a0Sdhill {
1215e4064a0Sdhill 	return (b & 0x80) ? ((b << 1) ^ 0x1b) : (b << 1);
1225e4064a0Sdhill }
1235e4064a0Sdhill 
1245e4064a0Sdhill #define NUMBER_OF_ROUNDS 10
1255e4064a0Sdhill 
1265e4064a0Sdhill void
yubikey_aes_decrypt(uint8_t * state,const uint8_t * key)1275e4064a0Sdhill yubikey_aes_decrypt(uint8_t *state, const uint8_t *key)
1285e4064a0Sdhill {
1295e4064a0Sdhill 	uint8_t i, j, round_key[0x10];
1305e4064a0Sdhill 	uint8_t a02x, a13x;
1315e4064a0Sdhill 	uint8_t a02xx, a13xx;
1325e4064a0Sdhill 	uint8_t k1, k2;
1335e4064a0Sdhill 
1345e4064a0Sdhill 	memcpy(round_key, key, sizeof(round_key));
1355e4064a0Sdhill 	for (i = 0; i < NUMBER_OF_ROUNDS; i++) {
1365e4064a0Sdhill 		round_key[0] ^= RC[i];
1375e4064a0Sdhill 
1385e4064a0Sdhill 		round_key[0] ^= rijndael_sbox[round_key[13]];
1395e4064a0Sdhill 		round_key[1] ^= rijndael_sbox[round_key[14]];
1405e4064a0Sdhill 		round_key[2] ^= rijndael_sbox[round_key[15]];
1415e4064a0Sdhill 		round_key[3] ^= rijndael_sbox[round_key[12]];
1425e4064a0Sdhill 
1435e4064a0Sdhill 		for (j = 4; j < 16; j++)
1445e4064a0Sdhill 			round_key[j] ^= round_key[j - 4];
1455e4064a0Sdhill 	}
1465e4064a0Sdhill 	for (i = 0; i < 0x10; i++)
1475e4064a0Sdhill 		state[i] ^= round_key[i];
1485e4064a0Sdhill 
1495e4064a0Sdhill 	for (i = 1; i <= NUMBER_OF_ROUNDS; i++) {
1505e4064a0Sdhill 		/* inv_byte_sub_shift_row(); */
1515e4064a0Sdhill 
1525e4064a0Sdhill 		/* First row: 0 shift, 0 4 8 12 */
1535e4064a0Sdhill 		state[0] = rijndael_inv_sbox[state[0]];
1545e4064a0Sdhill 		state[4] = rijndael_inv_sbox[state[4]];
1555e4064a0Sdhill 		state[8] = rijndael_inv_sbox[state[8]];
1565e4064a0Sdhill 		state[12] = rijndael_inv_sbox[state[12]];
1575e4064a0Sdhill 
1585e4064a0Sdhill 		/* Second row: -1 shift, 1 5 9 13 */
1595e4064a0Sdhill 		j = state[13];
1605e4064a0Sdhill 		state[13] = rijndael_inv_sbox[state[9]];
1615e4064a0Sdhill 		state[9] = rijndael_inv_sbox[state[5]];
1625e4064a0Sdhill 		state[5] = rijndael_inv_sbox[state[1]];
1635e4064a0Sdhill 		state[1] = rijndael_inv_sbox[j];
1645e4064a0Sdhill 
1655e4064a0Sdhill 		/* Third row: -2 shift, 2 6 10 14 */
1665e4064a0Sdhill 		j = state[2];
1675e4064a0Sdhill 		state[2] = rijndael_inv_sbox[state[10]];
1685e4064a0Sdhill 		state[10] = rijndael_inv_sbox[j];
1695e4064a0Sdhill 		j = state[6];
1705e4064a0Sdhill 		state[6] = rijndael_inv_sbox[state[14]];
1715e4064a0Sdhill 		state[14] = rijndael_inv_sbox[j];
1725e4064a0Sdhill 
1735e4064a0Sdhill 		/* Fourth row: -3 shift, 3 7 11 15 */
1745e4064a0Sdhill 		j = state[3];
1755e4064a0Sdhill 		state[3] = rijndael_inv_sbox[state[7]];
1765e4064a0Sdhill 		state[7] = rijndael_inv_sbox[state[11]];
1775e4064a0Sdhill 		state[11] = rijndael_inv_sbox[state[15]];
1785e4064a0Sdhill 		state[15] = rijndael_inv_sbox[j];
1795e4064a0Sdhill 
1805e4064a0Sdhill 		/* get_inv_round_key(i); */
1815e4064a0Sdhill 
1825e4064a0Sdhill 		for (j = 15; j > 3; j--)
1835e4064a0Sdhill 			round_key[j] ^= round_key[j - 4];
1845e4064a0Sdhill 
1855e4064a0Sdhill 		round_key[0] ^= (RC[NUMBER_OF_ROUNDS - i] ^
1865e4064a0Sdhill 		    rijndael_sbox[round_key[13]]);
1875e4064a0Sdhill 
1885e4064a0Sdhill 		round_key[1] ^= rijndael_sbox[round_key[14]];
1895e4064a0Sdhill 		round_key[2] ^= rijndael_sbox[round_key[15]];
1905e4064a0Sdhill 		round_key[3] ^= rijndael_sbox[round_key[12]];
1915e4064a0Sdhill 
1925e4064a0Sdhill 		for (j = 0; j < 16; j++)
1935e4064a0Sdhill 			state[j] ^= round_key[j];
1945e4064a0Sdhill 		if (i != NUMBER_OF_ROUNDS) {
1955e4064a0Sdhill 			/* inv_mix_column(); */
1965e4064a0Sdhill 
1975e4064a0Sdhill 			for (j = 0; j < 16; j += 4) {
1985e4064a0Sdhill 				k1 = state[j] ^ state[j + 2];
1995e4064a0Sdhill 				a02x = xtime(k1);
2005e4064a0Sdhill 				k2 = state[j + 1] ^ state[j + 3];
2015e4064a0Sdhill 				a13x = xtime(k2);
2025e4064a0Sdhill 
2035e4064a0Sdhill 				k1 ^= (k2 ^ xtime(state[j + 1] ^ state[j + 2]));
2045e4064a0Sdhill 				k2 = k1;
2055e4064a0Sdhill 
2065e4064a0Sdhill 				a02xx = xtime(a02x);
2075e4064a0Sdhill 				a13xx = xtime(a13x);
2085e4064a0Sdhill 
2095e4064a0Sdhill 
2105e4064a0Sdhill 				k1 ^= (xtime(a02xx ^ a13xx) ^ a02xx);
2115e4064a0Sdhill 				k2 ^= (xtime(a02xx ^ a13xx) ^ a13xx);
2125e4064a0Sdhill 
2135e4064a0Sdhill 				state[j] ^= (k1 ^ a02x);
2145e4064a0Sdhill 				state[j + 1] ^= k2;
2155e4064a0Sdhill 				state[j + 2] ^= (k1 ^ a13x);
2165e4064a0Sdhill 				state[j + 3] ^= (k2 ^ a02x ^ a13x);
2175e4064a0Sdhill 			}
2185e4064a0Sdhill 		}
2195e4064a0Sdhill 
2205e4064a0Sdhill 	}
2215e4064a0Sdhill }
2225e4064a0Sdhill 
2235e4064a0Sdhill uint16_t
yubikey_crc16(const uint8_t * buf,size_t buf_size)2245e4064a0Sdhill yubikey_crc16(const uint8_t *buf, size_t buf_size)
2255e4064a0Sdhill {
2265e4064a0Sdhill 	uint16_t m_crc = 0xffff;
2275e4064a0Sdhill 
2285e4064a0Sdhill 	while (buf_size--) {
2295e4064a0Sdhill 		int i, j;
2305e4064a0Sdhill 
2315e4064a0Sdhill 		m_crc ^= (uint8_t)*buf++ & 0xFF;
2325e4064a0Sdhill 		for (i = 0; i < 8; i++) {
2335e4064a0Sdhill 			j = m_crc & 1;
2345e4064a0Sdhill 			m_crc >>= 1;
2355e4064a0Sdhill 			if (j)
2365e4064a0Sdhill 				m_crc ^= 0x8408;
2375e4064a0Sdhill 		}
2385e4064a0Sdhill 	}
2395e4064a0Sdhill 	return m_crc;
2405e4064a0Sdhill }
2415e4064a0Sdhill 
2425e4064a0Sdhill static const char hex_trans[] = "0123456789abcdef";
2435e4064a0Sdhill 
2445e4064a0Sdhill void
yubikey_hex_encode(char * dst,const char * src,size_t srcSize)2455e4064a0Sdhill yubikey_hex_encode(char *dst, const char *src, size_t srcSize)
2465e4064a0Sdhill {
2475e4064a0Sdhill 	while (srcSize--) {
2485e4064a0Sdhill 		*dst++ = hex_trans[(*src >> 4) & 0xf];
2495e4064a0Sdhill 		*dst++ = hex_trans[*src++ & 0xf];
2505e4064a0Sdhill 	}
2515e4064a0Sdhill 	*dst = '\0';
2525e4064a0Sdhill }
2535e4064a0Sdhill 
2545e4064a0Sdhill void
yubikey_hex_decode(char * dst,const char * src,size_t dstSize)2555e4064a0Sdhill yubikey_hex_decode(char *dst, const char *src, size_t dstSize)
2565e4064a0Sdhill {
2575e4064a0Sdhill 	char b;
2585e4064a0Sdhill 	int flag = 0;
2595e4064a0Sdhill 	char *p1;
2605e4064a0Sdhill 
2615e4064a0Sdhill 	for (; *src && dstSize > 0; src++) {
2626e526c06Shalex 		p1 = strchr(hex_trans, tolower((unsigned char)*src));
2636e526c06Shalex 		if (p1 == NULL)
2645e4064a0Sdhill 			b = 0;
2655e4064a0Sdhill 		else
2665e4064a0Sdhill 			b = (char)(p1 - hex_trans);
2675e4064a0Sdhill 		if ((flag = !flag))
2685e4064a0Sdhill 			*dst = b;
2695e4064a0Sdhill 		else {
2705e4064a0Sdhill 			*dst = (*dst << 4) | b;
2715e4064a0Sdhill 			dst++;
2725e4064a0Sdhill 			dstSize--;
2735e4064a0Sdhill 		}
2745e4064a0Sdhill 	}
2755e4064a0Sdhill 	while (dstSize--)
2765e4064a0Sdhill 		*dst++ = 0;
2775e4064a0Sdhill }
2785e4064a0Sdhill 
2795e4064a0Sdhill static const char modhex_trans[] = "cbdefghijklnrtuv";
2805e4064a0Sdhill 
2815e4064a0Sdhill void
yubikey_modhex_decode(char * dst,const char * src,size_t dstSize)2825e4064a0Sdhill yubikey_modhex_decode(char *dst, const char *src, size_t dstSize)
2835e4064a0Sdhill {
2845e4064a0Sdhill 	char b;
2855e4064a0Sdhill 	int flag = 0;
2865e4064a0Sdhill 	char *p1;
2875e4064a0Sdhill 
2885e4064a0Sdhill 	for (; *src && dstSize > 0; src++) {
2896e526c06Shalex 		p1 = strchr(modhex_trans, tolower((unsigned char)*src));
2906e526c06Shalex 		if (p1 == NULL)
2915e4064a0Sdhill 			b = 0;
2925e4064a0Sdhill 		else
2935e4064a0Sdhill 			b = (char)(p1 - modhex_trans);
2945e4064a0Sdhill 
2955e4064a0Sdhill 		if ((flag = !flag))
2965e4064a0Sdhill 			*dst = b;
2975e4064a0Sdhill 		else {
2985e4064a0Sdhill 			*dst = (*dst << 4) | b;
2995e4064a0Sdhill 			dst++;
3005e4064a0Sdhill 			dstSize--;
3015e4064a0Sdhill 		}
3025e4064a0Sdhill 	}
3035e4064a0Sdhill 	while (dstSize--)
3045e4064a0Sdhill 		*dst++ = 0;
3055e4064a0Sdhill }
3065e4064a0Sdhill 
3073ef0233cSmcbride uint8_t
yubikey_keymap_decode(wchar_t * wpassword,char * token,int index)3083ef0233cSmcbride yubikey_keymap_decode(wchar_t *wpassword, char *token, int index)
3095e4064a0Sdhill {
3103ef0233cSmcbride 	int c, j, found;
3113ef0233cSmcbride 	for (j=0; j<YUBIKEY_TOKEN_SIZE; j++) {
3123ef0233cSmcbride 		found = 0;
3133ef0233cSmcbride 		for (c=0; c<16; c++) {
3143ef0233cSmcbride 			if (wpassword[j] == keymaps[index][c]) {
3153ef0233cSmcbride 				token[j] = modhex_trans[c];
3163ef0233cSmcbride 				found++;
3173ef0233cSmcbride 				break;
3183ef0233cSmcbride 			}
3193ef0233cSmcbride 		}
3203ef0233cSmcbride 		if (found == 0)
3213ef0233cSmcbride 			return 1;
3223ef0233cSmcbride 	}
3233ef0233cSmcbride 	return 0;
3243ef0233cSmcbride }
3253ef0233cSmcbride 
3263ef0233cSmcbride int
yubikey_parse(const uint8_t * password,const uint8_t key[YUBIKEY_KEY_SIZE],yubikey_token_t out,int index)3273ef0233cSmcbride yubikey_parse(const uint8_t *password, const uint8_t key[YUBIKEY_KEY_SIZE],
3283ef0233cSmcbride     yubikey_token_t out, int index)
3293ef0233cSmcbride {
3303ef0233cSmcbride 	wchar_t *wpassword, *pp;
3313ef0233cSmcbride 	char token[YUBIKEY_TOKEN_SIZE + 1], *lc_ctype;
332*6cc4e57dSanton 	size_t len;
333*6cc4e57dSanton 	int rc = 0;
3343ef0233cSmcbride 
3353ef0233cSmcbride 	if (index < 0 || index >= YUBIKEY_KEYMAP_COUNT)
3363ef0233cSmcbride 		return -1;
3373ef0233cSmcbride 
3383ef0233cSmcbride 	len = strlen(password);
33900f782e3Sderaadt 	pp = wpassword = reallocarray(NULL, len + 1, sizeof(wchar_t));
3403ef0233cSmcbride 	if (pp == NULL)
3413ef0233cSmcbride 		return ENOMEM;
3423ef0233cSmcbride 
3435e4064a0Sdhill 	memset(out, 0, sizeof(*out));
3443ef0233cSmcbride 	memset(token, 0, YUBIKEY_TOKEN_SIZE + 1);
3453ef0233cSmcbride 
3463ef0233cSmcbride 	lc_ctype = getenv("LC_CTYPE");
3473ef0233cSmcbride 	setlocale(LC_CTYPE, lc_ctype ? lc_ctype : "C.UTF-8");
3483ef0233cSmcbride 	len = mbstowcs(wpassword, password, len);
349*6cc4e57dSanton 	if (len == (size_t)-1) {
350*6cc4e57dSanton 		rc = errno;
351*6cc4e57dSanton 		goto ret;
3523ef0233cSmcbride 	}
3533ef0233cSmcbride 	setlocale(LC_CTYPE, "C");
3543ef0233cSmcbride 
3553ef0233cSmcbride 	if (len > YUBIKEY_TOKEN_SIZE)
3563ef0233cSmcbride 		pp = pp + len - YUBIKEY_TOKEN_SIZE;
357*6cc4e57dSanton 	if (len < YUBIKEY_TOKEN_SIZE) {
358*6cc4e57dSanton 		rc = EMSGSIZE;
359*6cc4e57dSanton 		goto ret;
360*6cc4e57dSanton 	}
3613ef0233cSmcbride 
362*6cc4e57dSanton 	if (yubikey_keymap_decode(pp, token, index)) {
363*6cc4e57dSanton 		rc = EINVAL;
364*6cc4e57dSanton 		goto ret;
365*6cc4e57dSanton 	}
3663ef0233cSmcbride 	yubikey_modhex_decode((void *)out, token, sizeof(*out));
3675e4064a0Sdhill 	yubikey_aes_decrypt((void *)out, key);
368*6cc4e57dSanton 
369*6cc4e57dSanton ret:
370*6cc4e57dSanton 	freezero(wpassword, (len + 1) * sizeof(wchar_t));
371*6cc4e57dSanton 	return rc;
3725e4064a0Sdhill }
373