yubikey.c revision 1.5
1/* $OpenBSD: yubikey.c,v 1.5 2014/10/08 04:47:20 deraadt Exp $ */
2
3/*
4 * Written by Simon Josefsson <simon@josefsson.org>.
5 * Copyright (c) 2006, 2007, 2008, 2009 Yubico AB
6 * Copyright (c) 2010 Daniel Hartmeier <daniel@benzedrine.cx>
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are
11 * met:
12 *
13 * * Redistributions of source code must retain the above copyright
14 *   notice, this list of conditions and the following disclaimer.
15 *
16 * * Redistributions in binary form must reproduce the above
17 *   copyright notice, this list of conditions and the following
18 *   disclaimer in the documentation and/or other materials provided
19 *   with the distribution.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 */
34
35#include <ctype.h>
36#include <stdlib.h>
37#include <wchar.h>
38#include <locale.h>
39#include <errno.h>
40
41#include "yubikey.h"
42#include "keymaps.h"
43
44static const uint8_t RC[] = {
45	0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36
46};
47
48static const uint8_t rijndael_sbox[] = {
49	0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5,
50	0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
51	0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0,
52	0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
53	0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC,
54	0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
55	0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A,
56	0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
57	0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0,
58	0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
59	0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B,
60	0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
61	0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85,
62	0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
63	0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5,
64	0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
65	0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17,
66	0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
67	0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88,
68	0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
69	0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C,
70	0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
71	0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9,
72	0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
73	0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6,
74	0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
75	0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E,
76	0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
77	0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94,
78	0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
79	0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68,
80	0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
81};
82
83static const uint8_t rijndael_inv_sbox[] = {
84	0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38,
85	0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
86	0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87,
87	0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
88	0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D,
89	0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
90	0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2,
91	0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
92	0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16,
93	0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
94	0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA,
95	0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
96	0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A,
97	0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
98	0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02,
99	0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
100	0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA,
101	0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
102	0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85,
103	0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
104	0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89,
105	0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
106	0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20,
107	0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
108	0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31,
109	0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
110	0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D,
111	0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
112	0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0,
113	0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
114	0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26,
115	0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
116};
117
118static inline uint8_t
119xtime(uint8_t b)
120{
121	return (b & 0x80) ? ((b << 1) ^ 0x1b) : (b << 1);
122}
123
124#define NUMBER_OF_ROUNDS 10
125
126void
127yubikey_aes_decrypt(uint8_t *state, const uint8_t *key)
128{
129	uint8_t i, j, round_key[0x10];
130	uint8_t a02x, a13x;
131	uint8_t a02xx, a13xx;
132	uint8_t k1, k2;
133
134	memcpy(round_key, key, sizeof(round_key));
135	for (i = 0; i < NUMBER_OF_ROUNDS; i++) {
136		round_key[0] ^= RC[i];
137
138		round_key[0] ^= rijndael_sbox[round_key[13]];
139		round_key[1] ^= rijndael_sbox[round_key[14]];
140		round_key[2] ^= rijndael_sbox[round_key[15]];
141		round_key[3] ^= rijndael_sbox[round_key[12]];
142
143		for (j = 4; j < 16; j++)
144			round_key[j] ^= round_key[j - 4];
145	}
146	for (i = 0; i < 0x10; i++)
147		state[i] ^= round_key[i];
148
149	for (i = 1; i <= NUMBER_OF_ROUNDS; i++) {
150		/* inv_byte_sub_shift_row(); */
151
152		/* First row: 0 shift, 0 4 8 12 */
153		state[0] = rijndael_inv_sbox[state[0]];
154		state[4] = rijndael_inv_sbox[state[4]];
155		state[8] = rijndael_inv_sbox[state[8]];
156		state[12] = rijndael_inv_sbox[state[12]];
157
158		/* Second row: -1 shift, 1 5 9 13 */
159		j = state[13];
160		state[13] = rijndael_inv_sbox[state[9]];
161		state[9] = rijndael_inv_sbox[state[5]];
162		state[5] = rijndael_inv_sbox[state[1]];
163		state[1] = rijndael_inv_sbox[j];
164
165		/* Third row: -2 shift, 2 6 10 14 */
166		j = state[2];
167		state[2] = rijndael_inv_sbox[state[10]];
168		state[10] = rijndael_inv_sbox[j];
169		j = state[6];
170		state[6] = rijndael_inv_sbox[state[14]];
171		state[14] = rijndael_inv_sbox[j];
172
173		/* Fourth row: -3 shift, 3 7 11 15 */
174		j = state[3];
175		state[3] = rijndael_inv_sbox[state[7]];
176		state[7] = rijndael_inv_sbox[state[11]];
177		state[11] = rijndael_inv_sbox[state[15]];
178		state[15] = rijndael_inv_sbox[j];
179
180		/* get_inv_round_key(i); */
181
182		for (j = 15; j > 3; j--)
183			round_key[j] ^= round_key[j - 4];
184
185		round_key[0] ^= (RC[NUMBER_OF_ROUNDS - i] ^
186		    rijndael_sbox[round_key[13]]);
187
188		round_key[1] ^= rijndael_sbox[round_key[14]];
189		round_key[2] ^= rijndael_sbox[round_key[15]];
190		round_key[3] ^= rijndael_sbox[round_key[12]];
191
192		for (j = 0; j < 16; j++)
193			state[j] ^= round_key[j];
194		if (i != NUMBER_OF_ROUNDS) {
195			/* inv_mix_column(); */
196
197			for (j = 0; j < 16; j += 4) {
198				k1 = state[j] ^ state[j + 2];
199				a02x = xtime(k1);
200				k2 = state[j + 1] ^ state[j + 3];
201				a13x = xtime(k2);
202
203				k1 ^= (k2 ^ xtime(state[j + 1] ^ state[j + 2]));
204				k2 = k1;
205
206				a02xx = xtime(a02x);
207				a13xx = xtime(a13x);
208
209
210				k1 ^= (xtime(a02xx ^ a13xx) ^ a02xx);
211				k2 ^= (xtime(a02xx ^ a13xx) ^ a13xx);
212
213				state[j] ^= (k1 ^ a02x);
214				state[j + 1] ^= k2;
215				state[j + 2] ^= (k1 ^ a13x);
216				state[j + 3] ^= (k2 ^ a02x ^ a13x);
217			}
218		}
219
220	}
221}
222
223uint16_t
224yubikey_crc16(const uint8_t *buf, size_t buf_size)
225{
226	uint16_t m_crc = 0xffff;
227
228	while (buf_size--) {
229		int i, j;
230
231		m_crc ^= (uint8_t)*buf++ & 0xFF;
232		for (i = 0; i < 8; i++) {
233			j = m_crc & 1;
234			m_crc >>= 1;
235			if (j)
236				m_crc ^= 0x8408;
237		}
238	}
239	return m_crc;
240}
241
242static const char hex_trans[] = "0123456789abcdef";
243
244void
245yubikey_hex_encode(char *dst, const char *src, size_t srcSize)
246{
247	while (srcSize--) {
248		*dst++ = hex_trans[(*src >> 4) & 0xf];
249		*dst++ = hex_trans[*src++ & 0xf];
250	}
251	*dst = '\0';
252}
253
254void
255yubikey_hex_decode(char *dst, const char *src, size_t dstSize)
256{
257	char b;
258	int flag = 0;
259	char *p1;
260
261	for (; *src && dstSize > 0; src++) {
262		p1 = strchr(hex_trans, tolower((unsigned char)*src));
263		if (p1 == NULL)
264			b = 0;
265		else
266			b = (char)(p1 - hex_trans);
267		if ((flag = !flag))
268			*dst = b;
269		else {
270			*dst = (*dst << 4) | b;
271			dst++;
272			dstSize--;
273		}
274	}
275	while (dstSize--)
276		*dst++ = 0;
277}
278
279static const char modhex_trans[] = "cbdefghijklnrtuv";
280
281void
282yubikey_modhex_decode(char *dst, const char *src, size_t dstSize)
283{
284	char b;
285	int flag = 0;
286	char *p1;
287
288	for (; *src && dstSize > 0; src++) {
289		p1 = strchr(modhex_trans, tolower((unsigned char)*src));
290		if (p1 == NULL)
291			b = 0;
292		else
293			b = (char)(p1 - modhex_trans);
294
295		if ((flag = !flag))
296			*dst = b;
297		else {
298			*dst = (*dst << 4) | b;
299			dst++;
300			dstSize--;
301		}
302	}
303	while (dstSize--)
304		*dst++ = 0;
305}
306
307uint8_t
308yubikey_keymap_decode(wchar_t *wpassword, char *token, int index)
309{
310	int c, j, found;
311	for (j=0; j<YUBIKEY_TOKEN_SIZE; j++) {
312		found = 0;
313		for (c=0; c<16; c++) {
314			if (wpassword[j] == keymaps[index][c]) {
315				token[j] = modhex_trans[c];
316				found++;
317				break;
318			}
319		}
320		if (found == 0)
321			return 1;
322	}
323	return 0;
324}
325
326int
327yubikey_parse(const uint8_t *password, const uint8_t key[YUBIKEY_KEY_SIZE],
328    yubikey_token_t out, int index)
329{
330	wchar_t *wpassword, *pp;
331	char token[YUBIKEY_TOKEN_SIZE + 1], *lc_ctype;
332	int len;
333
334	if (index < 0 || index >= YUBIKEY_KEYMAP_COUNT)
335		return -1;
336
337	len = strlen(password);
338	pp = wpassword = reallocarray(NULL, len + 1, sizeof(wchar_t));
339	if (pp == NULL)
340		return ENOMEM;
341
342	memset(out, 0, sizeof(*out));
343	memset(token, 0, YUBIKEY_TOKEN_SIZE + 1);
344
345	lc_ctype = getenv("LC_CTYPE");
346	setlocale(LC_CTYPE, lc_ctype ? lc_ctype : "C.UTF-8");
347	len = mbstowcs(wpassword, password, len);
348	if (len < 0) {
349		return errno;
350	}
351	setlocale(LC_CTYPE, "C");
352
353	if (len > YUBIKEY_TOKEN_SIZE)
354		pp = pp + len - YUBIKEY_TOKEN_SIZE;
355	if (len < YUBIKEY_TOKEN_SIZE)
356		return EMSGSIZE;
357
358	if (yubikey_keymap_decode(pp, token, index))
359		return EINVAL;
360	yubikey_modhex_decode((void *)out, token, sizeof(*out));
361	yubikey_aes_decrypt((void *)out, key);
362	return 0;
363}
364