aboutsummaryrefslogtreecommitdiffstats
path: root/hmac_init.c
blob: 6983073115e95a71b90464ba806cfe082ba57ff3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/* See LICENSE file for copyright and license details. */
#include "common.h"


/**
 * Initialise an HMAC state
 * 
 * @param   state        The state that should be initialised
 * @param   algorithm    The hashing algorithm
 * @param   key          The key
 * @param   key_length   The length of key, in bits
 * @return               Zero on success, -1 on error
 */
int
libsha2_hmac_init(struct libsha2_hmac_state *restrict state, enum libsha2_algorithm algorithm,
                  const void *restrict key_, size_t keylen)
{
	const unsigned char *restrict key = key_;
	size_t i;

	state->sha2_state.algorithm = algorithm;
	state->outsize = libsha2_algorithm_output_size(algorithm) * 8;
	if (!state->outsize) {
		errno = EINVAL;
		return -1;
	}
	state->inited = 0;

	if (keylen <= (algorithm <= LIBSHA2_256 ? 64 * 8 : 128 * 8)) {
		memset(state->ipad, 0x36, sizeof(state->ipad));
		memset(state->opad, 0x5C, sizeof(state->opad));
		for (i = 0; i < keylen / 8; i++) {
			state->ipad[i] ^= key[i];
			state->opad[i] ^= key[i];
		}
		if (keylen & 7) {
			state->ipad[i] ^= (unsigned char)(key[i] << (8 - (keylen & 7)));
			state->opad[i] ^= (unsigned char)(key[i] << (8 - (keylen & 7)));
		}
	} else {
		memset(state->ipad, 0, sizeof(state->ipad));
		if (libsha2_init(&state->sha2_state, algorithm))
			return -1;
		libsha2_digest(&state->sha2_state, key, keylen, state->ipad);
		memcpy(state->opad, state->ipad, sizeof(state->ipad));
		for (i = 0; i < sizeof(state->ipad); i++) {
			state->ipad[i] ^= 0x36;
			state->opad[i] ^= 0x5C;
		}
	}

	return 0;
}