Streamlined DRBG and MGF1 debug output
[strongswan.git] / src / libstrongswan / plugins / ntru / ntru_mgf1.c
1 /*
2 * Copyright (C) 2013 Andreas Steffen
3 * HSR 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
16 #include "ntru_mgf1.h"
17
18 #include <crypto/hashers/hasher.h>
19 #include <utils/debug.h>
20 #include <utils/test.h>
21
22 typedef struct private_ntru_mgf1_t private_ntru_mgf1_t;
23
24 /**
25 * Private data of an ntru_mgf1_t object.
26 */
27 struct private_ntru_mgf1_t {
28
29 /**
30 * Public ntru_mgf1_t interface.
31 */
32 ntru_mgf1_t public;
33
34 /**
35 * Hasher the MGF1 Mask Generation Function is based on
36 */
37 hasher_t *hasher;
38
39 /**
40 * Counter
41 */
42 u_int32_t counter;
43
44 /**
45 * Set if counter has reached 2^32
46 */
47 bool overflow;
48
49 /**
50 * Current state to be hashed
51 */
52 chunk_t state;
53
54 /**
55 * Position of the 4 octet counter string
56 */
57 u_char *ctr_str;
58
59 };
60
61 METHOD(ntru_mgf1_t, get_hash_size, size_t,
62 private_ntru_mgf1_t *this)
63 {
64 return this->hasher->get_hash_size(this->hasher);
65 }
66
67 METHOD(ntru_mgf1_t, get_mask, bool,
68 private_ntru_mgf1_t *this, size_t mask_len, u_char *mask)
69 {
70 u_char buf[HASH_SIZE_SHA512];
71 size_t len;
72
73 while (mask_len > 0)
74 {
75 /* detect overflow, set counter string and increment counter */
76 if (this->overflow)
77 {
78 return FALSE;
79 }
80 htoun32(this->ctr_str, this->counter++);
81 if (this->counter == 0)
82 {
83 this->overflow = TRUE;
84 }
85
86 if (!this->hasher->get_hash(this->hasher, this->state, buf))
87 {
88 return FALSE;
89 }
90
91 len = min(mask_len, this->hasher->get_hash_size(this->hasher));
92 memcpy(mask, buf, len);
93 mask_len -= len;
94 mask += len;
95 }
96
97 return TRUE;
98 }
99
100 METHOD(ntru_mgf1_t, allocate_mask, bool,
101 private_ntru_mgf1_t *this, size_t mask_len, chunk_t *mask)
102 {
103 if (mask_len == 0)
104 {
105 *mask = chunk_empty;
106 return TRUE;
107 }
108 *mask = chunk_alloc(mask_len);
109
110 return get_mask(this, mask_len, mask->ptr);
111 }
112
113 METHOD(ntru_mgf1_t, destroy, void,
114 private_ntru_mgf1_t *this)
115 {
116 this->hasher->destroy(this->hasher);
117 chunk_clear(&this->state);
118 free(this);
119 }
120
121 /*
122 * Described in header.
123 */
124 ntru_mgf1_t *ntru_mgf1_create(hash_algorithm_t alg, chunk_t seed,
125 bool hash_seed)
126 {
127 private_ntru_mgf1_t *this;
128 hasher_t *hasher;
129 size_t state_len;
130
131 if (seed.len == 0)
132 {
133 DBG1(DBG_LIB, "empty seed for MGF1");
134 return NULL;
135 }
136
137 hasher = lib->crypto->create_hasher(lib->crypto, alg);
138 if (!hasher)
139 {
140 DBG1(DBG_LIB, "failed to create %N hasher for MGF1",
141 hash_algorithm_names, alg);
142 return NULL;
143 }
144 state_len = (hash_seed ? hasher->get_hash_size(hasher) : seed.len) + 4;
145
146 INIT(this,
147 .public = {
148 .get_hash_size = _get_hash_size,
149 .allocate_mask = _allocate_mask,
150 .get_mask = _get_mask,
151 .destroy = _destroy,
152 },
153 .hasher = hasher,
154 .state = chunk_alloc(state_len),
155 );
156
157 /* determine position of the 4 octet counter string */
158 this->ctr_str = this->state.ptr + state_len - 4;
159
160 if (hash_seed)
161 {
162 if (!hasher->get_hash(hasher, seed, this->state.ptr))
163 {
164 DBG1(DBG_LIB, "failed to hash seed for MGF1");
165 destroy(this);
166 return NULL;
167 }
168 }
169 else
170 {
171 memcpy(this->state.ptr, seed.ptr, seed.len);
172 }
173
174 return &this->public;
175 }
176
177 EXPORT_FUNCTION_FOR_TESTS(ntru, ntru_mgf1_create);