Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / sal / rtl / random.cxx
blobc9cc0f841ea90615f36a0d93ebc34cb1410f151f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
22 #include <cmath>
24 #include <sal/types.h>
25 #include <o3tl/temporary.hxx>
26 #include <osl/thread.h>
27 #include <osl/thread.hxx>
28 #include <osl/time.h>
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) \
38 { \
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
51 sal_Int16 m_nX;
52 sal_Int16 m_nY;
53 sal_Int16 m_nZ;
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
64 rtlDigest m_hDigest;
65 sal_uInt8 m_pDigest[RTL_RANDOM_SIZE_DIGEST];
66 sal_uInt8 m_pData[RTL_RANDOM_SIZE_POOL + 1];
67 sal_uInt32 m_nData;
68 sal_uInt32 m_nIndex;
69 sal_uInt32 m_nCount;
72 static bool initPool(RandomPool_Impl *pImpl);
74 static void seedPool(
75 RandomPool_Impl *pImpl, const sal_uInt8 *pBuffer, sal_Size nBufLen);
77 static void readPool(
78 RandomPool_Impl *pImpl, sal_uInt8 *pBuffer, sal_Size nBufLen);
80 static double data(RandomData_Impl *pImpl)
82 double random;
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);
95 if (pImpl->m_hDigest)
97 oslThreadIdentifier tid;
98 TimeValue tv;
99 RandomData_Impl rd;
100 double seed;
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)
129 seed = data (&rd);
130 seedPool (pImpl, reinterpret_cast< sal_uInt8* >(&seed), sizeof(seed));
132 return true;
134 return false;
137 static void seedPool(
138 RandomPool_Impl *pImpl, const sal_uInt8 *pBuffer, sal_Size nBufLen)
140 sal_Size i;
141 sal_sSize j, k;
143 for (i = 0; i < nBufLen; i += RTL_RANDOM_SIZE_DIGEST)
145 j = nBufLen - i;
146 if (j > RTL_RANDOM_SIZE_DIGEST)
147 j = RTL_RANDOM_SIZE_DIGEST;
149 rtl_digest_update(
150 pImpl->m_hDigest, pImpl->m_pDigest, RTL_RANDOM_SIZE_DIGEST);
152 k = (pImpl->m_nIndex + j) - RTL_RANDOM_SIZE_POOL;
153 if (k > 0)
155 rtl_digest_update(
156 pImpl->m_hDigest, &(pImpl->m_pData[pImpl->m_nIndex]), j - k);
157 rtl_digest_update(
158 pImpl->m_hDigest, &(pImpl->m_pData[0]), k);
160 else
162 rtl_digest_update(
163 pImpl->m_hDigest, &(pImpl->m_pData[pImpl->m_nIndex]), j);
166 rtl_digest_update(pImpl->m_hDigest, pBuffer, j);
167 pBuffer += j;
169 rtl_digest_get(
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;
177 pImpl->m_nIndex = 0;
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)
189 sal_Int32 j, k;
191 while (nBufLen > 0)
193 j = nBufLen;
194 if (j > RTL_RANDOM_SIZE_DIGEST/2)
195 j = RTL_RANDOM_SIZE_DIGEST/2;
196 nBufLen -= j;
198 rtl_digest_update(
199 pImpl->m_hDigest,
200 &(pImpl->m_pDigest[RTL_RANDOM_SIZE_DIGEST/2]),
201 RTL_RANDOM_SIZE_DIGEST/2);
203 k = (pImpl->m_nIndex + j) - pImpl->m_nData;
204 if (k > 0)
206 rtl_digest_update(
207 pImpl->m_hDigest, &(pImpl->m_pData[pImpl->m_nIndex]), j - k);
208 rtl_digest_update(
209 pImpl->m_hDigest, &(pImpl->m_pData[0]), k);
211 else
213 rtl_digest_update(
214 pImpl->m_hDigest, &(pImpl->m_pData[pImpl->m_nIndex]), j);
217 rtl_digest_get(
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)
222 pImpl->m_nIndex = 0;
224 pImpl->m_pData[pImpl->m_nIndex++] ^= pImpl->m_pDigest[k];
225 *pBuffer++ = pImpl->m_pDigest[k + RTL_RANDOM_SIZE_DIGEST/2];
229 pImpl->m_nCount++;
230 rtl_digest_update(
231 pImpl->m_hDigest, &(pImpl->m_nCount), sizeof(pImpl->m_nCount));
232 rtl_digest_update(
233 pImpl->m_hDigest, pImpl->m_pDigest, RTL_RANDOM_SIZE_DIGEST);
234 rtl_digest_get(
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)));
242 if (pImpl)
244 char sanity[4];
245 if (!osl_get_system_random_data(sanity, 4))
247 if (!initPool(pImpl))
249 rtl_freeZeroMemory(pImpl, sizeof(RandomPool_Impl));
250 pImpl = nullptr;
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);
260 if (pImpl)
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: */