1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/types.h>
21 #include <osl/thread.h>
23 #include <rtl/alloc.h>
24 #include <rtl/digest.h>
25 #include <rtl/random.h>
27 /*========================================================================
29 * rtlRandom internals.
31 *======================================================================*/
32 #define RTL_RANDOM_RNG_1(a) ((a) * 16807L)
33 #define RTL_RANDOM_RNG_2(a) ((a) * 65539L)
35 #define RTL_RANDOM_RNG(x, y, z) \
37 (x) = 170 * ((x) % 178) - 63 * ((x) / 178); \
38 if ((x) < 0) (x) += 30328L; \
40 (y) = 171 * ((y) % 177) - 2 * ((y) / 177); \
41 if ((y) < 0) (y) += 30269L; \
43 (z) = 172 * ((z) % 176) - 35 * ((z) / 176); \
44 if ((z) < 0) (z) += 30307L; \
49 struct RandomData_Impl
56 /** __rtl_random_data.
58 static double __rtl_random_data (RandomData_Impl
*pImpl
);
62 #define RTL_RANDOM_DIGEST rtl_Digest_AlgorithmMD5
63 #define RTL_RANDOM_SIZE_DIGEST RTL_DIGEST_LENGTH_MD5
64 #define RTL_RANDOM_SIZE_POOL 1023
66 struct RandomPool_Impl
69 sal_uInt8 m_pDigest
[RTL_RANDOM_SIZE_DIGEST
];
70 sal_uInt8 m_pData
[RTL_RANDOM_SIZE_POOL
+ 1];
76 /** __rtl_random_initPool.
78 static sal_Bool
__rtl_random_initPool (
79 RandomPool_Impl
*pImpl
);
81 /** __rtl_random_seedPool.
83 static void __rtl_random_seedPool (
84 RandomPool_Impl
*pImpl
, const sal_uInt8
*pBuffer
, sal_Size nBufLen
);
86 /** __rtl_random_readPool.
88 static void __rtl_random_readPool (
89 RandomPool_Impl
*pImpl
, sal_uInt8
*pBuffer
, sal_Size nBufLen
);
94 static double __rtl_random_data (RandomData_Impl
*pImpl
)
98 RTL_RANDOM_RNG (pImpl
->m_nX
, pImpl
->m_nY
, pImpl
->m_nZ
);
99 random
= (((double)(pImpl
->m_nX
) / 30328.0) +
100 ((double)(pImpl
->m_nY
) / 30269.0) +
101 ((double)(pImpl
->m_nZ
) / 30307.0) );
103 random
-= ((double)((sal_uInt32
)(random
)));
108 * __rtl_random_initPool.
110 static sal_Bool
__rtl_random_initPool (RandomPool_Impl
*pImpl
)
112 pImpl
->m_hDigest
= rtl_digest_create (RTL_RANDOM_DIGEST
);
113 if (pImpl
->m_hDigest
)
115 oslThreadIdentifier id
;
120 /* The use of uninitialized stack variables as a way to
121 * enhance the entropy of the random pool triggers
122 * memory checkers like purify and valgrind.
126 __rtl_random_seedPool (pImpl, (sal_uInt8*)&id, sizeof(id));
127 __rtl_random_seedPool (pImpl, (sal_uInt8*)&tv, sizeof(tv));
128 __rtl_random_seedPool (pImpl, (sal_uInt8*)&rd, sizeof(rd));
131 id
= osl_getThreadIdentifier (NULL
);
132 id
= RTL_RANDOM_RNG_2(RTL_RANDOM_RNG_1(id
));
133 __rtl_random_seedPool (pImpl
, (sal_uInt8
*)&id
, sizeof(id
));
135 osl_getSystemTime (&tv
);
136 tv
.Seconds
= RTL_RANDOM_RNG_2(tv
.Seconds
);
137 tv
.Nanosec
= RTL_RANDOM_RNG_2(tv
.Nanosec
);
138 __rtl_random_seedPool (pImpl
, (sal_uInt8
*)&tv
, sizeof(tv
));
140 rd
.m_nX
= (sal_Int16
)(((id
>> 1) << 1) + 1);
141 rd
.m_nY
= (sal_Int16
)(((tv
.Seconds
>> 1) << 1) + 1);
142 rd
.m_nZ
= (sal_Int16
)(((tv
.Nanosec
>> 1) << 1) + 1);
143 __rtl_random_seedPool (pImpl
, (sal_uInt8
*)&rd
, sizeof(rd
));
145 while (pImpl
->m_nData
< RTL_RANDOM_SIZE_POOL
)
147 seed
= __rtl_random_data (&rd
);
148 __rtl_random_seedPool (pImpl
, (sal_uInt8
*)&seed
, sizeof(seed
));
156 * __rtl_random_seedPool.
158 static void __rtl_random_seedPool (
159 RandomPool_Impl
*pImpl
, const sal_uInt8
*pBuffer
, sal_Size nBufLen
)
164 for (i
= 0; i
< nBufLen
; i
+= RTL_RANDOM_SIZE_DIGEST
)
167 if (j
> RTL_RANDOM_SIZE_DIGEST
)
168 j
= RTL_RANDOM_SIZE_DIGEST
;
171 pImpl
->m_hDigest
, pImpl
->m_pDigest
, RTL_RANDOM_SIZE_DIGEST
);
173 k
= (pImpl
->m_nIndex
+ j
) - RTL_RANDOM_SIZE_POOL
;
177 pImpl
->m_hDigest
, &(pImpl
->m_pData
[pImpl
->m_nIndex
]), j
- k
);
179 pImpl
->m_hDigest
, &(pImpl
->m_pData
[0]), k
);
184 pImpl
->m_hDigest
, &(pImpl
->m_pData
[pImpl
->m_nIndex
]), j
);
187 rtl_digest_update (pImpl
->m_hDigest
, pBuffer
, j
);
191 pImpl
->m_hDigest
, pImpl
->m_pDigest
, RTL_RANDOM_SIZE_DIGEST
);
192 for (k
= 0; k
< j
; k
++)
194 pImpl
->m_pData
[pImpl
->m_nIndex
++] ^= pImpl
->m_pDigest
[k
];
195 if (pImpl
->m_nIndex
>= RTL_RANDOM_SIZE_POOL
)
197 pImpl
->m_nData
= RTL_RANDOM_SIZE_POOL
;
203 if (pImpl
->m_nIndex
> pImpl
->m_nData
)
204 pImpl
->m_nData
= pImpl
->m_nIndex
;
208 * __rtl_random_readPool.
210 static void __rtl_random_readPool (
211 RandomPool_Impl
*pImpl
, sal_uInt8
*pBuffer
, sal_Size nBufLen
)
218 if (j
> RTL_RANDOM_SIZE_DIGEST
/2)
219 j
= RTL_RANDOM_SIZE_DIGEST
/2;
224 &(pImpl
->m_pDigest
[RTL_RANDOM_SIZE_DIGEST
/2]),
225 RTL_RANDOM_SIZE_DIGEST
/2);
227 k
= (pImpl
->m_nIndex
+ j
) - pImpl
->m_nData
;
231 pImpl
->m_hDigest
, &(pImpl
->m_pData
[pImpl
->m_nIndex
]), j
- k
);
233 pImpl
->m_hDigest
, &(pImpl
->m_pData
[0]), k
);
238 pImpl
->m_hDigest
, &(pImpl
->m_pData
[pImpl
->m_nIndex
]), j
);
242 pImpl
->m_hDigest
, pImpl
->m_pDigest
, RTL_RANDOM_SIZE_DIGEST
);
243 for (k
= 0; k
< j
; k
++)
245 if (pImpl
->m_nIndex
>= pImpl
->m_nData
) pImpl
->m_nIndex
= 0;
246 pImpl
->m_pData
[pImpl
->m_nIndex
++] ^= pImpl
->m_pDigest
[k
];
247 *pBuffer
++ = pImpl
->m_pDigest
[k
+ RTL_RANDOM_SIZE_DIGEST
/2];
253 pImpl
->m_hDigest
, &(pImpl
->m_nCount
), sizeof(pImpl
->m_nCount
));
255 pImpl
->m_hDigest
, pImpl
->m_pDigest
, RTL_RANDOM_SIZE_DIGEST
);
257 pImpl
->m_hDigest
, pImpl
->m_pDigest
, RTL_RANDOM_SIZE_DIGEST
);
260 /*========================================================================
262 * rtlRandom implementation.
264 *======================================================================*/
266 * rtl_random_createPool.
268 rtlRandomPool SAL_CALL
rtl_random_createPool() SAL_THROW_EXTERN_C()
270 RandomPool_Impl
*pImpl
= (RandomPool_Impl
*)NULL
;
271 pImpl
= (RandomPool_Impl
*)rtl_allocateZeroMemory (sizeof(RandomPool_Impl
));
274 if (!__rtl_random_initPool (pImpl
))
276 rtl_freeZeroMemory (pImpl
, sizeof(RandomPool_Impl
));
277 pImpl
= (RandomPool_Impl
*)NULL
;
280 return ((rtlRandomPool
)pImpl
);
284 * rtl_random_destroyPool.
286 void SAL_CALL
rtl_random_destroyPool (rtlRandomPool Pool
) SAL_THROW_EXTERN_C()
288 RandomPool_Impl
*pImpl
= (RandomPool_Impl
*)Pool
;
291 rtl_digest_destroy (pImpl
->m_hDigest
);
292 rtl_freeZeroMemory (pImpl
, sizeof (RandomPool_Impl
));
297 * rtl_random_addBytes.
299 rtlRandomError SAL_CALL
rtl_random_addBytes (
300 rtlRandomPool Pool
, const void *Buffer
, sal_Size Bytes
) SAL_THROW_EXTERN_C()
302 RandomPool_Impl
*pImpl
= (RandomPool_Impl
*)Pool
;
303 const sal_uInt8
*pBuffer
= (const sal_uInt8
*)Buffer
;
305 if ((pImpl
== NULL
) || (pBuffer
== NULL
))
306 return rtl_Random_E_Argument
;
308 __rtl_random_seedPool (pImpl
, pBuffer
, Bytes
);
309 return rtl_Random_E_None
;
313 * rtl_random_getBytes.
315 rtlRandomError SAL_CALL
rtl_random_getBytes (
316 rtlRandomPool Pool
, void *Buffer
, sal_Size Bytes
) SAL_THROW_EXTERN_C()
318 RandomPool_Impl
*pImpl
= (RandomPool_Impl
*)Pool
;
319 sal_uInt8
*pBuffer
= (sal_uInt8
*)Buffer
;
321 if ((pImpl
== NULL
) || (pBuffer
== NULL
))
322 return rtl_Random_E_Argument
;
324 __rtl_random_readPool (pImpl
, pBuffer
, Bytes
);
325 return rtl_Random_E_None
;
328 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */