1214501Srpaulo/*
2214501Srpaulo * MD5 hash implementation and interface functions (non-FIPS allowed cases)
3214501Srpaulo * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
4214501Srpaulo *
5214501Srpaulo * This program is free software; you can redistribute it and/or modify
6214501Srpaulo * it under the terms of the GNU General Public License version 2 as
7214501Srpaulo * published by the Free Software Foundation.
8214501Srpaulo *
9214501Srpaulo * Alternatively, this software may be distributed under the terms of BSD
10214501Srpaulo * license.
11214501Srpaulo *
12214501Srpaulo * See README and COPYING for more details.
13214501Srpaulo */
14214501Srpaulo
15214501Srpaulo#include "includes.h"
16214501Srpaulo
17214501Srpaulo#include "common.h"
18214501Srpaulo#include "md5.h"
19214501Srpaulo#include "crypto.h"
20214501Srpaulo
21214501Srpaulo
22214501Srpaulo/**
23214501Srpaulo * hmac_md5_vector_non_fips_allow - HMAC-MD5 over data vector (RFC 2104)
24214501Srpaulo * @key: Key for HMAC operations
25214501Srpaulo * @key_len: Length of the key in bytes
26214501Srpaulo * @num_elem: Number of elements in the data vector
27214501Srpaulo * @addr: Pointers to the data areas
28214501Srpaulo * @len: Lengths of the data blocks
29214501Srpaulo * @mac: Buffer for the hash (16 bytes)
30214501Srpaulo * Returns: 0 on success, -1 on failure
31214501Srpaulo */
32214501Srpauloint hmac_md5_vector_non_fips_allow(const u8 *key, size_t key_len,
33214501Srpaulo				   size_t num_elem, const u8 *addr[],
34214501Srpaulo				   const size_t *len, u8 *mac)
35214501Srpaulo{
36214501Srpaulo	u8 k_pad[64]; /* padding - key XORd with ipad/opad */
37214501Srpaulo	u8 tk[16];
38214501Srpaulo	const u8 *_addr[6];
39214501Srpaulo	size_t i, _len[6];
40214501Srpaulo
41214501Srpaulo	if (num_elem > 5) {
42214501Srpaulo		/*
43214501Srpaulo		 * Fixed limit on the number of fragments to avoid having to
44214501Srpaulo		 * allocate memory (which could fail).
45214501Srpaulo		 */
46214501Srpaulo		return -1;
47214501Srpaulo	}
48214501Srpaulo
49214501Srpaulo        /* if key is longer than 64 bytes reset it to key = MD5(key) */
50214501Srpaulo        if (key_len > 64) {
51214501Srpaulo		if (md5_vector_non_fips_allow(1, &key, &key_len, tk))
52214501Srpaulo			return -1;
53214501Srpaulo		key = tk;
54214501Srpaulo		key_len = 16;
55214501Srpaulo        }
56214501Srpaulo
57214501Srpaulo	/* the HMAC_MD5 transform looks like:
58214501Srpaulo	 *
59214501Srpaulo	 * MD5(K XOR opad, MD5(K XOR ipad, text))
60214501Srpaulo	 *
61214501Srpaulo	 * where K is an n byte key
62214501Srpaulo	 * ipad is the byte 0x36 repeated 64 times
63214501Srpaulo	 * opad is the byte 0x5c repeated 64 times
64214501Srpaulo	 * and text is the data being protected */
65214501Srpaulo
66214501Srpaulo	/* start out by storing key in ipad */
67214501Srpaulo	os_memset(k_pad, 0, sizeof(k_pad));
68214501Srpaulo	os_memcpy(k_pad, key, key_len);
69214501Srpaulo
70214501Srpaulo	/* XOR key with ipad values */
71214501Srpaulo	for (i = 0; i < 64; i++)
72214501Srpaulo		k_pad[i] ^= 0x36;
73214501Srpaulo
74214501Srpaulo	/* perform inner MD5 */
75214501Srpaulo	_addr[0] = k_pad;
76214501Srpaulo	_len[0] = 64;
77214501Srpaulo	for (i = 0; i < num_elem; i++) {
78214501Srpaulo		_addr[i + 1] = addr[i];
79214501Srpaulo		_len[i + 1] = len[i];
80214501Srpaulo	}
81214501Srpaulo	if (md5_vector_non_fips_allow(1 + num_elem, _addr, _len, mac))
82214501Srpaulo		return -1;
83214501Srpaulo
84214501Srpaulo	os_memset(k_pad, 0, sizeof(k_pad));
85214501Srpaulo	os_memcpy(k_pad, key, key_len);
86214501Srpaulo	/* XOR key with opad values */
87214501Srpaulo	for (i = 0; i < 64; i++)
88214501Srpaulo		k_pad[i] ^= 0x5c;
89214501Srpaulo
90214501Srpaulo	/* perform outer MD5 */
91214501Srpaulo	_addr[0] = k_pad;
92214501Srpaulo	_len[0] = 64;
93214501Srpaulo	_addr[1] = mac;
94214501Srpaulo	_len[1] = MD5_MAC_LEN;
95214501Srpaulo	return md5_vector_non_fips_allow(2, _addr, _len, mac);
96214501Srpaulo}
97214501Srpaulo
98214501Srpaulo
99214501Srpaulo/**
100214501Srpaulo * hmac_md5_non_fips_allow - HMAC-MD5 over data buffer (RFC 2104)
101214501Srpaulo * @key: Key for HMAC operations
102214501Srpaulo * @key_len: Length of the key in bytes
103214501Srpaulo * @data: Pointers to the data area
104214501Srpaulo * @data_len: Length of the data area
105214501Srpaulo * @mac: Buffer for the hash (16 bytes)
106214501Srpaulo * Returns: 0 on success, -1 on failure
107214501Srpaulo */
108214501Srpauloint hmac_md5_non_fips_allow(const u8 *key, size_t key_len, const u8 *data,
109214501Srpaulo			    size_t data_len, u8 *mac)
110214501Srpaulo{
111214501Srpaulo	return hmac_md5_vector_non_fips_allow(key, key_len, 1, &data,
112214501Srpaulo					      &data_len, mac);
113214501Srpaulo}
114