]>
Commit | Line | Data |
---|---|---|
9e228de6 | 1 | /* |
19ef2aec | 2 | * Copyright (C) 2022 Tobias Brunner |
9e228de6 | 3 | * |
19ef2aec | 4 | * Copyright (C) secunet Security Networks AG |
9e228de6 | 5 | * |
19ef2aec TB |
6 | * This program is free software; you can redistribute it and/or modify it |
7 | * under the terms of the GNU General Public License as published by the | |
8 | * Free Software Foundation; either version 2 of the License, or (at your | |
9 | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | |
9e228de6 | 10 | * |
19ef2aec TB |
11 | * This program is distributed in the hope that it will be useful, but |
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
13 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
14 | * for more details. | |
9e228de6 TB |
15 | */ |
16 | ||
0339ce34 | 17 | #include "kdf_kdf.h" |
9e228de6 | 18 | |
9e228de6 TB |
19 | typedef struct private_kdf_t private_kdf_t; |
20 | ||
21 | /** | |
22 | * Private data. | |
23 | */ | |
24 | struct private_kdf_t { | |
25 | ||
26 | /** | |
27 | * Public interface. | |
28 | */ | |
29 | kdf_t public; | |
30 | ||
0339ce34 TB |
31 | /** |
32 | * KDF type. | |
33 | */ | |
34 | key_derivation_function_t type; | |
35 | ||
9e228de6 TB |
36 | /** |
37 | * Underlying PRF. | |
38 | */ | |
39 | prf_t *prf; | |
40 | ||
41 | /** | |
42 | * Salt value. | |
43 | */ | |
44 | chunk_t salt; | |
45 | }; | |
46 | ||
47 | METHOD(kdf_t, get_type, key_derivation_function_t, | |
48 | private_kdf_t *this) | |
49 | { | |
0339ce34 | 50 | return this->type; |
9e228de6 TB |
51 | } |
52 | ||
7bde56a9 TB |
53 | METHOD(kdf_t, get_length, size_t, |
54 | private_kdf_t *this) | |
55 | { | |
0339ce34 TB |
56 | if (this->type == KDF_PRF_PLUS) |
57 | { | |
58 | return SIZE_MAX; | |
59 | } | |
60 | return this->prf->get_block_size(this->prf); | |
7bde56a9 TB |
61 | } |
62 | ||
0339ce34 | 63 | METHOD(kdf_t, get_bytes_prf_plus, bool, |
9e228de6 TB |
64 | private_kdf_t *this, size_t out_len, uint8_t *buffer) |
65 | { | |
f0957d12 TB |
66 | chunk_t block, previous = chunk_empty; |
67 | uint8_t counter = 1, *out = buffer; | |
68 | size_t len; | |
69 | bool success = TRUE; | |
9e228de6 | 70 | |
f0957d12 TB |
71 | block = chunk_alloca(this->prf->get_block_size(this->prf)); |
72 | if (out_len > block.len * 255) | |
9e228de6 TB |
73 | { |
74 | return FALSE; | |
75 | } | |
f0957d12 TB |
76 | |
77 | while (out_len) | |
78 | { | |
79 | if (!this->prf->get_bytes(this->prf, previous, NULL) || | |
80 | !this->prf->get_bytes(this->prf, this->salt, NULL) || | |
81 | !this->prf->get_bytes(this->prf, chunk_from_thing(counter), | |
82 | block.ptr)) | |
83 | { | |
84 | success = FALSE; | |
85 | break; | |
86 | } | |
87 | len = min(out_len, block.len); | |
88 | memcpy(out, block.ptr, len); | |
89 | previous = chunk_create(out, block.len); | |
90 | ||
91 | out_len -= len; | |
92 | out += len; | |
93 | counter++; | |
94 | } | |
95 | memwipe(block.ptr, block.len); | |
9e228de6 TB |
96 | return success; |
97 | } | |
98 | ||
0339ce34 TB |
99 | METHOD(kdf_t, get_bytes, bool, |
100 | private_kdf_t *this, size_t out_len, uint8_t *buffer) | |
101 | { | |
102 | if (out_len != get_length(this)) | |
103 | { | |
104 | return FALSE; | |
105 | } | |
106 | return this->prf->get_bytes(this->prf, this->salt, buffer); | |
107 | } | |
108 | ||
9e228de6 TB |
109 | METHOD(kdf_t, allocate_bytes, bool, |
110 | private_kdf_t *this, size_t out_len, chunk_t *chunk) | |
111 | { | |
0339ce34 TB |
112 | if (this->type == KDF_PRF) |
113 | { | |
114 | out_len = out_len ?: get_length(this); | |
115 | } | |
116 | ||
9e228de6 TB |
117 | *chunk = chunk_alloc(out_len); |
118 | ||
0339ce34 | 119 | if (!this->public.get_bytes(&this->public, out_len, chunk->ptr)) |
9e228de6 TB |
120 | { |
121 | chunk_free(chunk); | |
122 | return FALSE; | |
123 | } | |
124 | return TRUE; | |
125 | } | |
126 | ||
127 | METHOD(kdf_t, set_param, bool, | |
128 | private_kdf_t *this, kdf_param_t param, ...) | |
129 | { | |
130 | chunk_t chunk; | |
131 | bool success = FALSE; | |
132 | ||
0339ce34 TB |
133 | if (this->type == KDF_PRF) |
134 | { /* IKEv2 uses the nonces etc., which we receive as SALT, as PRF key and | |
135 | * the DH secret as salt */ | |
136 | switch (param) | |
137 | { | |
138 | case KDF_PARAM_KEY: | |
139 | param = KDF_PARAM_SALT; | |
140 | break; | |
141 | case KDF_PARAM_SALT: | |
142 | param = KDF_PARAM_KEY; | |
143 | break; | |
144 | default: | |
145 | break; | |
146 | } | |
147 | } | |
148 | ||
9e228de6 TB |
149 | switch (param) |
150 | { | |
151 | case KDF_PARAM_KEY: | |
152 | VA_ARGS_GET(param, chunk); | |
153 | success = this->prf->set_key(this->prf, chunk); | |
154 | break; | |
155 | case KDF_PARAM_SALT: | |
156 | VA_ARGS_GET(param, chunk); | |
157 | chunk_clear(&this->salt); | |
158 | this->salt = chunk_clone(chunk); | |
159 | success = TRUE; | |
160 | break; | |
161 | } | |
162 | return success; | |
163 | } | |
164 | ||
165 | METHOD(kdf_t, destroy, void, | |
166 | private_kdf_t *this) | |
167 | { | |
168 | this->prf->destroy(this->prf); | |
169 | chunk_clear(&this->salt); | |
170 | free(this); | |
171 | } | |
172 | ||
173 | /* | |
174 | * Described in header | |
175 | */ | |
0339ce34 | 176 | kdf_t *kdf_kdf_create(key_derivation_function_t algo, va_list args) |
9e228de6 TB |
177 | { |
178 | private_kdf_t *this; | |
179 | pseudo_random_function_t prf_alg; | |
180 | prf_t *prf; | |
181 | ||
0339ce34 | 182 | if (algo != KDF_PRF && algo != KDF_PRF_PLUS) |
9e228de6 TB |
183 | { |
184 | return NULL; | |
185 | } | |
186 | ||
187 | VA_ARGS_VGET(args, prf_alg); | |
188 | prf = lib->crypto->create_prf(lib->crypto, prf_alg); | |
189 | if (!prf) | |
190 | { | |
0339ce34 TB |
191 | DBG1(DBG_LIB, "failed to create %N for %N", |
192 | pseudo_random_function_names, prf_alg, | |
193 | key_derivation_function_names, algo); | |
9e228de6 TB |
194 | return NULL; |
195 | } | |
196 | ||
197 | INIT(this, | |
198 | .public = { | |
199 | .get_type = _get_type, | |
7bde56a9 | 200 | .get_length = _get_length, |
9e228de6 TB |
201 | .get_bytes = _get_bytes, |
202 | .allocate_bytes = _allocate_bytes, | |
203 | .set_param = _set_param, | |
204 | .destroy = _destroy, | |
205 | }, | |
0339ce34 | 206 | .type = algo, |
9e228de6 TB |
207 | .prf = prf, |
208 | ); | |
209 | ||
0339ce34 TB |
210 | if (algo == KDF_PRF_PLUS) |
211 | { | |
212 | this->public.get_bytes = _get_bytes_prf_plus; | |
213 | } | |
9e228de6 TB |
214 | return &this->public; |
215 | } |