1 /* 2 * Crypto wrapper for internal crypto implementation 3 * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 * 9 * Alternatively, this software may be distributed under the terms of BSD 10 * license. 11 * 12 * See README and COPYING for more details. 13 */ 14 15 #include "includes.h" 16 17 #include "common.h" 18 #include "crypto.h" 19 #include "sha1_i.h" 20 #include "md5_i.h" 21 22 struct crypto_hash { 23 enum crypto_hash_alg alg; 24 union { 25 struct MD5Context md5; 26 struct SHA1Context sha1; 27 } u; 28 u8 key[64]; 29 size_t key_len; 30 }; 31 32 33 struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, 34 size_t key_len) 35 { 36 struct crypto_hash *ctx; 37 u8 k_pad[64]; 38 u8 tk[20]; 39 size_t i; 40 41 ctx = os_zalloc(sizeof(*ctx)); 42 if (ctx == NULL) 43 return NULL; 44 45 ctx->alg = alg; 46 47 switch (alg) { 48 case CRYPTO_HASH_ALG_MD5: 49 MD5Init(&ctx->u.md5); 50 break; 51 case CRYPTO_HASH_ALG_SHA1: 52 SHA1Init(&ctx->u.sha1); 53 break; 54 case CRYPTO_HASH_ALG_HMAC_MD5: 55 if (key_len > sizeof(k_pad)) { 56 MD5Init(&ctx->u.md5); 57 MD5Update(&ctx->u.md5, key, key_len); 58 MD5Final(tk, &ctx->u.md5); 59 key = tk; 60 key_len = 16; 61 } 62 os_memcpy(ctx->key, key, key_len); 63 ctx->key_len = key_len; 64 65 os_memcpy(k_pad, key, key_len); 66 if (key_len < sizeof(k_pad)) 67 os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len); 68 for (i = 0; i < sizeof(k_pad); i++) 69 k_pad[i] ^= 0x36; 70 MD5Init(&ctx->u.md5); 71 MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad)); 72 break; 73 case CRYPTO_HASH_ALG_HMAC_SHA1: 74 if (key_len > sizeof(k_pad)) { 75 SHA1Init(&ctx->u.sha1); 76 SHA1Update(&ctx->u.sha1, key, key_len); 77 SHA1Final(tk, &ctx->u.sha1); 78 key = tk; 79 key_len = 20; 80 } 81 os_memcpy(ctx->key, key, key_len); 82 ctx->key_len = key_len; 83 84 os_memcpy(k_pad, key, key_len); 85 if (key_len < sizeof(k_pad)) 86 os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len); 87 for (i = 0; i < sizeof(k_pad); i++) 88 k_pad[i] ^= 0x36; 89 SHA1Init(&ctx->u.sha1); 90 SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad)); 91 break; 92 default: 93 os_free(ctx); 94 return NULL; 95 } 96 97 return ctx; 98 } 99 100 101 void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len) 102 { 103 if (ctx == NULL) 104 return; 105 106 switch (ctx->alg) { 107 case CRYPTO_HASH_ALG_MD5: 108 case CRYPTO_HASH_ALG_HMAC_MD5: 109 MD5Update(&ctx->u.md5, data, len); 110 break; 111 case CRYPTO_HASH_ALG_SHA1: 112 case CRYPTO_HASH_ALG_HMAC_SHA1: 113 SHA1Update(&ctx->u.sha1, data, len); 114 break; 115 } 116 } 117 118 119 int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len) 120 { 121 u8 k_pad[64]; 122 size_t i; 123 124 if (ctx == NULL) 125 return -2; 126 127 if (mac == NULL || len == NULL) { 128 os_free(ctx); 129 return 0; 130 } 131 132 switch (ctx->alg) { 133 case CRYPTO_HASH_ALG_MD5: 134 if (*len < 16) { 135 *len = 16; 136 os_free(ctx); 137 return -1; 138 } 139 *len = 16; 140 MD5Final(mac, &ctx->u.md5); 141 break; 142 case CRYPTO_HASH_ALG_SHA1: 143 if (*len < 20) { 144 *len = 20; 145 os_free(ctx); 146 return -1; 147 } 148 *len = 20; 149 SHA1Final(mac, &ctx->u.sha1); 150 break; 151 case CRYPTO_HASH_ALG_HMAC_MD5: 152 if (*len < 16) { 153 *len = 16; 154 os_free(ctx); 155 return -1; 156 } 157 *len = 16; 158 159 MD5Final(mac, &ctx->u.md5); 160 161 os_memcpy(k_pad, ctx->key, ctx->key_len); 162 os_memset(k_pad + ctx->key_len, 0, 163 sizeof(k_pad) - ctx->key_len); 164 for (i = 0; i < sizeof(k_pad); i++) 165 k_pad[i] ^= 0x5c; 166 MD5Init(&ctx->u.md5); 167 MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad)); 168 MD5Update(&ctx->u.md5, mac, 16); 169 MD5Final(mac, &ctx->u.md5); 170 break; 171 case CRYPTO_HASH_ALG_HMAC_SHA1: 172 if (*len < 20) { 173 *len = 20; 174 os_free(ctx); 175 return -1; 176 } 177 *len = 20; 178 179 SHA1Final(mac, &ctx->u.sha1); 180 181 os_memcpy(k_pad, ctx->key, ctx->key_len); 182 os_memset(k_pad + ctx->key_len, 0, 183 sizeof(k_pad) - ctx->key_len); 184 for (i = 0; i < sizeof(k_pad); i++) 185 k_pad[i] ^= 0x5c; 186 SHA1Init(&ctx->u.sha1); 187 SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad)); 188 SHA1Update(&ctx->u.sha1, mac, 20); 189 SHA1Final(mac, &ctx->u.sha1); 190 break; 191 } 192 193 os_free(ctx); 194 195 return 0; 196 } 197 198 199 int crypto_global_init(void) 200 { 201 return 0; 202 } 203 204 205 void crypto_global_deinit(void) 206 { 207 } 208