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