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; \
49 struct RandomData_Impl
56 static double data (RandomData_Impl
*pImpl
);
58 #define RTL_RANDOM_DIGEST rtl_Digest_AlgorithmMD5
59 #define RTL_RANDOM_SIZE_DIGEST RTL_DIGEST_LENGTH_MD5
60 #define RTL_RANDOM_SIZE_POOL 1023
62 struct RandomPool_Impl
65 sal_uInt8 m_pDigest
[RTL_RANDOM_SIZE_DIGEST
];
66 sal_uInt8 m_pData
[RTL_RANDOM_SIZE_POOL
+ 1];
72 static bool initPool(RandomPool_Impl
*pImpl
);
75 RandomPool_Impl
*pImpl
, const sal_uInt8
*pBuffer
, sal_Size nBufLen
);
78 RandomPool_Impl
*pImpl
, sal_uInt8
*pBuffer
, sal_Size nBufLen
);
80 static double data(RandomData_Impl
*pImpl
)
84 RTL_RANDOM_RNG (pImpl
->m_nX
, pImpl
->m_nY
, pImpl
->m_nZ
);
85 random
= ((static_cast<double>(pImpl
->m_nX
) / 30328.0) +
86 (static_cast<double>(pImpl
->m_nY
) / 30269.0) +
87 (static_cast<double>(pImpl
->m_nZ
) / 30307.0) );
89 return std::modf(random
, &o3tl::temporary(double()));
92 static bool initPool(RandomPool_Impl
*pImpl
)
94 pImpl
->m_hDigest
= rtl_digest_create(RTL_RANDOM_DIGEST
);
97 oslThreadIdentifier tid
;
102 /* The use of uninitialized stack variables as a way to
103 * enhance the entropy of the random pool triggers
104 * memory checkers like purify and valgrind.
108 seedPool (pImpl, (sal_uInt8*)&tid, sizeof(tid));
109 seedPool (pImpl, (sal_uInt8*)&tv, sizeof(tv));
110 seedPool (pImpl, (sal_uInt8*)&rd, sizeof(rd));
113 tid
= osl::Thread::getCurrentIdentifier();
114 tid
= RTL_RANDOM_RNG_2(RTL_RANDOM_RNG_1(tid
));
115 seedPool (pImpl
, reinterpret_cast< sal_uInt8
* >(&tid
), sizeof(tid
));
117 osl_getSystemTime (&tv
);
118 tv
.Seconds
= RTL_RANDOM_RNG_2(tv
.Seconds
);
119 tv
.Nanosec
= RTL_RANDOM_RNG_2(tv
.Nanosec
);
120 seedPool (pImpl
, reinterpret_cast< sal_uInt8
* >(&tv
), sizeof(tv
));
122 rd
.m_nX
= static_cast<sal_Int16
>(((tid
>> 1) << 1) + 1);
123 rd
.m_nY
= static_cast<sal_Int16
>(((tv
.Seconds
>> 1) << 1) + 1);
124 rd
.m_nZ
= static_cast<sal_Int16
>(((tv
.Nanosec
>> 1) << 1) + 1);
125 seedPool (pImpl
, reinterpret_cast< sal_uInt8
* >(&rd
), sizeof(rd
));
127 while (pImpl
->m_nData
< RTL_RANDOM_SIZE_POOL
)
130 seedPool (pImpl
, reinterpret_cast< sal_uInt8
* >(&seed
), sizeof(seed
));
137 static void seedPool(
138 RandomPool_Impl
*pImpl
, const sal_uInt8
*pBuffer
, sal_Size nBufLen
)
143 for (i
= 0; i
< nBufLen
; i
+= RTL_RANDOM_SIZE_DIGEST
)
146 if (j
> RTL_RANDOM_SIZE_DIGEST
)
147 j
= RTL_RANDOM_SIZE_DIGEST
;
150 pImpl
->m_hDigest
, pImpl
->m_pDigest
, RTL_RANDOM_SIZE_DIGEST
);
152 k
= (pImpl
->m_nIndex
+ j
) - RTL_RANDOM_SIZE_POOL
;
156 pImpl
->m_hDigest
, &(pImpl
->m_pData
[pImpl
->m_nIndex
]), j
- k
);
158 pImpl
->m_hDigest
, &(pImpl
->m_pData
[0]), k
);
163 pImpl
->m_hDigest
, &(pImpl
->m_pData
[pImpl
->m_nIndex
]), j
);
166 rtl_digest_update(pImpl
->m_hDigest
, pBuffer
, j
);
170 pImpl
->m_hDigest
, pImpl
->m_pDigest
, RTL_RANDOM_SIZE_DIGEST
);
171 for (k
= 0; k
< j
; k
++)
173 pImpl
->m_pData
[pImpl
->m_nIndex
++] ^= pImpl
->m_pDigest
[k
];
174 if (pImpl
->m_nIndex
>= RTL_RANDOM_SIZE_POOL
)
176 pImpl
->m_nData
= RTL_RANDOM_SIZE_POOL
;
182 if (pImpl
->m_nIndex
> pImpl
->m_nData
)
183 pImpl
->m_nData
= pImpl
->m_nIndex
;
186 static void readPool (
187 RandomPool_Impl
*pImpl
, sal_uInt8
*pBuffer
, sal_Size nBufLen
)
194 if (j
> RTL_RANDOM_SIZE_DIGEST
/2)
195 j
= RTL_RANDOM_SIZE_DIGEST
/2;
200 &(pImpl
->m_pDigest
[RTL_RANDOM_SIZE_DIGEST
/2]),
201 RTL_RANDOM_SIZE_DIGEST
/2);
203 k
= (pImpl
->m_nIndex
+ j
) - pImpl
->m_nData
;
207 pImpl
->m_hDigest
, &(pImpl
->m_pData
[pImpl
->m_nIndex
]), j
- k
);
209 pImpl
->m_hDigest
, &(pImpl
->m_pData
[0]), k
);
214 pImpl
->m_hDigest
, &(pImpl
->m_pData
[pImpl
->m_nIndex
]), j
);
218 pImpl
->m_hDigest
, pImpl
->m_pDigest
, RTL_RANDOM_SIZE_DIGEST
);
219 for (k
= 0; k
< j
; k
++)
221 if (pImpl
->m_nIndex
>= pImpl
->m_nData
)
224 pImpl
->m_pData
[pImpl
->m_nIndex
++] ^= pImpl
->m_pDigest
[k
];
225 *pBuffer
++ = pImpl
->m_pDigest
[k
+ RTL_RANDOM_SIZE_DIGEST
/2];
231 pImpl
->m_hDigest
, &(pImpl
->m_nCount
), sizeof(pImpl
->m_nCount
));
233 pImpl
->m_hDigest
, pImpl
->m_pDigest
, RTL_RANDOM_SIZE_DIGEST
);
235 pImpl
->m_hDigest
, pImpl
->m_pDigest
, RTL_RANDOM_SIZE_DIGEST
);
238 rtlRandomPool SAL_CALL
rtl_random_createPool() SAL_THROW_EXTERN_C()
240 /* try to get system random number, if it fail fall back on own pool */
241 RandomPool_Impl
*pImpl
= static_cast< RandomPool_Impl
* >(rtl_allocateZeroMemory(sizeof(RandomPool_Impl
)));
245 if (!osl_get_system_random_data(sanity
, 4))
247 if (!initPool(pImpl
))
249 rtl_freeZeroMemory(pImpl
, sizeof(RandomPool_Impl
));
254 return static_cast< rtlRandomPool
>(pImpl
);
257 void SAL_CALL
rtl_random_destroyPool(rtlRandomPool Pool
) SAL_THROW_EXTERN_C()
259 RandomPool_Impl
*pImpl
= static_cast< RandomPool_Impl
* >(Pool
);
262 if (pImpl
->m_hDigest
)
263 rtl_digest_destroy(pImpl
->m_hDigest
);
265 rtl_freeZeroMemory (pImpl
, sizeof(RandomPool_Impl
));
269 rtlRandomError SAL_CALL
rtl_random_addBytes(
270 rtlRandomPool Pool
, const void *Buffer
, sal_Size Bytes
) SAL_THROW_EXTERN_C()
272 RandomPool_Impl
*pImpl
= static_cast< RandomPool_Impl
* >(Pool
);
273 const sal_uInt8
*pBuffer
= static_cast< const sal_uInt8
* >(Buffer
);
275 if (!pImpl
|| !pBuffer
)
276 return rtl_Random_E_Argument
;
278 if (pImpl
->m_hDigest
)
279 seedPool (pImpl
, pBuffer
, Bytes
);
281 return rtl_Random_E_None
;
284 rtlRandomError SAL_CALL
rtl_random_getBytes (
285 rtlRandomPool Pool
, void *Buffer
, sal_Size Bytes
) SAL_THROW_EXTERN_C()
287 RandomPool_Impl
*pImpl
= static_cast< RandomPool_Impl
* >(Pool
);
288 sal_uInt8
*pBuffer
= static_cast< sal_uInt8
* >(Buffer
);
290 if (!pImpl
|| !pBuffer
)
291 return rtl_Random_E_Argument
;
293 if (pImpl
->m_hDigest
|| !osl_get_system_random_data(static_cast< char* >(Buffer
), Bytes
))
295 if (!pImpl
->m_hDigest
&& !initPool(pImpl
))
296 return rtl_Random_E_Unknown
;
297 readPool(pImpl
, pBuffer
, Bytes
);
299 return rtl_Random_E_None
;
302 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */