1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: random.c,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #define _RTL_RANDOM_C_ "$Revision: 1.6 $"
33 #include <sal/types.h>
34 #include <osl/thread.h>
36 #include <rtl/alloc.h>
37 #include <rtl/digest.h>
38 #include <rtl/random.h>
41 /*========================================================================
43 * rtlRandom internals.
45 *======================================================================*/
46 #define RTL_RANDOM_RNG_1(a) ((a) * 16807L)
47 #define RTL_RANDOM_RNG_2(a) ((a) * 65539L)
49 #define RTL_RANDOM_RNG(x, y, z) \
51 (x) = 170 * ((x) % 178) - 63 * ((x) / 178); \
52 if ((x) < 0) (x) += 30328L; \
54 (y) = 171 * ((y) % 177) - 2 * ((y) / 177); \
55 if ((y) < 0) (y) += 30269L; \
57 (z) = 172 * ((z) % 176) - 35 * ((z) / 176); \
58 if ((z) < 0) (z) += 30307L; \
63 typedef struct random_data_impl_st
70 /** __rtl_random_data.
72 static double __rtl_random_data (RandomData_Impl
*pImpl
);
76 #define RTL_RANDOM_DIGEST rtl_Digest_AlgorithmMD5
77 #define RTL_RANDOM_SIZE_DIGEST RTL_DIGEST_LENGTH_MD5
78 #define RTL_RANDOM_SIZE_POOL 1023
80 typedef struct random_pool_impl_st
83 sal_uInt8 m_pDigest
[RTL_RANDOM_SIZE_DIGEST
];
84 sal_uInt8 m_pData
[RTL_RANDOM_SIZE_POOL
+ 1];
90 /** __rtl_random_initPool.
92 static sal_Bool
__rtl_random_initPool (
93 RandomPool_Impl
*pImpl
);
95 /** __rtl_random_seedPool.
97 static void __rtl_random_seedPool (
98 RandomPool_Impl
*pImpl
, const sal_uInt8
*pBuffer
, sal_Size nBufLen
);
100 /** __rtl_random_readPool.
102 static void __rtl_random_readPool (
103 RandomPool_Impl
*pImpl
, sal_uInt8
*pBuffer
, sal_Size nBufLen
);
108 static double __rtl_random_data (RandomData_Impl
*pImpl
)
110 register double random
;
112 RTL_RANDOM_RNG (pImpl
->m_nX
, pImpl
->m_nY
, pImpl
->m_nZ
);
113 random
= (((double)(pImpl
->m_nX
) / 30328.0) +
114 ((double)(pImpl
->m_nY
) / 30269.0) +
115 ((double)(pImpl
->m_nZ
) / 30307.0) );
117 random
-= ((double)((sal_uInt32
)(random
)));
122 * __rtl_random_initPool.
124 static sal_Bool
__rtl_random_initPool (RandomPool_Impl
*pImpl
)
126 pImpl
->m_hDigest
= rtl_digest_create (RTL_RANDOM_DIGEST
);
127 if (pImpl
->m_hDigest
)
129 oslThreadIdentifier id
;
134 /* The use of uninitialized stack variables as a way to
135 * enhance the entropy of the random pool triggers
136 * memory checkers like purify and valgrind.
140 __rtl_random_seedPool (pImpl, (sal_uInt8*)&id, sizeof(id));
141 __rtl_random_seedPool (pImpl, (sal_uInt8*)&tv, sizeof(tv));
142 __rtl_random_seedPool (pImpl, (sal_uInt8*)&rd, sizeof(rd));
145 id
= osl_getThreadIdentifier (NULL
);
146 id
= RTL_RANDOM_RNG_2(RTL_RANDOM_RNG_1(id
));
147 __rtl_random_seedPool (pImpl
, (sal_uInt8
*)&id
, sizeof(id
));
149 osl_getSystemTime (&tv
);
150 tv
.Seconds
= RTL_RANDOM_RNG_2(tv
.Seconds
);
151 tv
.Nanosec
= RTL_RANDOM_RNG_2(tv
.Nanosec
);
152 __rtl_random_seedPool (pImpl
, (sal_uInt8
*)&tv
, sizeof(tv
));
154 rd
.m_nX
= (sal_Int16
)(((id
>> 1) << 1) + 1);
155 rd
.m_nY
= (sal_Int16
)(((tv
.Seconds
>> 1) << 1) + 1);
156 rd
.m_nZ
= (sal_Int16
)(((tv
.Nanosec
>> 1) << 1) + 1);
157 __rtl_random_seedPool (pImpl
, (sal_uInt8
*)&rd
, sizeof(rd
));
159 while (pImpl
->m_nData
< RTL_RANDOM_SIZE_POOL
)
161 seed
= __rtl_random_data (&rd
);
162 __rtl_random_seedPool (pImpl
, (sal_uInt8
*)&seed
, sizeof(seed
));
170 * __rtl_random_seedPool.
172 static void __rtl_random_seedPool (
173 RandomPool_Impl
*pImpl
, const sal_uInt8
*pBuffer
, sal_Size nBufLen
)
178 for (i
= 0; i
< nBufLen
; i
+= RTL_RANDOM_SIZE_DIGEST
)
181 if (j
> RTL_RANDOM_SIZE_DIGEST
)
182 j
= RTL_RANDOM_SIZE_DIGEST
;
185 pImpl
->m_hDigest
, pImpl
->m_pDigest
, RTL_RANDOM_SIZE_DIGEST
);
187 k
= (pImpl
->m_nIndex
+ j
) - RTL_RANDOM_SIZE_POOL
;
191 pImpl
->m_hDigest
, &(pImpl
->m_pData
[pImpl
->m_nIndex
]), j
- k
);
193 pImpl
->m_hDigest
, &(pImpl
->m_pData
[0]), k
);
198 pImpl
->m_hDigest
, &(pImpl
->m_pData
[pImpl
->m_nIndex
]), j
);
201 rtl_digest_update (pImpl
->m_hDigest
, pBuffer
, j
);
205 pImpl
->m_hDigest
, pImpl
->m_pDigest
, RTL_RANDOM_SIZE_DIGEST
);
206 for (k
= 0; k
< j
; k
++)
208 pImpl
->m_pData
[pImpl
->m_nIndex
++] ^= pImpl
->m_pDigest
[k
];
209 if (pImpl
->m_nIndex
>= RTL_RANDOM_SIZE_POOL
)
211 pImpl
->m_nData
= RTL_RANDOM_SIZE_POOL
;
217 if (pImpl
->m_nIndex
> pImpl
->m_nData
)
218 pImpl
->m_nData
= pImpl
->m_nIndex
;
222 * __rtl_random_readPool.
224 static void __rtl_random_readPool (
225 RandomPool_Impl
*pImpl
, sal_uInt8
*pBuffer
, sal_Size nBufLen
)
232 if (j
> RTL_RANDOM_SIZE_DIGEST
/2)
233 j
= RTL_RANDOM_SIZE_DIGEST
/2;
238 &(pImpl
->m_pDigest
[RTL_RANDOM_SIZE_DIGEST
/2]),
239 RTL_RANDOM_SIZE_DIGEST
/2);
241 k
= (pImpl
->m_nIndex
+ j
) - pImpl
->m_nData
;
245 pImpl
->m_hDigest
, &(pImpl
->m_pData
[pImpl
->m_nIndex
]), j
- k
);
247 pImpl
->m_hDigest
, &(pImpl
->m_pData
[0]), k
);
252 pImpl
->m_hDigest
, &(pImpl
->m_pData
[pImpl
->m_nIndex
]), j
);
256 pImpl
->m_hDigest
, pImpl
->m_pDigest
, RTL_RANDOM_SIZE_DIGEST
);
257 for (k
= 0; k
< j
; k
++)
259 if (pImpl
->m_nIndex
>= pImpl
->m_nData
) pImpl
->m_nIndex
= 0;
260 pImpl
->m_pData
[pImpl
->m_nIndex
++] ^= pImpl
->m_pDigest
[k
];
261 *pBuffer
++ = pImpl
->m_pDigest
[k
+ RTL_RANDOM_SIZE_DIGEST
/2];
267 pImpl
->m_hDigest
, &(pImpl
->m_nCount
), sizeof(pImpl
->m_nCount
));
269 pImpl
->m_hDigest
, pImpl
->m_pDigest
, RTL_RANDOM_SIZE_DIGEST
);
271 pImpl
->m_hDigest
, pImpl
->m_pDigest
, RTL_RANDOM_SIZE_DIGEST
);
274 /*========================================================================
276 * rtlRandom implementation.
278 *======================================================================*/
280 * rtl_random_createPool.
282 rtlRandomPool SAL_CALL
rtl_random_createPool (void)
284 RandomPool_Impl
*pImpl
= (RandomPool_Impl
*)NULL
;
285 pImpl
= (RandomPool_Impl
*)rtl_allocateZeroMemory (sizeof(RandomPool_Impl
));
288 if (!__rtl_random_initPool (pImpl
))
290 rtl_freeZeroMemory (pImpl
, sizeof(RandomPool_Impl
));
291 pImpl
= (RandomPool_Impl
*)NULL
;
294 return ((rtlRandomPool
)pImpl
);
298 * rtl_random_destroyPool.
300 void SAL_CALL
rtl_random_destroyPool (rtlRandomPool Pool
)
302 RandomPool_Impl
*pImpl
= (RandomPool_Impl
*)Pool
;
305 rtl_digest_destroy (pImpl
->m_hDigest
);
306 rtl_freeZeroMemory (pImpl
, sizeof (RandomPool_Impl
));
311 * rtl_random_addBytes.
313 rtlRandomError SAL_CALL
rtl_random_addBytes (
314 rtlRandomPool Pool
, const void *Buffer
, sal_Size Bytes
)
316 RandomPool_Impl
*pImpl
= (RandomPool_Impl
*)Pool
;
317 const sal_uInt8
*pBuffer
= (const sal_uInt8
*)Buffer
;
319 if ((pImpl
== NULL
) || (pBuffer
== NULL
))
320 return rtl_Random_E_Argument
;
322 __rtl_random_seedPool (pImpl
, pBuffer
, Bytes
);
323 return rtl_Random_E_None
;
327 * rtl_random_getBytes.
329 rtlRandomError SAL_CALL
rtl_random_getBytes (
330 rtlRandomPool Pool
, void *Buffer
, sal_Size Bytes
)
332 RandomPool_Impl
*pImpl
= (RandomPool_Impl
*)Pool
;
333 sal_uInt8
*pBuffer
= (sal_uInt8
*)Buffer
;
335 if ((pImpl
== NULL
) || (pBuffer
== NULL
))
336 return rtl_Random_E_Argument
;
338 __rtl_random_readPool (pImpl
, pBuffer
, Bytes
);
339 return rtl_Random_E_None
;