yubikey.c revision 1.3
1/* $OpenBSD: yubikey.c,v 1.3 2012/11/23 23:53:54 halex 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 37#include "yubikey.h" 38 39static const uint8_t RC[] = { 40 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36 41}; 42 43static const uint8_t rijndael_sbox[] = { 44 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 45 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 46 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 47 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 48 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 49 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 50 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 51 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, 52 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 53 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 54 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 55 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 56 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 57 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, 58 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 59 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 60 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 61 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, 62 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 63 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, 64 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 65 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 66 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 67 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, 68 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 69 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 70 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 71 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 72 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 73 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, 74 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 75 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 76}; 77 78static const uint8_t rijndael_inv_sbox[] = { 79 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 80 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, 81 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 82 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, 83 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 84 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, 85 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 86 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, 87 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 88 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, 89 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 90 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, 91 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 92 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, 93 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 94 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, 95 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 96 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, 97 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 98 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, 99 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 100 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, 101 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 102 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, 103 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 104 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, 105 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 106 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, 107 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 108 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, 109 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 110 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D 111}; 112 113static inline uint8_t 114xtime(uint8_t b) 115{ 116 return (b & 0x80) ? ((b << 1) ^ 0x1b) : (b << 1); 117} 118 119#define NUMBER_OF_ROUNDS 10 120 121void 122yubikey_aes_decrypt(uint8_t *state, const uint8_t *key) 123{ 124 uint8_t i, j, round_key[0x10]; 125 uint8_t a02x, a13x; 126 uint8_t a02xx, a13xx; 127 uint8_t k1, k2; 128 129 memcpy(round_key, key, sizeof(round_key)); 130 for (i = 0; i < NUMBER_OF_ROUNDS; i++) { 131 round_key[0] ^= RC[i]; 132 133 round_key[0] ^= rijndael_sbox[round_key[13]]; 134 round_key[1] ^= rijndael_sbox[round_key[14]]; 135 round_key[2] ^= rijndael_sbox[round_key[15]]; 136 round_key[3] ^= rijndael_sbox[round_key[12]]; 137 138 for (j = 4; j < 16; j++) 139 round_key[j] ^= round_key[j - 4]; 140 } 141 for (i = 0; i < 0x10; i++) 142 state[i] ^= round_key[i]; 143 144 for (i = 1; i <= NUMBER_OF_ROUNDS; i++) { 145 /* inv_byte_sub_shift_row(); */ 146 147 /* First row: 0 shift, 0 4 8 12 */ 148 state[0] = rijndael_inv_sbox[state[0]]; 149 state[4] = rijndael_inv_sbox[state[4]]; 150 state[8] = rijndael_inv_sbox[state[8]]; 151 state[12] = rijndael_inv_sbox[state[12]]; 152 153 /* Second row: -1 shift, 1 5 9 13 */ 154 j = state[13]; 155 state[13] = rijndael_inv_sbox[state[9]]; 156 state[9] = rijndael_inv_sbox[state[5]]; 157 state[5] = rijndael_inv_sbox[state[1]]; 158 state[1] = rijndael_inv_sbox[j]; 159 160 /* Third row: -2 shift, 2 6 10 14 */ 161 j = state[2]; 162 state[2] = rijndael_inv_sbox[state[10]]; 163 state[10] = rijndael_inv_sbox[j]; 164 j = state[6]; 165 state[6] = rijndael_inv_sbox[state[14]]; 166 state[14] = rijndael_inv_sbox[j]; 167 168 /* Fourth row: -3 shift, 3 7 11 15 */ 169 j = state[3]; 170 state[3] = rijndael_inv_sbox[state[7]]; 171 state[7] = rijndael_inv_sbox[state[11]]; 172 state[11] = rijndael_inv_sbox[state[15]]; 173 state[15] = rijndael_inv_sbox[j]; 174 175 /* get_inv_round_key(i); */ 176 177 for (j = 15; j > 3; j--) 178 round_key[j] ^= round_key[j - 4]; 179 180 round_key[0] ^= (RC[NUMBER_OF_ROUNDS - i] ^ 181 rijndael_sbox[round_key[13]]); 182 183 round_key[1] ^= rijndael_sbox[round_key[14]]; 184 round_key[2] ^= rijndael_sbox[round_key[15]]; 185 round_key[3] ^= rijndael_sbox[round_key[12]]; 186 187 for (j = 0; j < 16; j++) 188 state[j] ^= round_key[j]; 189 if (i != NUMBER_OF_ROUNDS) { 190 /* inv_mix_column(); */ 191 192 for (j = 0; j < 16; j += 4) { 193 k1 = state[j] ^ state[j + 2]; 194 a02x = xtime(k1); 195 k2 = state[j + 1] ^ state[j + 3]; 196 a13x = xtime(k2); 197 198 k1 ^= (k2 ^ xtime(state[j + 1] ^ state[j + 2])); 199 k2 = k1; 200 201 a02xx = xtime(a02x); 202 a13xx = xtime(a13x); 203 204 205 k1 ^= (xtime(a02xx ^ a13xx) ^ a02xx); 206 k2 ^= (xtime(a02xx ^ a13xx) ^ a13xx); 207 208 state[j] ^= (k1 ^ a02x); 209 state[j + 1] ^= k2; 210 state[j + 2] ^= (k1 ^ a13x); 211 state[j + 3] ^= (k2 ^ a02x ^ a13x); 212 } 213 } 214 215 } 216} 217 218uint16_t 219yubikey_crc16(const uint8_t *buf, size_t buf_size) 220{ 221 uint16_t m_crc = 0xffff; 222 223 while (buf_size--) { 224 int i, j; 225 226 m_crc ^= (uint8_t)*buf++ & 0xFF; 227 for (i = 0; i < 8; i++) { 228 j = m_crc & 1; 229 m_crc >>= 1; 230 if (j) 231 m_crc ^= 0x8408; 232 } 233 } 234 return m_crc; 235} 236 237static const char hex_trans[] = "0123456789abcdef"; 238 239void 240yubikey_hex_encode(char *dst, const char *src, size_t srcSize) 241{ 242 while (srcSize--) { 243 *dst++ = hex_trans[(*src >> 4) & 0xf]; 244 *dst++ = hex_trans[*src++ & 0xf]; 245 } 246 *dst = '\0'; 247} 248 249void 250yubikey_hex_decode(char *dst, const char *src, size_t dstSize) 251{ 252 char b; 253 int flag = 0; 254 char *p1; 255 256 for (; *src && dstSize > 0; src++) { 257 p1 = strchr(hex_trans, tolower((unsigned char)*src)); 258 if (p1 == NULL) 259 b = 0; 260 else 261 b = (char)(p1 - hex_trans); 262 if ((flag = !flag)) 263 *dst = b; 264 else { 265 *dst = (*dst << 4) | b; 266 dst++; 267 dstSize--; 268 } 269 } 270 while (dstSize--) 271 *dst++ = 0; 272} 273 274static const char modhex_trans[] = "cbdefghijklnrtuv"; 275 276void 277yubikey_modhex_decode(char *dst, const char *src, size_t dstSize) 278{ 279 char b; 280 int flag = 0; 281 char *p1; 282 283 for (; *src && dstSize > 0; src++) { 284 p1 = strchr(modhex_trans, tolower((unsigned char)*src)); 285 if (p1 == NULL) 286 b = 0; 287 else 288 b = (char)(p1 - modhex_trans); 289 290 if ((flag = !flag)) 291 *dst = b; 292 else { 293 *dst = (*dst << 4) | b; 294 dst++; 295 dstSize--; 296 } 297 } 298 while (dstSize--) 299 *dst++ = 0; 300} 301 302void 303yubikey_parse(const uint8_t token[32], const uint8_t key[16], 304 yubikey_token_t out) 305{ 306 memset(out, 0, sizeof(*out)); 307 yubikey_modhex_decode((void *)out, (char *)token, sizeof(*out)); 308 yubikey_aes_decrypt((void *)out, key); 309} 310