The introduced SHA1_NOFINAL hasher was not sufficient for EAP-AKA,
[strongswan.git] / src / libstrongswan / plugins / fips_prf / fips_prf.c
1 /*
2 * Copyright (C) 2006 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 *
15 * $Id$
16 */
17
18 #include "fips_prf.h"
19
20 #include <arpa/inet.h>
21
22 #include <debug.h>
23
24 typedef struct private_fips_prf_t private_fips_prf_t;
25
26 /**
27 * Private data of a fips_prf_t object.
28 */
29 struct private_fips_prf_t {
30 /**
31 * Public fips_prf_t interface.
32 */
33 fips_prf_t public;
34
35 /**
36 * key of prf function, "b" long
37 */
38 u_int8_t *key;
39
40 /**
41 * size of "b" in bytes
42 */
43 size_t b;
44
45 /**
46 * Keyed SHA1 prf: It does not use SHA1Final operation
47 */
48 prf_t *keyed_prf;
49
50 /**
51 * G function, either SHA1 or DES
52 */
53 void (*g)(private_fips_prf_t *this, chunk_t c, u_int8_t res[]);
54 };
55
56 /**
57 * sum = (a + b) mod 2 ^ (length * 8)
58 */
59 static void add_mod(size_t length, u_int8_t a[], u_int8_t b[], u_int8_t sum[])
60 {
61 int i, c = 0;
62
63 for(i = length - 1; i >= 0; i--)
64 {
65 u_int32_t tmp;
66
67 tmp = a[i] + b[i] + c;
68 sum[i] = 0xff & tmp;
69 c = tmp >> 8;
70 }
71 }
72
73 /**
74 * calculate "chunk mod 2^(length*8)" and save it into buffer
75 */
76 static void chunk_mod(size_t length, chunk_t chunk, u_int8_t buffer[])
77 {
78 if (chunk.len < length)
79 {
80 /* apply seed as least significant bits, others are zero */
81 memset(buffer, 0, length - chunk.len);
82 memcpy(buffer + length - chunk.len, chunk.ptr, chunk.len);
83 }
84 else
85 {
86 /* use least significant bytes from seed, as we use mod 2^b */
87 memcpy(buffer, chunk.ptr + chunk.len - length, length);
88 }
89 }
90
91 /**
92 * Implementation of prf_t.get_bytes.
93 *
94 * Test vector:
95 *
96 * key:
97 * 0xbd, 0x02, 0x9b, 0xbe, 0x7f, 0x51, 0x96, 0x0b,
98 * 0xcf, 0x9e, 0xdb, 0x2b, 0x61, 0xf0, 0x6f, 0x0f,
99 * 0xeb, 0x5a, 0x38, 0xb6
100 *
101 * seed:
102 * 0x00
103 *
104 * result:
105 * 0x20, 0x70, 0xb3, 0x22, 0x3d, 0xba, 0x37, 0x2f,
106 * 0xde, 0x1c, 0x0f, 0xfc, 0x7b, 0x2e, 0x3b, 0x49,
107 * 0x8b, 0x26, 0x06, 0x14, 0x3c, 0x6c, 0x18, 0xba,
108 * 0xcb, 0x0f, 0x6c, 0x55, 0xba, 0xbb, 0x13, 0x78,
109 * 0x8e, 0x20, 0xd7, 0x37, 0xa3, 0x27, 0x51, 0x16
110 */
111 static void get_bytes(private_fips_prf_t *this, chunk_t seed, u_int8_t w[])
112 {
113 int i;
114 u_int8_t xval[this->b];
115 u_int8_t xseed[this->b];
116 u_int8_t sum[this->b];
117 u_int8_t *xkey = this->key;
118 u_int8_t one[this->b];
119 chunk_t xval_chunk = chunk_from_buf(xval);
120
121 memset(one, 0, this->b);
122 one[this->b - 1] = 0x01;
123
124 /* 3.1 */
125 chunk_mod(this->b, seed, xseed);
126
127 /* 3.2 */
128 for (i = 0; i < 2; i++) /* twice */
129 {
130 /* a. XVAL = (XKEY + XSEED j) mod 2^b */
131 add_mod(this->b, xkey, xseed, xval);
132 DBG3("XVAL %b", xval, this->b);
133 /* b. wi = G(t, XVAL ) */
134 this->g(this, xval_chunk, &w[i * this->b]);
135 DBG3("w[%d] %b", i, &w[i * this->b], this->b);
136 /* c. XKEY = (1 + XKEY + wi) mod 2b */
137 add_mod(this->b, xkey, &w[i * this->b], sum);
138 add_mod(this->b, sum, one, xkey);
139 DBG3("XKEY %b", xkey, this->b);
140 }
141
142 /* 3.3 done already, mod q not used */
143 }
144
145 /**
146 * Implementation of prf_t.get_block_size.
147 */
148 static size_t get_block_size(private_fips_prf_t *this)
149 {
150 return 2 * this->b;
151 }
152 /**
153 * Implementation of prf_t.allocate_bytes.
154 */
155 static void allocate_bytes(private_fips_prf_t *this, chunk_t seed, chunk_t *chunk)
156 {
157 *chunk = chunk_alloc(get_block_size(this));
158 get_bytes(this, seed, chunk->ptr);
159 }
160
161 /**
162 * Implementation of prf_t.get_key_size.
163 */
164 static size_t get_key_size(private_fips_prf_t *this)
165 {
166 return this->b;
167 }
168
169 /**
170 * Implementation of prf_t.set_key.
171 */
172 static void set_key(private_fips_prf_t *this, chunk_t key)
173 {
174 /* save key as "key mod 2^b" */
175 chunk_mod(this->b, key, this->key);
176 }
177
178 /**
179 * Implementation of the G() function based on SHA1
180 */
181 void g_sha1(private_fips_prf_t *this, chunk_t c, u_int8_t res[])
182 {
183 u_int8_t buf[64];
184
185 if (c.len < sizeof(buf))
186 {
187 /* pad c with zeros */
188 memset(buf, 0, sizeof(buf));
189 memcpy(buf, c.ptr, c.len);
190 c.ptr = buf;
191 c.len = sizeof(buf);
192 }
193 else
194 {
195 /* not more than 512 bits can be G()-ed */
196 c.len = sizeof(buf);
197 }
198
199 /* use the keyed hasher, but use an empty key to use SHA1 IV */
200 this->keyed_prf->set_key(this->keyed_prf, chunk_empty);
201 this->keyed_prf->get_bytes(this->keyed_prf, c, res);
202 }
203
204 /**
205 * Implementation of prf_t.destroy.
206 */
207 static void destroy(private_fips_prf_t *this)
208 {
209 this->keyed_prf->destroy(this->keyed_prf);
210 free(this->key);
211 free(this);
212 }
213
214 /*
215 * Described in header.
216 */
217 fips_prf_t *fips_prf_create(pseudo_random_function_t algo)
218 {
219 private_fips_prf_t *this = malloc_thing(private_fips_prf_t);
220
221 this->public.prf_interface.get_bytes = (void (*) (prf_t *,chunk_t,u_int8_t*))get_bytes;
222 this->public.prf_interface.allocate_bytes = (void (*) (prf_t*,chunk_t,chunk_t*))allocate_bytes;
223 this->public.prf_interface.get_block_size = (size_t (*) (prf_t*))get_block_size;
224 this->public.prf_interface.get_key_size = (size_t (*) (prf_t*))get_key_size;
225 this->public.prf_interface.set_key = (void (*) (prf_t *,chunk_t))set_key;
226 this->public.prf_interface.destroy = (void (*) (prf_t *))destroy;
227
228 switch (algo)
229 {
230 case PRF_FIPS_SHA1_160:
231 {
232 this->g = g_sha1;
233 this->b = 20;
234 this->keyed_prf = lib->crypto->create_prf(lib->crypto, PRF_KEYED_SHA1);
235 if (this->keyed_prf == NULL)
236 {
237 free(this);
238 return NULL;
239 }
240 break;
241 }
242 case PRF_FIPS_DES:
243 /* not implemented yet */
244 default:
245 free(this);
246 return NULL;
247 }
248 this->key = malloc(this->b);
249
250 return &this->public;
251 }
252