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/config.h>
24 #include <sal/types.h>
25 #include <o3tl/temporary.hxx>
26 #include <osl/thread.h>
27 #include <osl/thread.hxx>
29 #include <rtl/alloc.h>
30 #include <rtl/digest.h>
31 #include <rtl/random.h>
32 #include <oslrandom.h>
34 #define RTL_RANDOM_RNG_1(a) ((a) * 16807L)
35 #define RTL_RANDOM_RNG_2(a) ((a) * 65539L)
37 #define RTL_RANDOM_RNG(x, y, z) \
39 (x) = 170 * ((x) % 178) - 63 * ((x) / 178); \
40 if ((x) < 0) (x) += 30328; \
42 (y) = 171 * ((y) % 177) - 2 * ((y) / 177); \
43 if ((y) < 0) (y) += 30269; \
45 (z) = 172 * ((z) % 176) - 35 * ((z) / 176); \
46 if ((z) < 0) (z) += 30307; \
51 struct RandomData_Impl
60 static double 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
68 struct RandomPool_Impl
71 sal_uInt8 m_pDigest
[RTL_RANDOM_SIZE_DIGEST
];
72 sal_uInt8 m_pData
[RTL_RANDOM_SIZE_POOL
+ 1];
80 static bool initPool(RandomPool_Impl
*pImpl
);
83 RandomPool_Impl
*pImpl
, const sal_uInt8
*pBuffer
, sal_Size nBufLen
);
86 RandomPool_Impl
*pImpl
, sal_uInt8
*pBuffer
, sal_Size nBufLen
);
88 static double data(RandomData_Impl
*pImpl
)
92 RTL_RANDOM_RNG (pImpl
->m_nX
, pImpl
->m_nY
, pImpl
->m_nZ
);
93 random
= ((static_cast<double>(pImpl
->m_nX
) / 30328.0) +
94 (static_cast<double>(pImpl
->m_nY
) / 30269.0) +
95 (static_cast<double>(pImpl
->m_nZ
) / 30307.0) );
97 return std::modf(random
, &o3tl::temporary(double()));
100 static bool initPool(RandomPool_Impl
*pImpl
)
102 pImpl
->m_hDigest
= rtl_digest_create(RTL_RANDOM_DIGEST
);
103 if (pImpl
->m_hDigest
)
105 oslThreadIdentifier tid
;
110 /* The use of uninitialized stack variables as a way to
111 * enhance the entropy of the random pool triggers
112 * memory checkers like purify and valgrind.
116 seedPool (pImpl, (sal_uInt8*)&tid, sizeof(tid));
117 seedPool (pImpl, (sal_uInt8*)&tv, sizeof(tv));
118 seedPool (pImpl, (sal_uInt8*)&rd, sizeof(rd));
121 tid
= osl::Thread::getCurrentIdentifier();
122 tid
= RTL_RANDOM_RNG_2(RTL_RANDOM_RNG_1(tid
));
123 seedPool (pImpl
, reinterpret_cast< sal_uInt8
* >(&tid
), sizeof(tid
));
125 osl_getSystemTime (&tv
);
126 tv
.Seconds
= RTL_RANDOM_RNG_2(tv
.Seconds
);
127 tv
.Nanosec
= RTL_RANDOM_RNG_2(tv
.Nanosec
);
128 seedPool (pImpl
, reinterpret_cast< sal_uInt8
* >(&tv
), sizeof(tv
));
130 rd
.m_nX
= static_cast<sal_Int16
>(((tid
>> 1) << 1) + 1);
131 rd
.m_nY
= static_cast<sal_Int16
>(((tv
.Seconds
>> 1) << 1) + 1);
132 rd
.m_nZ
= static_cast<sal_Int16
>(((tv
.Nanosec
>> 1) << 1) + 1);
133 seedPool (pImpl
, reinterpret_cast< sal_uInt8
* >(&rd
), sizeof(rd
));
135 while (pImpl
->m_nData
< RTL_RANDOM_SIZE_POOL
)
138 seedPool (pImpl
, reinterpret_cast< sal_uInt8
* >(&seed
), sizeof(seed
));
145 static void seedPool(
146 RandomPool_Impl
*pImpl
, const sal_uInt8
*pBuffer
, sal_Size nBufLen
)
151 for (i
= 0; i
< nBufLen
; i
+= RTL_RANDOM_SIZE_DIGEST
)
154 if (j
> RTL_RANDOM_SIZE_DIGEST
)
155 j
= RTL_RANDOM_SIZE_DIGEST
;
158 pImpl
->m_hDigest
, pImpl
->m_pDigest
, RTL_RANDOM_SIZE_DIGEST
);
160 k
= (pImpl
->m_nIndex
+ j
) - RTL_RANDOM_SIZE_POOL
;
164 pImpl
->m_hDigest
, &(pImpl
->m_pData
[pImpl
->m_nIndex
]), j
- k
);
166 pImpl
->m_hDigest
, &(pImpl
->m_pData
[0]), k
);
171 pImpl
->m_hDigest
, &(pImpl
->m_pData
[pImpl
->m_nIndex
]), j
);
174 rtl_digest_update(pImpl
->m_hDigest
, pBuffer
, j
);
178 pImpl
->m_hDigest
, pImpl
->m_pDigest
, RTL_RANDOM_SIZE_DIGEST
);
179 for (k
= 0; k
< j
; k
++)
181 pImpl
->m_pData
[pImpl
->m_nIndex
++] ^= pImpl
->m_pDigest
[k
];
182 if (pImpl
->m_nIndex
>= RTL_RANDOM_SIZE_POOL
)
184 pImpl
->m_nData
= RTL_RANDOM_SIZE_POOL
;
190 if (pImpl
->m_nIndex
> pImpl
->m_nData
)
191 pImpl
->m_nData
= pImpl
->m_nIndex
;
194 static void readPool (
195 RandomPool_Impl
*pImpl
, sal_uInt8
*pBuffer
, sal_Size nBufLen
)
202 if (j
> RTL_RANDOM_SIZE_DIGEST
/2)
203 j
= RTL_RANDOM_SIZE_DIGEST
/2;
208 &(pImpl
->m_pDigest
[RTL_RANDOM_SIZE_DIGEST
/2]),
209 RTL_RANDOM_SIZE_DIGEST
/2);
211 k
= (pImpl
->m_nIndex
+ j
) - pImpl
->m_nData
;
215 pImpl
->m_hDigest
, &(pImpl
->m_pData
[pImpl
->m_nIndex
]), j
- k
);
217 pImpl
->m_hDigest
, &(pImpl
->m_pData
[0]), k
);
222 pImpl
->m_hDigest
, &(pImpl
->m_pData
[pImpl
->m_nIndex
]), j
);
226 pImpl
->m_hDigest
, pImpl
->m_pDigest
, RTL_RANDOM_SIZE_DIGEST
);
227 for (k
= 0; k
< j
; k
++)
229 if (pImpl
->m_nIndex
>= pImpl
->m_nData
)
232 pImpl
->m_pData
[pImpl
->m_nIndex
++] ^= pImpl
->m_pDigest
[k
];
233 *pBuffer
++ = pImpl
->m_pDigest
[k
+ RTL_RANDOM_SIZE_DIGEST
/2];
239 pImpl
->m_hDigest
, &(pImpl
->m_nCount
), sizeof(pImpl
->m_nCount
));
241 pImpl
->m_hDigest
, pImpl
->m_pDigest
, RTL_RANDOM_SIZE_DIGEST
);
243 pImpl
->m_hDigest
, pImpl
->m_pDigest
, RTL_RANDOM_SIZE_DIGEST
);
246 rtlRandomPool SAL_CALL
rtl_random_createPool() SAL_THROW_EXTERN_C()
248 /* try to get system random number, if it fail fall back on own pool */
249 RandomPool_Impl
*pImpl
= static_cast< RandomPool_Impl
* >(rtl_allocateZeroMemory(sizeof(RandomPool_Impl
)));
253 if (!osl_get_system_random_data(sanity
, 4))
255 if (!initPool(pImpl
))
257 rtl_freeZeroMemory(pImpl
, sizeof(RandomPool_Impl
));
262 return static_cast< rtlRandomPool
>(pImpl
);
265 void SAL_CALL
rtl_random_destroyPool(rtlRandomPool Pool
) SAL_THROW_EXTERN_C()
267 RandomPool_Impl
*pImpl
= static_cast< RandomPool_Impl
* >(Pool
);
270 if (pImpl
->m_hDigest
)
271 rtl_digest_destroy(pImpl
->m_hDigest
);
273 rtl_freeZeroMemory (pImpl
, sizeof(RandomPool_Impl
));
277 rtlRandomError SAL_CALL
rtl_random_addBytes(
278 rtlRandomPool Pool
, const void *Buffer
, sal_Size Bytes
) SAL_THROW_EXTERN_C()
280 RandomPool_Impl
*pImpl
= static_cast< RandomPool_Impl
* >(Pool
);
281 const sal_uInt8
*pBuffer
= static_cast< const sal_uInt8
* >(Buffer
);
283 if (!pImpl
|| !pBuffer
)
284 return rtl_Random_E_Argument
;
286 if (pImpl
->m_hDigest
)
287 seedPool (pImpl
, pBuffer
, Bytes
);
289 return rtl_Random_E_None
;
292 rtlRandomError SAL_CALL
rtl_random_getBytes (
293 rtlRandomPool Pool
, void *Buffer
, sal_Size Bytes
) SAL_THROW_EXTERN_C()
295 RandomPool_Impl
*pImpl
= static_cast< RandomPool_Impl
* >(Pool
);
296 sal_uInt8
*pBuffer
= static_cast< sal_uInt8
* >(Buffer
);
298 if (!pImpl
|| !pBuffer
)
299 return rtl_Random_E_Argument
;
301 if (pImpl
->m_hDigest
|| !osl_get_system_random_data(static_cast< char* >(Buffer
), Bytes
))
303 if (!pImpl
->m_hDigest
&& !initPool(pImpl
))
304 return rtl_Random_E_Unknown
;
305 readPool(pImpl
, pBuffer
, Bytes
);
307 return rtl_Random_E_None
;
310 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */