Coverage Report

Created: 2024-07-22 06:07

/src/strongswan/src/libstrongswan/plugins/mgf1/mgf1_xof.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2013-2016 Andreas Steffen
3
 *
4
 * Copyright (C) secunet Security Networks AG
5
 *
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>.
10
 *
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.
15
 */
16
17
#include "mgf1_xof.h"
18
19
#include "crypto/hashers/hasher.h"
20
#include "utils/debug.h"
21
22
typedef struct private_mgf1_xof_t private_mgf1_xof_t;
23
24
/**
25
 * Private data of an mgf1_xof_t object.
26
 */
27
struct private_mgf1_xof_t {
28
29
  /**
30
   * Public mgf1_xof_t interface.
31
   */
32
  mgf1_xof_t public;
33
34
  /**
35
   * XOF type of the MGF1 Mask Generation Function
36
   */
37
  ext_out_function_t type;
38
39
  /**
40
   * Hasher the MGF1 Mask Generation Function is based on
41
   */
42
  hasher_t *hasher;
43
44
  /**
45
   * Is the seed hashed before using it as a seed for MGF1 ?
46
   */
47
  bool hash_seed;
48
49
  /**
50
   * Counter
51
   */
52
  uint32_t counter;
53
54
  /**
55
   * Set if counter has reached 2^32
56
   */
57
  bool overflow;
58
59
  /**
60
   * Current state to be hashed
61
   */
62
  chunk_t state;
63
64
  /**
65
   * Position of the 4 octet counter string
66
   */
67
  uint8_t *ctr_str;
68
69
  /**
70
   * Latest hash block
71
   */
72
  uint8_t buf[HASH_SIZE_SHA512];
73
74
  /**
75
   * Index pointing to the current position in the hash block
76
   */
77
  size_t buf_index;
78
79
};
80
81
METHOD(xof_t, get_type, ext_out_function_t,
82
  private_mgf1_xof_t *this)
83
0
{
84
0
  return this->type;
85
0
}
86
87
static bool get_next_block(private_mgf1_xof_t *this, uint8_t *buffer)
88
0
{
89
  /* detect overflow, set counter string and increment counter */
90
0
  if (this->overflow)
91
0
  {
92
0
    DBG1(DBG_LIB, "MGF1 overflow occurred");
93
0
    return FALSE;
94
0
  }
95
0
  htoun32(this->ctr_str, this->counter++);
96
0
  if (this->counter == 0)
97
0
  {
98
0
    this->overflow = TRUE;
99
0
  }
100
101
  /* get the next block from the hash function */
102
0
  if (!this->hasher->get_hash(this->hasher, this->state, buffer))
103
0
  {
104
0
    return FALSE;
105
0
  }
106
107
0
  return TRUE;
108
0
}
109
110
METHOD(xof_t, get_bytes, bool,
111
  private_mgf1_xof_t *this, size_t out_len, uint8_t *buffer)
112
0
{
113
0
  size_t index = 0, blocks, len, hash_size;
114
115
0
  hash_size = this->hasher->get_hash_size(this->hasher);
116
117
  /* empty the current hash block buffer first */
118
0
  len = min(out_len, hash_size - this->buf_index);
119
0
  if (len)
120
0
  {
121
0
    memcpy(buffer, this->buf + this->buf_index, len);
122
0
    index += len;
123
0
    this->buf_index += len;
124
0
  }
125
126
  /* copy whole hash blocks directly to output buffer */
127
0
  blocks = (out_len - index) / hash_size;
128
0
  while (blocks--)
129
0
  {
130
0
    if (!get_next_block(this, buffer + index))
131
0
    {
132
0
      return FALSE;
133
0
    }
134
0
    index += hash_size;
135
0
  }
136
137
  /* get another hash block if some more output bytes are needed */
138
0
  len = out_len - index;
139
0
  if (len)
140
0
  {
141
0
    if (!get_next_block(this, this->buf))
142
0
    {
143
0
      return FALSE;
144
0
    }
145
0
    memcpy(buffer + index, this->buf, len);
146
0
    this->buf_index = len;
147
0
  }
148
149
0
  return TRUE;
150
0
}
151
152
METHOD(xof_t, allocate_bytes, bool,
153
  private_mgf1_xof_t *this, size_t out_len, chunk_t *chunk)
154
0
{
155
0
  *chunk = chunk_alloc(out_len);
156
157
0
  if (!get_bytes(this, out_len, chunk->ptr))
158
0
  {
159
0
    chunk_free(chunk);
160
0
    return FALSE;
161
0
  }
162
163
0
  return TRUE;
164
0
}
165
166
METHOD(xof_t, get_block_size, size_t,
167
  private_mgf1_xof_t *this)
168
0
{
169
0
  return this->hasher->get_hash_size(this->hasher);
170
0
}
171
172
METHOD(xof_t, get_seed_size, size_t,
173
  private_mgf1_xof_t *this)
174
0
{
175
0
  return this->hasher->get_hash_size(this->hasher);
176
0
}
177
178
METHOD(xof_t, set_seed, bool,
179
  private_mgf1_xof_t *this, chunk_t seed)
180
0
{
181
0
  size_t hash_size, state_len;
182
183
0
  if (seed.len == 0)
184
0
  {
185
0
    DBG1(DBG_LIB, "empty seed for MGF1");
186
0
    return FALSE;
187
0
  }
188
189
  /* determine state size and allocate space accordingly */
190
0
  hash_size = this->hasher->get_hash_size(this->hasher);
191
0
  state_len = (this->hash_seed ? hash_size : seed.len) + 4;
192
0
  chunk_clear(&this->state);
193
0
  this->state = chunk_alloc(state_len);
194
195
  /* hash block buffer is empty */
196
0
  this->buf_index = hash_size;
197
198
  /* reset counter */
199
0
  this->counter = 0;
200
201
  /* determine position of the 4 octet counter string */
202
0
  this->ctr_str = this->state.ptr + state_len - 4;
203
204
0
  if (this->hash_seed)
205
0
  {
206
0
    if (!this->hasher->get_hash(this->hasher, seed, this->state.ptr))
207
0
    {
208
0
      DBG1(DBG_LIB, "failed to hash seed for MGF1");
209
0
      return FALSE;
210
0
    }
211
0
  }
212
0
  else
213
0
  {
214
0
    memcpy(this->state.ptr, seed.ptr, seed.len);
215
0
  }
216
217
0
  return TRUE;
218
0
}
219
220
METHOD(xof_t, destroy, void,
221
  private_mgf1_xof_t *this)
222
0
{
223
0
  this->hasher->destroy(this->hasher);
224
0
  chunk_clear(&this->state);
225
0
  free(this);
226
0
}
227
228
METHOD(mgf1_t, set_hash_seed, void,
229
  private_mgf1_xof_t *this, bool yes)
230
0
{
231
0
  this->hash_seed = yes;
232
0
}
233
234
/*
235
 * Described in header.
236
 */
237
mgf1_xof_t *mgf1_xof_create(ext_out_function_t algorithm)
238
0
{
239
0
  private_mgf1_xof_t *this;
240
0
  hash_algorithm_t hash_alg;
241
0
  hasher_t *hasher;
242
243
0
  switch (algorithm)
244
0
  {
245
0
    case XOF_MGF1_SHA1:
246
0
      hash_alg = HASH_SHA1;
247
0
      break;
248
0
    case XOF_MGF1_SHA224:
249
0
      hash_alg = HASH_SHA224;
250
0
      break;
251
0
    case XOF_MGF1_SHA256:
252
0
      hash_alg = HASH_SHA256;
253
0
      break;
254
0
    case XOF_MGF1_SHA384:
255
0
      hash_alg = HASH_SHA384;
256
0
      break;
257
0
    case XOF_MGF1_SHA512:
258
0
      hash_alg = HASH_SHA512;
259
0
      break;
260
0
    default:
261
0
      return NULL;
262
0
  }
263
264
0
  hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
265
0
  if (!hasher)
266
0
  {
267
0
    DBG1(DBG_LIB, "failed to create %N hasher for MGF1",
268
0
       hash_algorithm_names, hash_alg);
269
0
    return NULL;
270
0
  }
271
272
0
  INIT(this,
273
0
    .public = {
274
0
      .mgf1_interface = {
275
0
        .xof_interface = {
276
0
          .get_type = _get_type,
277
0
          .get_bytes = _get_bytes,
278
0
          .allocate_bytes = _allocate_bytes,
279
0
          .get_block_size = _get_block_size,
280
0
          .get_seed_size = _get_seed_size,
281
0
          .set_seed = _set_seed,
282
0
          .destroy = _destroy,
283
0
        },
284
0
        .set_hash_seed = _set_hash_seed,
285
0
      },
286
0
    },
287
0
    .type = algorithm,
288
0
    .hasher = hasher,
289
0
  );
290
291
0
  return &this->public;
292
0
}