]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libstrongswan/plugins/kdf/kdf_kdf.c
Update copyright headers after acquisition by secunet
[thirdparty/strongswan.git] / src / libstrongswan / plugins / kdf / kdf_kdf.c
CommitLineData
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
19typedef struct private_kdf_t private_kdf_t;
20
21/**
22 * Private data.
23 */
24struct 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
47METHOD(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
53METHOD(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 63METHOD(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
99METHOD(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
109METHOD(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
127METHOD(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
165METHOD(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 176kdf_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}