1/*
2 * MD5 hash implementation and interface functions (non-FIPS allowed cases)
3 * Copyright (c) 2003-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 "md5.h"
19#include "crypto.h"
20
21
22/**
23 * hmac_md5_vector_non_fips_allow - HMAC-MD5 over data vector (RFC 2104)
24 * @key: Key for HMAC operations
25 * @key_len: Length of the key in bytes
26 * @num_elem: Number of elements in the data vector
27 * @addr: Pointers to the data areas
28 * @len: Lengths of the data blocks
29 * @mac: Buffer for the hash (16 bytes)
30 * Returns: 0 on success, -1 on failure
31 */
32int hmac_md5_vector_non_fips_allow(const u8 *key, size_t key_len,
33				   size_t num_elem, const u8 *addr[],
34				   const size_t *len, u8 *mac)
35{
36	u8 k_pad[64]; /* padding - key XORd with ipad/opad */
37	u8 tk[16];
38	const u8 *_addr[6];
39	size_t i, _len[6];
40
41	if (num_elem > 5) {
42		/*
43		 * Fixed limit on the number of fragments to avoid having to
44		 * allocate memory (which could fail).
45		 */
46		return -1;
47	}
48
49        /* if key is longer than 64 bytes reset it to key = MD5(key) */
50        if (key_len > 64) {
51		if (md5_vector_non_fips_allow(1, &key, &key_len, tk))
52			return -1;
53		key = tk;
54		key_len = 16;
55        }
56
57	/* the HMAC_MD5 transform looks like:
58	 *
59	 * MD5(K XOR opad, MD5(K XOR ipad, text))
60	 *
61	 * where K is an n byte key
62	 * ipad is the byte 0x36 repeated 64 times
63	 * opad is the byte 0x5c repeated 64 times
64	 * and text is the data being protected */
65
66	/* start out by storing key in ipad */
67	os_memset(k_pad, 0, sizeof(k_pad));
68	os_memcpy(k_pad, key, key_len);
69
70	/* XOR key with ipad values */
71	for (i = 0; i < 64; i++)
72		k_pad[i] ^= 0x36;
73
74	/* perform inner MD5 */
75	_addr[0] = k_pad;
76	_len[0] = 64;
77	for (i = 0; i < num_elem; i++) {
78		_addr[i + 1] = addr[i];
79		_len[i + 1] = len[i];
80	}
81	if (md5_vector_non_fips_allow(1 + num_elem, _addr, _len, mac))
82		return -1;
83
84	os_memset(k_pad, 0, sizeof(k_pad));
85	os_memcpy(k_pad, key, key_len);
86	/* XOR key with opad values */
87	for (i = 0; i < 64; i++)
88		k_pad[i] ^= 0x5c;
89
90	/* perform outer MD5 */
91	_addr[0] = k_pad;
92	_len[0] = 64;
93	_addr[1] = mac;
94	_len[1] = MD5_MAC_LEN;
95	return md5_vector_non_fips_allow(2, _addr, _len, mac);
96}
97
98
99/**
100 * hmac_md5_non_fips_allow - HMAC-MD5 over data buffer (RFC 2104)
101 * @key: Key for HMAC operations
102 * @key_len: Length of the key in bytes
103 * @data: Pointers to the data area
104 * @data_len: Length of the data area
105 * @mac: Buffer for the hash (16 bytes)
106 * Returns: 0 on success, -1 on failure
107 */
108int hmac_md5_non_fips_allow(const u8 *key, size_t key_len, const u8 *data,
109			    size_t data_len, u8 *mac)
110{
111	return hmac_md5_vector_non_fips_allow(key, key_len, 1, &data,
112					      &data_len, mac);
113}
114