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