xref: /trunk/main/sal/rtl/source/random.c (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #define _RTL_RANDOM_C_ "$Revision: 1.6 $"
29 
30 #include <sal/types.h>
31 #include <osl/thread.h>
32 #include <osl/time.h>
33 #include <rtl/alloc.h>
34 #include <rtl/digest.h>
35 #include <rtl/random.h>
36 #include <osl/time.h>
37 
38 /*========================================================================
39  *
40  * rtlRandom internals.
41  *
42  *======================================================================*/
43 #define RTL_RANDOM_RNG_1(a) ((a) * 16807L)
44 #define RTL_RANDOM_RNG_2(a) ((a) * 65539L)
45 
46 #define RTL_RANDOM_RNG(x, y, z) \
47 { \
48 	(x) = 170 * ((x) % 178) - 63 * ((x) / 178); \
49 	if ((x) < 0) (x) += 30328L; \
50 	\
51 	(y) = 171 * ((y) % 177) -  2 * ((y) / 177); \
52 	if ((y) < 0) (y) += 30269L; \
53 	\
54 	(z) = 172 * ((z) % 176) - 35 * ((z) / 176); \
55 	if ((z) < 0) (z) += 30307L; \
56 }
57 
58 /** RandomData_Impl.
59  */
60 typedef struct random_data_impl_st
61 {
62 	sal_Int16 m_nX;
63 	sal_Int16 m_nY;
64 	sal_Int16 m_nZ;
65 } RandomData_Impl;
66 
67 /** __rtl_random_data.
68  */
69 static double __rtl_random_data (RandomData_Impl *pImpl);
70 
71 /** RandomPool_Impl.
72  */
73 #define RTL_RANDOM_DIGEST      rtl_Digest_AlgorithmMD5
74 #define RTL_RANDOM_SIZE_DIGEST RTL_DIGEST_LENGTH_MD5
75 #define RTL_RANDOM_SIZE_POOL   1023
76 
77 typedef struct random_pool_impl_st
78 {
79 	rtlDigest  m_hDigest;
80 	sal_uInt8  m_pDigest[RTL_RANDOM_SIZE_DIGEST];
81 	sal_uInt8  m_pData[RTL_RANDOM_SIZE_POOL + 1];
82 	sal_uInt32 m_nData;
83 	sal_uInt32 m_nIndex;
84 	sal_uInt32 m_nCount;
85 } RandomPool_Impl;
86 
87 /** __rtl_random_initPool.
88  */
89 static sal_Bool __rtl_random_initPool (
90 	RandomPool_Impl *pImpl);
91 
92 /** __rtl_random_seedPool.
93  */
94 static void __rtl_random_seedPool (
95 	RandomPool_Impl *pImpl, const sal_uInt8 *pBuffer, sal_Size nBufLen);
96 
97 /** __rtl_random_readPool.
98  */
99 static void __rtl_random_readPool (
100 	RandomPool_Impl *pImpl, sal_uInt8 *pBuffer, sal_Size nBufLen);
101 
102 /*
103  * __rtl_random_data.
104  */
105 static double __rtl_random_data (RandomData_Impl *pImpl)
106 {
107 	register double random;
108 
109 	RTL_RANDOM_RNG (pImpl->m_nX, pImpl->m_nY, pImpl->m_nZ);
110 	random = (((double)(pImpl->m_nX) / 30328.0) +
111 			  ((double)(pImpl->m_nY) / 30269.0) +
112 			  ((double)(pImpl->m_nZ) / 30307.0)   );
113 
114 	random -= ((double)((sal_uInt32)(random)));
115 	return (random);
116 }
117 
118 /*
119  * __rtl_random_initPool.
120  */
121 static sal_Bool __rtl_random_initPool (RandomPool_Impl *pImpl)
122 {
123 	pImpl->m_hDigest = rtl_digest_create (RTL_RANDOM_DIGEST);
124 	if (pImpl->m_hDigest)
125 	{
126 		oslThreadIdentifier id;
127 		TimeValue           tv;
128 		RandomData_Impl     rd;
129 		double              seed;
130 
131         /* The use of uninitialized stack variables as a way to
132          * enhance the entropy of the random pool triggers
133          * memory checkers like purify and valgrind.
134          */
135 
136         /*
137 		__rtl_random_seedPool (pImpl, (sal_uInt8*)&id, sizeof(id));
138 		__rtl_random_seedPool (pImpl, (sal_uInt8*)&tv, sizeof(tv));
139 		__rtl_random_seedPool (pImpl, (sal_uInt8*)&rd, sizeof(rd));
140         */
141 
142 		id = osl_getThreadIdentifier (NULL);
143 		id = RTL_RANDOM_RNG_2(RTL_RANDOM_RNG_1(id));
144 		__rtl_random_seedPool (pImpl, (sal_uInt8*)&id, sizeof(id));
145 
146 		osl_getSystemTime (&tv);
147 		tv.Seconds = RTL_RANDOM_RNG_2(tv.Seconds);
148 		tv.Nanosec = RTL_RANDOM_RNG_2(tv.Nanosec);
149 		__rtl_random_seedPool (pImpl, (sal_uInt8*)&tv, sizeof(tv));
150 
151 		rd.m_nX = (sal_Int16)(((id         >> 1) << 1) + 1);
152 		rd.m_nY = (sal_Int16)(((tv.Seconds >> 1) << 1) + 1);
153 		rd.m_nZ = (sal_Int16)(((tv.Nanosec >> 1) << 1) + 1);
154 		__rtl_random_seedPool (pImpl, (sal_uInt8*)&rd, sizeof(rd));
155 
156 		while (pImpl->m_nData < RTL_RANDOM_SIZE_POOL)
157 		{
158 			seed = __rtl_random_data (&rd);
159 			__rtl_random_seedPool (pImpl, (sal_uInt8*)&seed, sizeof(seed));
160 		}
161 		return sal_True;
162 	}
163 	return sal_False;
164 }
165 
166 /*
167  * __rtl_random_seedPool.
168  */
169 static void __rtl_random_seedPool (
170 	RandomPool_Impl *pImpl, const sal_uInt8 *pBuffer, sal_Size nBufLen)
171 {
172 	sal_Size i;
173 	sal_sSize  j, k;
174 
175 	for (i = 0; i < nBufLen; i += RTL_RANDOM_SIZE_DIGEST)
176 	{
177 		j = nBufLen - i;
178 		if (j > RTL_RANDOM_SIZE_DIGEST)
179 			j = RTL_RANDOM_SIZE_DIGEST;
180 
181 		rtl_digest_update (
182 			pImpl->m_hDigest, pImpl->m_pDigest, RTL_RANDOM_SIZE_DIGEST);
183 
184 		k = (pImpl->m_nIndex + j) - RTL_RANDOM_SIZE_POOL;
185 		if (k > 0)
186 		{
187 			rtl_digest_update (
188 				pImpl->m_hDigest, &(pImpl->m_pData[pImpl->m_nIndex]), j - k);
189 			rtl_digest_update (
190 				pImpl->m_hDigest, &(pImpl->m_pData[0]), k);
191 		}
192 		else
193 		{
194 			rtl_digest_update (
195 				pImpl->m_hDigest, &(pImpl->m_pData[pImpl->m_nIndex]), j);
196 		}
197 
198 		rtl_digest_update (pImpl->m_hDigest, pBuffer, j);
199 		pBuffer += j;
200 
201 		rtl_digest_get (
202 			pImpl->m_hDigest, pImpl->m_pDigest, RTL_RANDOM_SIZE_DIGEST);
203 		for (k = 0; k < j; k++)
204 		{
205 			pImpl->m_pData[pImpl->m_nIndex++] ^= pImpl->m_pDigest[k];
206 			if (pImpl->m_nIndex >= RTL_RANDOM_SIZE_POOL)
207 			{
208 				pImpl->m_nData  = RTL_RANDOM_SIZE_POOL;
209 				pImpl->m_nIndex = 0;
210 			}
211 		}
212 	}
213 
214 	if (pImpl->m_nIndex > pImpl->m_nData)
215 		pImpl->m_nData = pImpl->m_nIndex;
216 }
217 
218 /*
219  * __rtl_random_readPool.
220  */
221 static void __rtl_random_readPool (
222 	RandomPool_Impl *pImpl, sal_uInt8 *pBuffer, sal_Size nBufLen)
223 {
224 	sal_Int32 j, k;
225 
226 	while (nBufLen > 0)
227 	{
228 		j = nBufLen;
229 		if (j > RTL_RANDOM_SIZE_DIGEST/2)
230 			j = RTL_RANDOM_SIZE_DIGEST/2;
231 		nBufLen -= j;
232 
233 		rtl_digest_update (
234 			pImpl->m_hDigest,
235 			&(pImpl->m_pDigest[RTL_RANDOM_SIZE_DIGEST/2]),
236 			RTL_RANDOM_SIZE_DIGEST/2);
237 
238 		k = (pImpl->m_nIndex + j) - pImpl->m_nData;
239 		if (k > 0)
240 		{
241 			rtl_digest_update (
242 				pImpl->m_hDigest, &(pImpl->m_pData[pImpl->m_nIndex]), j - k);
243 			rtl_digest_update (
244 				pImpl->m_hDigest, &(pImpl->m_pData[0]), k);
245 		}
246 		else
247 		{
248 			rtl_digest_update (
249 				pImpl->m_hDigest, &(pImpl->m_pData[pImpl->m_nIndex]), j);
250 		}
251 
252 		rtl_digest_get (
253 			pImpl->m_hDigest, pImpl->m_pDigest, RTL_RANDOM_SIZE_DIGEST);
254 		for (k = 0; k < j; k++)
255 		{
256 			if (pImpl->m_nIndex >= pImpl->m_nData) pImpl->m_nIndex = 0;
257 			pImpl->m_pData[pImpl->m_nIndex++] ^= pImpl->m_pDigest[k];
258 			*pBuffer++ = pImpl->m_pDigest[k + RTL_RANDOM_SIZE_DIGEST/2];
259 		}
260 	}
261 
262 	pImpl->m_nCount++;
263 	rtl_digest_update (
264 		pImpl->m_hDigest, &(pImpl->m_nCount), sizeof(pImpl->m_nCount));
265 	rtl_digest_update (
266 		pImpl->m_hDigest, pImpl->m_pDigest, RTL_RANDOM_SIZE_DIGEST);
267 	rtl_digest_get (
268 		pImpl->m_hDigest, pImpl->m_pDigest, RTL_RANDOM_SIZE_DIGEST);
269 }
270 
271 /*========================================================================
272  *
273  * rtlRandom implementation.
274  *
275  *======================================================================*/
276 /*
277  * rtl_random_createPool.
278  */
279 rtlRandomPool SAL_CALL rtl_random_createPool (void)
280 {
281 	RandomPool_Impl *pImpl = (RandomPool_Impl*)NULL;
282 	pImpl = (RandomPool_Impl*)rtl_allocateZeroMemory (sizeof(RandomPool_Impl));
283 	if (pImpl)
284 	{
285 		if (!__rtl_random_initPool (pImpl))
286 		{
287 			rtl_freeZeroMemory (pImpl, sizeof(RandomPool_Impl));
288 			pImpl = (RandomPool_Impl*)NULL;
289 		}
290 	}
291 	return ((rtlRandomPool)pImpl);
292 }
293 
294 /*
295  * rtl_random_destroyPool.
296  */
297 void SAL_CALL rtl_random_destroyPool (rtlRandomPool Pool)
298 {
299 	RandomPool_Impl *pImpl = (RandomPool_Impl *)Pool;
300 	if (pImpl)
301 	{
302 		rtl_digest_destroy (pImpl->m_hDigest);
303 		rtl_freeZeroMemory (pImpl, sizeof (RandomPool_Impl));
304 	}
305 }
306 
307 /*
308  * rtl_random_addBytes.
309  */
310 rtlRandomError SAL_CALL rtl_random_addBytes (
311 	rtlRandomPool Pool, const void *Buffer, sal_Size Bytes)
312 {
313 	RandomPool_Impl *pImpl   = (RandomPool_Impl *)Pool;
314 	const sal_uInt8 *pBuffer = (const sal_uInt8 *)Buffer;
315 
316 	if ((pImpl == NULL) || (pBuffer == NULL))
317 		return rtl_Random_E_Argument;
318 
319 	__rtl_random_seedPool (pImpl, pBuffer, Bytes);
320 	return rtl_Random_E_None;
321 }
322 
323 /*
324  * rtl_random_getBytes.
325  */
326 rtlRandomError SAL_CALL rtl_random_getBytes (
327 	rtlRandomPool Pool, void *Buffer, sal_Size Bytes)
328 {
329 	RandomPool_Impl *pImpl   = (RandomPool_Impl *)Pool;
330 	sal_uInt8       *pBuffer = (sal_uInt8 *)Buffer;
331 
332 	if ((pImpl == NULL) || (pBuffer == NULL))
333 		return rtl_Random_E_Argument;
334 
335 	__rtl_random_readPool (pImpl, pBuffer, Bytes);
336 	return rtl_Random_E_None;
337 }
338 
339