xref: /AOO41X/main/sal/rtl/source/random.c (revision 647f063d49501903f1667b75f5634541fc603283)
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: 1.6 $"
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