1 /*
2 * Copyright (c) 1998, 1999, 2000, 2002 X-Way Rights BV
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 */
19
20 /*!\file fips186.c
21 * \brief FIPS 186 pseudo-random number generator.
22 * \author Bob Deblier <bob.deblier@telenet.be>
23 * \ingroup PRNG_m PRNG_fips186_m
24 */
25
26 #define BEECRYPT_DLL_EXPORT
27
28 #if HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include "beecrypt/fips186.h"
33
34 /*!\addtogroup PRNG_fips186_m
35 * \{
36 */
37
38 static uint32_t fips186hinit[5] = { 0xefcdab89U, 0x98badcfeU, 0x10325476U, 0xc3d2e1f0U, 0x67452301U };
39
40 const randomGenerator fips186prng = {
41 "FIPS 186",
42 sizeof(fips186Param),
43 (randomGeneratorSetup) fips186Setup,
44 (randomGeneratorSeed) fips186Seed,
45 (randomGeneratorNext) fips186Next,
46 (randomGeneratorCleanup) fips186Cleanup
47 };
48
fips186init(register sha1Param * p)49 static int fips186init(register sha1Param* p)
50 {
51 memcpy(p->h, fips186hinit, 5 * sizeof(uint32_t));
52 return 0;
53 }
54
fips186Setup(fips186Param * fp)55 int fips186Setup(fips186Param* fp)
56 {
57 if (fp)
58 {
59 #ifdef _REENTRANT
60 # if WIN32
61 if (!(fp->lock = CreateMutex(NULL, FALSE, NULL)))
62 return -1;
63 # else
64 # if HAVE_THREAD_H && HAVE_SYNCH_H
65 if (mutex_init(&fp->lock, USYNC_THREAD, (void *) 0))
66 return -1;
67 # elif HAVE_PTHREAD_H
68 if (pthread_mutex_init(&fp->lock, (pthread_mutexattr_t *) 0))
69 return -1;
70 # endif
71 # endif
72 #endif
73
74 fp->digestremain = 0;
75
76 return entropyGatherNext((byte*) fp->state, MP_WORDS_TO_BYTES(FIPS186_STATE_SIZE));
77 }
78 return -1;
79 }
80
fips186Seed(fips186Param * fp,const byte * data,size_t size)81 int fips186Seed(fips186Param* fp, const byte* data, size_t size)
82 {
83 if (fp)
84 {
85 #ifdef _REENTRANT
86 # if WIN32
87 if (WaitForSingleObject(fp->lock, INFINITE) != WAIT_OBJECT_0)
88 return -1;
89 # else
90 # if HAVE_THREAD_H && HAVE_SYNCH_H
91 if (mutex_lock(&fp->lock))
92 return -1;
93 # elif HAVE_PTHREAD_H
94 if (pthread_mutex_lock(&fp->lock))
95 return -1;
96 # endif
97 # endif
98 #endif
99 if (data)
100 {
101 mpw seed[FIPS186_STATE_SIZE];
102
103 /* if there's too much data, cut off at what we can deal with */
104 if (size > MP_WORDS_TO_BYTES(FIPS186_STATE_SIZE))
105 size = MP_WORDS_TO_BYTES(FIPS186_STATE_SIZE);
106
107 /* convert to multi-precision integer, and add to the state */
108 if (os2ip(seed, FIPS186_STATE_SIZE, data, size) == 0)
109 mpadd(FIPS186_STATE_SIZE, fp->state, seed);
110 }
111 #ifdef _REENTRANT
112 # if WIN32
113 if (!ReleaseMutex(fp->lock))
114 return -1;
115 # else
116 # if HAVE_THREAD_H && HAVE_SYNCH_H
117 if (mutex_unlock(&fp->lock))
118 return -1;
119 # elif HAVE_PTHREAD_H
120 if (pthread_mutex_unlock(&fp->lock))
121 return -1;
122 # endif
123 # endif
124 #endif
125 return 0;
126 }
127 return -1;
128 }
129
fips186Next(fips186Param * fp,byte * data,size_t size)130 int fips186Next(fips186Param* fp, byte* data, size_t size)
131 {
132 if (fp)
133 {
134 mpw dig[FIPS186_STATE_SIZE];
135
136 #ifdef _REENTRANT
137 # if WIN32
138 if (WaitForSingleObject(fp->lock, INFINITE) != WAIT_OBJECT_0)
139 return -1;
140 # else
141 # if HAVE_THREAD_H && HAVE_SYNCH_H
142 if (mutex_lock(&fp->lock))
143 return -1;
144 # elif HAVE_PTHREAD_H
145 if (pthread_mutex_lock(&fp->lock))
146 return -1;
147 # endif
148 # endif
149 #endif
150
151 while (size > 0)
152 {
153 register size_t copy;
154
155 if (fp->digestremain == 0)
156 {
157 fips186init(&fp->param);
158 /* copy the 512 bits of state data into the sha1Param */
159 memcpy(fp->param.data, fp->state, MP_WORDS_TO_BYTES(FIPS186_STATE_SIZE));
160 /* process the data */
161 sha1Process(&fp->param);
162
163 #if WORDS_BIGENDIAN
164 memcpy(fp->digest, fp->param.h, 20);
165 #else
166 /* encode 5 integers big-endian style */
167 fp->digest[ 0] = (byte)(fp->param.h[0] >> 24);
168 fp->digest[ 1] = (byte)(fp->param.h[0] >> 16);
169 fp->digest[ 2] = (byte)(fp->param.h[0] >> 8);
170 fp->digest[ 3] = (byte)(fp->param.h[0] >> 0);
171 fp->digest[ 4] = (byte)(fp->param.h[1] >> 24);
172 fp->digest[ 5] = (byte)(fp->param.h[1] >> 16);
173 fp->digest[ 6] = (byte)(fp->param.h[1] >> 8);
174 fp->digest[ 7] = (byte)(fp->param.h[1] >> 0);
175 fp->digest[ 8] = (byte)(fp->param.h[2] >> 24);
176 fp->digest[ 9] = (byte)(fp->param.h[2] >> 16);
177 fp->digest[10] = (byte)(fp->param.h[2] >> 8);
178 fp->digest[11] = (byte)(fp->param.h[2] >> 0);
179 fp->digest[12] = (byte)(fp->param.h[3] >> 24);
180 fp->digest[13] = (byte)(fp->param.h[3] >> 16);
181 fp->digest[14] = (byte)(fp->param.h[3] >> 8);
182 fp->digest[15] = (byte)(fp->param.h[3] >> 0);
183 fp->digest[16] = (byte)(fp->param.h[4] >> 24);
184 fp->digest[17] = (byte)(fp->param.h[4] >> 16);
185 fp->digest[18] = (byte)(fp->param.h[4] >> 8);
186 fp->digest[19] = (byte)(fp->param.h[4] >> 0);
187 #endif
188
189 if (os2ip(dig, FIPS186_STATE_SIZE, fp->digest, 20) == 0)
190 {
191 /* set state to state + digest + 1 mod 2^512 */
192 mpadd (FIPS186_STATE_SIZE, fp->state, dig);
193 mpaddw(FIPS186_STATE_SIZE, fp->state, 1);
194 }
195 /* else shouldn't occur */
196 /* we now have 5 words of pseudo-random data */
197 fp->digestremain = 20;
198 }
199 copy = (size > fp->digestremain) ? fp->digestremain : size;
200 memcpy(data, fp->digest+20-fp->digestremain, copy);
201 fp->digestremain -= copy;
202 size -= copy;
203 data += copy;
204 }
205 #ifdef _REENTRANT
206 # if WIN32
207 if (!ReleaseMutex(fp->lock))
208 return -1;
209 # else
210 # if HAVE_THREAD_H && HAVE_SYNCH_H
211 if (mutex_unlock(&fp->lock))
212 return -1;
213 # elif HAVE_PTHREAD_H
214 if (pthread_mutex_unlock(&fp->lock))
215 return -1;
216 # endif
217 # endif
218 #endif
219 return 0;
220 }
221 return -1;
222 }
223
fips186Cleanup(fips186Param * fp)224 int fips186Cleanup(fips186Param* fp)
225 {
226 if (fp)
227 {
228 #ifdef _REENTRANT
229 # if WIN32
230 if (!CloseHandle(fp->lock))
231 return -1;
232 # else
233 # if HAVE_THREAD_H && HAVE_SYNCH_H
234 if (mutex_destroy(&fp->lock))
235 return -1;
236 # elif HAVE_PTHREAD_H
237 if (pthread_mutex_destroy(&fp->lock))
238 return -1;
239 # endif
240 # endif
241 #endif
242 return 0;
243 }
244 return -1;
245 }
246
247 /*!\}
248 */
249