1 /* $OpenBSD: yubikey.c,v 1.6 2017/09/16 08:07:15 anton 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
44 static const uint8_t RC[] = {
45 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36
46 };
47
48 static 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
83 static 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
118 static inline uint8_t
xtime(uint8_t b)119 xtime(uint8_t b)
120 {
121 return (b & 0x80) ? ((b << 1) ^ 0x1b) : (b << 1);
122 }
123
124 #define NUMBER_OF_ROUNDS 10
125
126 void
yubikey_aes_decrypt(uint8_t * state,const uint8_t * key)127 yubikey_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
223 uint16_t
yubikey_crc16(const uint8_t * buf,size_t buf_size)224 yubikey_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
242 static const char hex_trans[] = "0123456789abcdef";
243
244 void
yubikey_hex_encode(char * dst,const char * src,size_t srcSize)245 yubikey_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
254 void
yubikey_hex_decode(char * dst,const char * src,size_t dstSize)255 yubikey_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
279 static const char modhex_trans[] = "cbdefghijklnrtuv";
280
281 void
yubikey_modhex_decode(char * dst,const char * src,size_t dstSize)282 yubikey_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
307 uint8_t
yubikey_keymap_decode(wchar_t * wpassword,char * token,int index)308 yubikey_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
326 int
yubikey_parse(const uint8_t * password,const uint8_t key[YUBIKEY_KEY_SIZE],yubikey_token_t out,int index)327 yubikey_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 size_t len;
333 int rc = 0;
334
335 if (index < 0 || index >= YUBIKEY_KEYMAP_COUNT)
336 return -1;
337
338 len = strlen(password);
339 pp = wpassword = reallocarray(NULL, len + 1, sizeof(wchar_t));
340 if (pp == NULL)
341 return ENOMEM;
342
343 memset(out, 0, sizeof(*out));
344 memset(token, 0, YUBIKEY_TOKEN_SIZE + 1);
345
346 lc_ctype = getenv("LC_CTYPE");
347 setlocale(LC_CTYPE, lc_ctype ? lc_ctype : "C.UTF-8");
348 len = mbstowcs(wpassword, password, len);
349 if (len == (size_t)-1) {
350 rc = errno;
351 goto ret;
352 }
353 setlocale(LC_CTYPE, "C");
354
355 if (len > YUBIKEY_TOKEN_SIZE)
356 pp = pp + len - YUBIKEY_TOKEN_SIZE;
357 if (len < YUBIKEY_TOKEN_SIZE) {
358 rc = EMSGSIZE;
359 goto ret;
360 }
361
362 if (yubikey_keymap_decode(pp, token, index)) {
363 rc = EINVAL;
364 goto ret;
365 }
366 yubikey_modhex_decode((void *)out, token, sizeof(*out));
367 yubikey_aes_decrypt((void *)out, key);
368
369 ret:
370 freezero(wpassword, (len + 1) * sizeof(wchar_t));
371 return rc;
372 }
373