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