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>
22 #include <osl/thread.hxx>
24 #include <rtl/alloc.h>
25 #include <rtl/digest.h>
26 #include <rtl/random.h>
28 /*========================================================================
30 * rtlRandom internals.
32 *======================================================================*/
33 #define RTL_RANDOM_RNG_1(a) ((a) * 16807L)
34 #define RTL_RANDOM_RNG_2(a) ((a) * 65539L)
36 #define RTL_RANDOM_RNG(x, y, z) \
38 (x) = 170 * ((x) % 178) - 63 * ((x) / 178); \
39 if ((x) < 0) (x) += 30328L; \
41 (y) = 171 * ((y) % 177) - 2 * ((y) / 177); \
42 if ((y) < 0) (y) += 30269L; \
44 (z) = 172 * ((z) % 176) - 35 * ((z) / 176); \
45 if ((z) < 0) (z) += 30307L; \
50 struct RandomData_Impl
57 /** __rtl_random_data.
59 static double __rtl_random_data (RandomData_Impl
*pImpl
);
63 #define RTL_RANDOM_DIGEST rtl_Digest_AlgorithmMD5
64 #define RTL_RANDOM_SIZE_DIGEST RTL_DIGEST_LENGTH_MD5
65 #define RTL_RANDOM_SIZE_POOL 1023
67 struct RandomPool_Impl
70 sal_uInt8 m_pDigest
[RTL_RANDOM_SIZE_DIGEST
];
71 sal_uInt8 m_pData
[RTL_RANDOM_SIZE_POOL
+ 1];
77 /** __rtl_random_initPool.
79 static bool __rtl_random_initPool (
80 RandomPool_Impl
*pImpl
);
82 /** __rtl_random_seedPool.
84 static void __rtl_random_seedPool (
85 RandomPool_Impl
*pImpl
, const sal_uInt8
*pBuffer
, sal_Size nBufLen
);
87 /** __rtl_random_readPool.
89 static void __rtl_random_readPool (
90 RandomPool_Impl
*pImpl
, sal_uInt8
*pBuffer
, sal_Size nBufLen
);
95 static double __rtl_random_data (RandomData_Impl
*pImpl
)
99 RTL_RANDOM_RNG (pImpl
->m_nX
, pImpl
->m_nY
, pImpl
->m_nZ
);
100 random
= (((double)(pImpl
->m_nX
) / 30328.0) +
101 ((double)(pImpl
->m_nY
) / 30269.0) +
102 ((double)(pImpl
->m_nZ
) / 30307.0) );
104 random
-= ((double)((sal_uInt32
)(random
)));
109 * __rtl_random_initPool.
111 static bool __rtl_random_initPool (RandomPool_Impl
*pImpl
)
113 pImpl
->m_hDigest
= rtl_digest_create (RTL_RANDOM_DIGEST
);
114 if (pImpl
->m_hDigest
)
116 oslThreadIdentifier tid
;
121 /* The use of uninitialized stack variables as a way to
122 * enhance the entropy of the random pool triggers
123 * memory checkers like purify and valgrind.
127 __rtl_random_seedPool (pImpl, (sal_uInt8*)&tid, sizeof(tid));
128 __rtl_random_seedPool (pImpl, (sal_uInt8*)&tv, sizeof(tv));
129 __rtl_random_seedPool (pImpl, (sal_uInt8*)&rd, sizeof(rd));
132 tid
= osl::Thread::getCurrentIdentifier();
133 tid
= RTL_RANDOM_RNG_2(RTL_RANDOM_RNG_1(tid
));
134 __rtl_random_seedPool (pImpl
, reinterpret_cast<sal_uInt8
*>(&tid
), sizeof(tid
));
136 osl_getSystemTime (&tv
);
137 tv
.Seconds
= RTL_RANDOM_RNG_2(tv
.Seconds
);
138 tv
.Nanosec
= RTL_RANDOM_RNG_2(tv
.Nanosec
);
139 __rtl_random_seedPool (pImpl
, reinterpret_cast<sal_uInt8
*>(&tv
), sizeof(tv
));
141 rd
.m_nX
= (sal_Int16
)(((tid
>> 1) << 1) + 1);
142 rd
.m_nY
= (sal_Int16
)(((tv
.Seconds
>> 1) << 1) + 1);
143 rd
.m_nZ
= (sal_Int16
)(((tv
.Nanosec
>> 1) << 1) + 1);
144 __rtl_random_seedPool (pImpl
, reinterpret_cast<sal_uInt8
*>(&rd
), sizeof(rd
));
146 while (pImpl
->m_nData
< RTL_RANDOM_SIZE_POOL
)
148 seed
= __rtl_random_data (&rd
);
149 __rtl_random_seedPool (pImpl
, reinterpret_cast<sal_uInt8
*>(&seed
), sizeof(seed
));
157 * __rtl_random_seedPool.
159 static void __rtl_random_seedPool (
160 RandomPool_Impl
*pImpl
, const sal_uInt8
*pBuffer
, sal_Size nBufLen
)
165 for (i
= 0; i
< nBufLen
; i
+= RTL_RANDOM_SIZE_DIGEST
)
168 if (j
> RTL_RANDOM_SIZE_DIGEST
)
169 j
= RTL_RANDOM_SIZE_DIGEST
;
172 pImpl
->m_hDigest
, pImpl
->m_pDigest
, RTL_RANDOM_SIZE_DIGEST
);
174 k
= (pImpl
->m_nIndex
+ j
) - RTL_RANDOM_SIZE_POOL
;
178 pImpl
->m_hDigest
, &(pImpl
->m_pData
[pImpl
->m_nIndex
]), j
- k
);
180 pImpl
->m_hDigest
, &(pImpl
->m_pData
[0]), k
);
185 pImpl
->m_hDigest
, &(pImpl
->m_pData
[pImpl
->m_nIndex
]), j
);
188 rtl_digest_update (pImpl
->m_hDigest
, pBuffer
, j
);
192 pImpl
->m_hDigest
, pImpl
->m_pDigest
, RTL_RANDOM_SIZE_DIGEST
);
193 for (k
= 0; k
< j
; k
++)
195 pImpl
->m_pData
[pImpl
->m_nIndex
++] ^= pImpl
->m_pDigest
[k
];
196 if (pImpl
->m_nIndex
>= RTL_RANDOM_SIZE_POOL
)
198 pImpl
->m_nData
= RTL_RANDOM_SIZE_POOL
;
204 if (pImpl
->m_nIndex
> pImpl
->m_nData
)
205 pImpl
->m_nData
= pImpl
->m_nIndex
;
209 * __rtl_random_readPool.
211 static void __rtl_random_readPool (
212 RandomPool_Impl
*pImpl
, sal_uInt8
*pBuffer
, sal_Size nBufLen
)
219 if (j
> RTL_RANDOM_SIZE_DIGEST
/2)
220 j
= RTL_RANDOM_SIZE_DIGEST
/2;
225 &(pImpl
->m_pDigest
[RTL_RANDOM_SIZE_DIGEST
/2]),
226 RTL_RANDOM_SIZE_DIGEST
/2);
228 k
= (pImpl
->m_nIndex
+ j
) - pImpl
->m_nData
;
232 pImpl
->m_hDigest
, &(pImpl
->m_pData
[pImpl
->m_nIndex
]), j
- k
);
234 pImpl
->m_hDigest
, &(pImpl
->m_pData
[0]), k
);
239 pImpl
->m_hDigest
, &(pImpl
->m_pData
[pImpl
->m_nIndex
]), j
);
243 pImpl
->m_hDigest
, pImpl
->m_pDigest
, RTL_RANDOM_SIZE_DIGEST
);
244 for (k
= 0; k
< j
; k
++)
246 if (pImpl
->m_nIndex
>= pImpl
->m_nData
) pImpl
->m_nIndex
= 0;
247 pImpl
->m_pData
[pImpl
->m_nIndex
++] ^= pImpl
->m_pDigest
[k
];
248 *pBuffer
++ = pImpl
->m_pDigest
[k
+ RTL_RANDOM_SIZE_DIGEST
/2];
254 pImpl
->m_hDigest
, &(pImpl
->m_nCount
), sizeof(pImpl
->m_nCount
));
256 pImpl
->m_hDigest
, pImpl
->m_pDigest
, RTL_RANDOM_SIZE_DIGEST
);
258 pImpl
->m_hDigest
, pImpl
->m_pDigest
, RTL_RANDOM_SIZE_DIGEST
);
261 /*========================================================================
263 * rtlRandom implementation.
265 *======================================================================*/
267 * rtl_random_createPool.
269 rtlRandomPool SAL_CALL
rtl_random_createPool() SAL_THROW_EXTERN_C()
271 RandomPool_Impl
*pImpl
= (RandomPool_Impl
*)NULL
;
272 pImpl
= static_cast<RandomPool_Impl
*>(rtl_allocateZeroMemory (sizeof(RandomPool_Impl
)));
275 if (!__rtl_random_initPool (pImpl
))
277 rtl_freeZeroMemory (pImpl
, sizeof(RandomPool_Impl
));
278 pImpl
= (RandomPool_Impl
*)NULL
;
281 return (rtlRandomPool
)pImpl
;
285 * rtl_random_destroyPool.
287 void SAL_CALL
rtl_random_destroyPool (rtlRandomPool Pool
) SAL_THROW_EXTERN_C()
289 RandomPool_Impl
*pImpl
= static_cast<RandomPool_Impl
*>(Pool
);
292 rtl_digest_destroy (pImpl
->m_hDigest
);
293 rtl_freeZeroMemory (pImpl
, sizeof (RandomPool_Impl
));
298 * rtl_random_addBytes.
300 rtlRandomError SAL_CALL
rtl_random_addBytes (
301 rtlRandomPool Pool
, const void *Buffer
, sal_Size Bytes
) SAL_THROW_EXTERN_C()
303 RandomPool_Impl
*pImpl
= static_cast<RandomPool_Impl
*>(Pool
);
304 const sal_uInt8
*pBuffer
= static_cast<const sal_uInt8
*>(Buffer
);
306 if ((pImpl
== NULL
) || (pBuffer
== NULL
))
307 return rtl_Random_E_Argument
;
309 __rtl_random_seedPool (pImpl
, pBuffer
, Bytes
);
310 return rtl_Random_E_None
;
314 * rtl_random_getBytes.
316 rtlRandomError SAL_CALL
rtl_random_getBytes (
317 rtlRandomPool Pool
, void *Buffer
, sal_Size Bytes
) SAL_THROW_EXTERN_C()
319 RandomPool_Impl
*pImpl
= static_cast<RandomPool_Impl
*>(Pool
);
320 sal_uInt8
*pBuffer
= static_cast<sal_uInt8
*>(Buffer
);
322 if ((pImpl
== NULL
) || (pBuffer
== NULL
))
323 return rtl_Random_E_Argument
;
325 __rtl_random_readPool (pImpl
, pBuffer
, Bytes
);
326 return rtl_Random_E_None
;
329 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */