]>
Commit | Line | Data |
---|---|---|
781fadcc MW |
1 | /** |
2 | * @file hmac.c | |
3 | * | |
7a09fcea | 4 | * @brief Implementation of hmac_t. |
781fadcc MW |
5 | */ |
6 | ||
7 | /* | |
8 | * Copyright (C) 2005 Jan Hutter, Martin Willi | |
9 | * Hochschule fuer Technik Rapperswil | |
10 | * | |
11 | * This program is free software; you can redistribute it and/or modify it | |
7a09fcea | 12 | * under the terms of the GNU General hmac License as published by the |
781fadcc MW |
13 | * Free Software Foundation; either version 2 of the License, or (at your |
14 | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | |
15 | * | |
16 | * This program is distributed in the hope that it will be useful, but | |
17 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
7a09fcea | 18 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General hmac License |
781fadcc MW |
19 | * for more details. |
20 | */ | |
21 | ||
5113680f | 22 | #include <string.h> |
781fadcc MW |
23 | |
24 | #include "hmac.h" | |
25 | ||
7a09fcea | 26 | |
5796aa16 MW |
27 | typedef struct private_hmac_t private_hmac_t; |
28 | ||
781fadcc | 29 | /** |
1e7d52a6 JH |
30 | * Private data of a hmac_t object. |
31 | * | |
32 | * The variable names are the same as in the RFC. | |
781fadcc | 33 | */ |
5796aa16 | 34 | struct private_hmac_t { |
781fadcc | 35 | /** |
1e7d52a6 | 36 | * Public hmac_t interface. |
781fadcc | 37 | */ |
7a09fcea | 38 | hmac_t hmac; |
781fadcc | 39 | |
781fadcc | 40 | /** |
1e7d52a6 | 41 | * Block size, as in RFC. |
781fadcc MW |
42 | */ |
43 | u_int8_t b; | |
44 | ||
45 | /** | |
1e7d52a6 | 46 | * Hash function. |
781fadcc MW |
47 | */ |
48 | hasher_t *h; | |
49 | ||
50 | /** | |
1e7d52a6 | 51 | * Previously xor'ed key using opad. |
781fadcc MW |
52 | */ |
53 | chunk_t opaded_key; | |
1e7d52a6 | 54 | |
781fadcc | 55 | /** |
1e7d52a6 | 56 | * Previously xor'ed key using ipad. |
781fadcc MW |
57 | */ |
58 | chunk_t ipaded_key; | |
59 | }; | |
60 | ||
61 | /** | |
7a09fcea | 62 | * Implementation of hmac_t.get_mac. |
781fadcc | 63 | */ |
d048df5c | 64 | static void get_mac(private_hmac_t *this, chunk_t data, u_int8_t *out) |
781fadcc | 65 | { |
1318dd4e MW |
66 | /* H(K XOR opad, H(K XOR ipad, text)) |
67 | * | |
68 | * if out is NULL, we append text to the inner hash. | |
69 | * else, we complete the inner and do the outer. | |
70 | * | |
71 | */ | |
72 | ||
52923c9a | 73 | u_int8_t buffer[this->h->get_hash_size(this->h)]; |
781fadcc | 74 | chunk_t inner; |
781fadcc | 75 | |
1318dd4e MW |
76 | if (out == NULL) |
77 | { | |
78 | /* append data to inner */ | |
79 | this->h->get_hash(this->h, data, NULL); | |
80 | } | |
81 | else | |
82 | { | |
83 | /* append and do outer hash */ | |
84 | inner.ptr = buffer; | |
52923c9a | 85 | inner.len = this->h->get_hash_size(this->h); |
1318dd4e MW |
86 | |
87 | /* complete inner */ | |
88 | this->h->get_hash(this->h, data, buffer); | |
89 | ||
90 | /* do outer */ | |
91 | this->h->get_hash(this->h, this->opaded_key, NULL); | |
92 | this->h->get_hash(this->h, inner, out); | |
93 | ||
94 | /* reinit for next call */ | |
95 | this->h->get_hash(this->h, this->ipaded_key, NULL); | |
96 | } | |
781fadcc MW |
97 | } |
98 | ||
99 | /** | |
7a09fcea | 100 | * Implementation of hmac_t.allocate_mac. |
781fadcc | 101 | */ |
d048df5c | 102 | static void allocate_mac(private_hmac_t *this, chunk_t data, chunk_t *out) |
781fadcc MW |
103 | { |
104 | /* allocate space and use get_mac */ | |
1318dd4e | 105 | if (out == NULL) |
781fadcc | 106 | { |
1318dd4e | 107 | /* append mode */ |
7a09fcea | 108 | this->hmac.get_mac(&(this->hmac), data, NULL); |
1318dd4e MW |
109 | } |
110 | else | |
111 | { | |
52923c9a | 112 | out->len = this->h->get_hash_size(this->h); |
5113680f | 113 | out->ptr = malloc(out->len); |
7a09fcea | 114 | this->hmac.get_mac(&(this->hmac), data, out->ptr); |
781fadcc | 115 | } |
781fadcc MW |
116 | } |
117 | ||
118 | /** | |
7a09fcea | 119 | * Implementation of hmac_t.get_block_size. |
781fadcc MW |
120 | */ |
121 | static size_t get_block_size(private_hmac_t *this) | |
122 | { | |
52923c9a | 123 | return this->h->get_hash_size(this->h); |
781fadcc MW |
124 | } |
125 | ||
a217b51d | 126 | /** |
7a09fcea | 127 | * Implementation of hmac_t.set_key. |
a217b51d | 128 | */ |
d048df5c | 129 | static void set_key(private_hmac_t *this, chunk_t key) |
a217b51d MW |
130 | { |
131 | int i; | |
132 | u_int8_t buffer[this->b]; | |
133 | ||
134 | memset(buffer, 0, this->b); | |
135 | ||
136 | if (key.len > this->b) | |
137 | { | |
138 | /* if key is too long, it will be hashed */ | |
139 | this->h->get_hash(this->h, key, buffer); | |
140 | } | |
141 | else | |
142 | { | |
143 | /* if not, just copy it in our pre-padded k */ | |
144 | memcpy(buffer, key.ptr, key.len); | |
145 | } | |
146 | ||
147 | /* apply ipad and opad to key */ | |
148 | for (i = 0; i < this->b; i++) | |
149 | { | |
150 | this->ipaded_key.ptr[i] = buffer[i] ^ 0x36; | |
151 | this->opaded_key.ptr[i] = buffer[i] ^ 0x5C; | |
152 | } | |
153 | ||
62adf1e0 | 154 | /* begin hashing of inner pad */ |
1318dd4e MW |
155 | this->h->reset(this->h); |
156 | this->h->get_hash(this->h, this->ipaded_key, NULL); | |
a217b51d MW |
157 | } |
158 | ||
781fadcc | 159 | /** |
7a09fcea | 160 | * Implementation of hmac_t.destroy. |
781fadcc | 161 | */ |
d048df5c | 162 | static void destroy(private_hmac_t *this) |
781fadcc MW |
163 | { |
164 | this->h->destroy(this->h); | |
5113680f MW |
165 | free(this->opaded_key.ptr); |
166 | free(this->ipaded_key.ptr); | |
167 | free(this); | |
781fadcc MW |
168 | } |
169 | ||
170 | /* | |
171 | * Described in header | |
172 | */ | |
a217b51d | 173 | hmac_t *hmac_create(hash_algorithm_t hash_algorithm) |
781fadcc MW |
174 | { |
175 | private_hmac_t *this; | |
781fadcc | 176 | |
5113680f | 177 | this = malloc_thing(private_hmac_t); |
d048df5c | 178 | |
7a09fcea | 179 | /* set hmac_t methods */ |
d048df5c MW |
180 | this->hmac.get_mac = (void (*)(hmac_t *,chunk_t,u_int8_t*))get_mac; |
181 | this->hmac.allocate_mac = (void (*)(hmac_t *,chunk_t,chunk_t*))allocate_mac; | |
7a09fcea | 182 | this->hmac.get_block_size = (size_t (*)(hmac_t *))get_block_size; |
d048df5c MW |
183 | this->hmac.set_key = (void (*)(hmac_t *,chunk_t))set_key; |
184 | this->hmac.destroy = (void (*)(hmac_t *))destroy; | |
781fadcc MW |
185 | |
186 | /* set b, according to hasher */ | |
187 | switch (hash_algorithm) | |
188 | { | |
189 | case HASH_SHA1: | |
1484eedb | 190 | case HASH_MD5: |
781fadcc MW |
191 | this->b = 64; |
192 | break; | |
193 | default: | |
5113680f | 194 | free(this); |
781fadcc MW |
195 | return NULL; |
196 | } | |
197 | ||
198 | /* build the hasher */ | |
199 | this->h = hasher_create(hash_algorithm); | |
781fadcc MW |
200 | |
201 | /* build ipad and opad */ | |
5113680f | 202 | this->opaded_key.ptr = malloc(this->b); |
781fadcc | 203 | this->opaded_key.len = this->b; |
d048df5c | 204 | |
5113680f | 205 | this->ipaded_key.ptr = malloc(this->b); |
781fadcc | 206 | this->ipaded_key.len = this->b; |
a217b51d | 207 | |
7a09fcea | 208 | return &(this->hmac); |
781fadcc | 209 | } |