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