14126Szf162725 /*
2*11034SQuaker.Fang@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
34126Szf162725 * Use is subject to license terms.
44126Szf162725 */
54126Szf162725
64126Szf162725 /*
74126Szf162725 * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
84126Szf162725 * Sun elects to license this software under the BSD license.
94126Szf162725 * See README for more details.
104126Szf162725 */
114126Szf162725
124126Szf162725 #include <stdio.h>
134126Szf162725 #include <stdlib.h>
144126Szf162725 #include <string.h>
154126Szf162725 #include <strings.h>
164126Szf162725 #include <sys/types.h>
174126Szf162725
184126Szf162725 #include <openssl/aes.h>
194126Szf162725 #include <openssl/hmac.h>
204126Szf162725 #include <openssl/rc4.h>
214126Szf162725
224126Szf162725 #include "wpa_enc.h"
234126Szf162725
244126Szf162725 /*
254126Szf162725 * @kek: key encryption key (KEK)
264126Szf162725 * @n: length of the wrapped key in 64-bit units; e.g., 2 = 128-bit = 16 bytes
274126Szf162725 * @plain: plaintext key to be wrapped, n * 64 bit
284126Szf162725 * @cipher: wrapped key, (n + 1) * 64 bit
294126Szf162725 */
304126Szf162725 void
aes_wrap(uint8_t * kek,int n,uint8_t * plain,uint8_t * cipher)314126Szf162725 aes_wrap(uint8_t *kek, int n, uint8_t *plain, uint8_t *cipher)
324126Szf162725 {
334126Szf162725 uint8_t *a, *r, b[16];
344126Szf162725 int i, j;
354126Szf162725 AES_KEY key;
364126Szf162725
374126Szf162725 a = cipher;
384126Szf162725 r = cipher + 8;
394126Szf162725
404126Szf162725 /* 1) Initialize variables. */
414126Szf162725 (void) memset(a, 0xa6, 8);
424126Szf162725 (void) memcpy(r, plain, 8 * n);
434126Szf162725
44*11034SQuaker.Fang@Sun.COM (void) AES_set_encrypt_key(kek, 128, &key);
454126Szf162725
464126Szf162725 /*
474126Szf162725 * 2) Calculate intermediate values.
484126Szf162725 * For j = 0 to 5
494126Szf162725 * For i=1 to n
504126Szf162725 * B = AES(K, A | R[i])
514126Szf162725 * A = MSB(64, B) ^ t where t = (n*j)+i
524126Szf162725 * R[i] = LSB(64, B)
534126Szf162725 */
544126Szf162725 for (j = 0; j <= 5; j++) {
554126Szf162725 r = cipher + 8;
564126Szf162725 for (i = 1; i <= n; i++) {
574126Szf162725 (void) memcpy(b, a, 8);
584126Szf162725 (void) memcpy(b + 8, r, 8);
594126Szf162725 AES_encrypt(b, b, &key);
604126Szf162725 (void) memcpy(a, b, 8);
614126Szf162725 a[7] ^= n * j + i;
624126Szf162725 (void) memcpy(r, b + 8, 8);
634126Szf162725 r += 8;
644126Szf162725 }
654126Szf162725 }
664126Szf162725
674126Szf162725 /*
684126Szf162725 * 3) Output the results.
694126Szf162725 *
704126Szf162725 * These are already in @cipher due to the location of temporary
714126Szf162725 * variables.
724126Szf162725 */
734126Szf162725 }
744126Szf162725
754126Szf162725 /*
764126Szf162725 * @kek: key encryption key (KEK)
774126Szf162725 * @n: length of the wrapped key in 64-bit units; e.g., 2 = 128-bit = 16 bytes
784126Szf162725 * @cipher: wrapped key to be unwrapped, (n + 1) * 64 bit
794126Szf162725 * @plain: plaintext key, n * 64 bit
804126Szf162725 */
814126Szf162725 int
aes_unwrap(uint8_t * kek,int n,uint8_t * cipher,uint8_t * plain)824126Szf162725 aes_unwrap(uint8_t *kek, int n, uint8_t *cipher, uint8_t *plain)
834126Szf162725 {
844126Szf162725 uint8_t a[8], *r, b[16];
854126Szf162725 int i, j;
864126Szf162725 AES_KEY key;
874126Szf162725
884126Szf162725 /* 1) Initialize variables. */
894126Szf162725 (void) memcpy(a, cipher, 8);
904126Szf162725 r = plain;
914126Szf162725 (void) memcpy(r, cipher + 8, 8 * n);
924126Szf162725
93*11034SQuaker.Fang@Sun.COM (void) AES_set_decrypt_key(kek, 128, &key);
944126Szf162725
954126Szf162725 /*
964126Szf162725 * 2) Compute intermediate values.
974126Szf162725 * For j = 5 to 0
984126Szf162725 * For i = n to 1
994126Szf162725 * B = AES-1(K, (A ^ t) | R[i]) where t = n*j+i
1004126Szf162725 * A = MSB(64, B)
1014126Szf162725 * R[i] = LSB(64, B)
1024126Szf162725 */
1034126Szf162725 for (j = 5; j >= 0; j--) {
1044126Szf162725 r = plain + (n - 1) * 8;
1054126Szf162725 for (i = n; i >= 1; i--) {
1064126Szf162725 (void) memcpy(b, a, 8);
1074126Szf162725 b[7] ^= n * j + i;
1084126Szf162725
1094126Szf162725 (void) memcpy(b + 8, r, 8);
1104126Szf162725 AES_decrypt(b, b, &key);
1114126Szf162725 (void) memcpy(a, b, 8);
1124126Szf162725 (void) memcpy(r, b + 8, 8);
1134126Szf162725 r -= 8;
1144126Szf162725 }
1154126Szf162725 }
1164126Szf162725
1174126Szf162725 /*
1184126Szf162725 * 3) Output results.
1194126Szf162725 *
1204126Szf162725 * These are already in @plain due to the location of temporary
1214126Szf162725 * variables. Just verify that the IV matches with the expected value.
1224126Szf162725 */
1234126Szf162725 for (i = 0; i < 8; i++) {
1244126Szf162725 if (a[i] != 0xa6) {
1254126Szf162725 return (-1);
1264126Szf162725 }
1274126Szf162725 }
1284126Szf162725
1294126Szf162725 return (0);
1304126Szf162725 }
1314126Szf162725
1324126Szf162725 /* RFC 2104 */
1334126Szf162725 void
hmac_sha1(unsigned char * key,unsigned int key_len,unsigned char * data,unsigned int data_len,unsigned char * mac)1344126Szf162725 hmac_sha1(unsigned char *key, unsigned int key_len,
1354126Szf162725 unsigned char *data, unsigned int data_len, unsigned char *mac)
1364126Szf162725 {
1374126Szf162725 unsigned int mac_len = 0;
138*11034SQuaker.Fang@Sun.COM (void) HMAC(EVP_sha1(), key, key_len, data, data_len, mac, &mac_len);
1394126Szf162725 }
1404126Szf162725
1414126Szf162725
1424126Szf162725 void
hmac_sha1_vector(unsigned char * key,unsigned int key_len,size_t num_elem,unsigned char * addr[],unsigned int * len,unsigned char * mac)1434126Szf162725 hmac_sha1_vector(unsigned char *key, unsigned int key_len, size_t num_elem,
1444126Szf162725 unsigned char *addr[], unsigned int *len, unsigned char *mac)
1454126Szf162725 {
1464126Szf162725 unsigned char *buf, *ptr;
1474126Szf162725 int i, buf_len;
1484126Szf162725
1494126Szf162725 buf_len = 0;
1504126Szf162725 for (i = 0; i < num_elem; i ++)
1514126Szf162725 buf_len += len[i];
1524126Szf162725
1534126Szf162725 buf = malloc(buf_len);
1544126Szf162725 ptr = buf;
1554126Szf162725
1564126Szf162725 for (i = 0; i < num_elem; i ++) {
1574126Szf162725 (void) memcpy(ptr, addr[i], len[i]);
1584126Szf162725 ptr += len[i];
1594126Szf162725 }
1604126Szf162725
1614126Szf162725 hmac_sha1(key, key_len, buf, buf_len, mac);
1624126Szf162725
1634126Szf162725 free(buf);
1644126Szf162725 }
1654126Szf162725
1664126Szf162725
1674126Szf162725 void
sha1_prf(unsigned char * key,unsigned int key_len,char * label,unsigned char * data,unsigned int data_len,unsigned char * buf,size_t buf_len)1684126Szf162725 sha1_prf(unsigned char *key, unsigned int key_len,
1694126Szf162725 char *label, unsigned char *data, unsigned int data_len,
1704126Szf162725 unsigned char *buf, size_t buf_len)
1714126Szf162725 {
1724126Szf162725 uint8_t zero = 0, counter = 0;
1734126Szf162725 size_t pos, plen;
1744126Szf162725 uint8_t hash[SHA1_MAC_LEN];
1754126Szf162725 size_t label_len = strlen(label);
1764126Szf162725
1774126Szf162725 unsigned char *addr[4];
1784126Szf162725 unsigned int len[4];
1794126Szf162725
1804126Szf162725 addr[0] = (uint8_t *)label;
1814126Szf162725 len[0] = label_len;
1824126Szf162725 addr[1] = &zero;
1834126Szf162725 len[1] = 1;
1844126Szf162725 addr[2] = data;
1854126Szf162725 len[2] = data_len;
1864126Szf162725 addr[3] = &counter;
1874126Szf162725 len[3] = 1;
1884126Szf162725
1894126Szf162725 pos = 0;
1904126Szf162725 while (pos < buf_len) {
1914126Szf162725 plen = buf_len - pos;
1924126Szf162725 if (plen >= SHA1_MAC_LEN) {
1934126Szf162725 hmac_sha1_vector(key, key_len, 4, addr, len, &buf[pos]);
1944126Szf162725 pos += SHA1_MAC_LEN;
1954126Szf162725 } else {
1964126Szf162725 hmac_sha1_vector(key, key_len, 4, addr, len, hash);
1974126Szf162725 (void) memcpy(&buf[pos], hash, plen);
1984126Szf162725 break;
1994126Szf162725 }
2004126Szf162725 counter++;
2014126Szf162725 }
2024126Szf162725 }
2034126Szf162725
2044126Szf162725 void
pbkdf2_sha1(char * passphrase,char * ssid,size_t ssid_len,int iterations,unsigned char * buf,size_t buflen)2054126Szf162725 pbkdf2_sha1(char *passphrase, char *ssid, size_t ssid_len, int iterations,
2064126Szf162725 unsigned char *buf, size_t buflen)
2074126Szf162725 {
208*11034SQuaker.Fang@Sun.COM (void) PKCS5_PBKDF2_HMAC_SHA1(passphrase, -1, (unsigned char *)ssid,
209*11034SQuaker.Fang@Sun.COM ssid_len, iterations, buflen, buf);
2104126Szf162725 }
2114126Szf162725
2124126Szf162725 void
rc4_skip(uint8_t * key,size_t keylen,size_t skip,uint8_t * data,size_t data_len)2134126Szf162725 rc4_skip(uint8_t *key, size_t keylen, size_t skip,
2144126Szf162725 uint8_t *data, size_t data_len)
2154126Szf162725 {
2164126Szf162725 uint8_t *buf;
2174126Szf162725 size_t buf_len;
2184126Szf162725
2194126Szf162725 buf_len = skip + data_len;
2204126Szf162725 buf = malloc(buf_len);
2214126Szf162725
2224126Szf162725 bzero(buf, buf_len);
2234126Szf162725 bcopy(data, buf + skip, data_len);
2244126Szf162725
2254126Szf162725 rc4(buf, buf_len, key, keylen);
2264126Szf162725
2274126Szf162725 bcopy(buf + skip, data, data_len);
2284126Szf162725 free(buf);
2294126Szf162725 }
2304126Szf162725
2314126Szf162725 void
rc4(uint8_t * buf,size_t len,uint8_t * key,size_t key_len)2324126Szf162725 rc4(uint8_t *buf, size_t len, uint8_t *key, size_t key_len)
2334126Szf162725 {
2344126Szf162725 RC4_KEY k;
2354126Szf162725
2364126Szf162725 RC4_set_key(&k, key_len, key);
2374126Szf162725 RC4(&k, len, buf, buf);
2384126Szf162725 }
2394126Szf162725
2404126Szf162725 void
hmac_md5_vector(uint8_t * key,size_t key_len,size_t num_elem,uint8_t * addr[],size_t * len,uint8_t * mac)2414126Szf162725 hmac_md5_vector(uint8_t *key, size_t key_len, size_t num_elem,
2424126Szf162725 uint8_t *addr[], size_t *len, uint8_t *mac)
2434126Szf162725 {
2444126Szf162725 unsigned char *buf, *ptr;
2454126Szf162725 int i, buf_len;
2464126Szf162725
2474126Szf162725 buf_len = 0;
2484126Szf162725 for (i = 0; i < num_elem; i ++)
2494126Szf162725 buf_len += len[i];
2504126Szf162725
2514126Szf162725 buf = malloc(buf_len);
2524126Szf162725 ptr = buf;
2534126Szf162725
2544126Szf162725 for (i = 0; i < num_elem; i ++) {
2554126Szf162725 (void) memcpy(ptr, addr[i], len[i]);
2564126Szf162725 ptr += len[i];
2574126Szf162725 }
2584126Szf162725
2594126Szf162725 hmac_md5(key, key_len, buf, buf_len, mac);
2604126Szf162725 free(buf);
2614126Szf162725 }
2624126Szf162725
2634126Szf162725 /* RFC 2104 */
2644126Szf162725 void
hmac_md5(uint8_t * key,size_t key_len,uint8_t * data,size_t data_len,uint8_t * mac)2654126Szf162725 hmac_md5(uint8_t *key, size_t key_len, uint8_t *data,
2664126Szf162725 size_t data_len, uint8_t *mac)
2674126Szf162725 {
2684126Szf162725 unsigned int mac_len = 0;
269*11034SQuaker.Fang@Sun.COM (void) HMAC(EVP_md5(), key, key_len, data, data_len, mac, &mac_len);
2704126Szf162725 }
271