LCOV - code coverage report
Current view: top level - sal/rtl - random.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 92 98 93.9 %
Date: 2015-06-13 12:38:46 Functions: 8 8 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       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/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      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 .
      18             :  */
      19             : 
      20             : #include <sal/types.h>
      21             : #include <osl/thread.h>
      22             : #include <osl/thread.hxx>
      23             : #include <osl/time.h>
      24             : #include <rtl/alloc.h>
      25             : #include <rtl/digest.h>
      26             : #include <rtl/random.h>
      27             : 
      28             : /*========================================================================
      29             :  *
      30             :  * rtlRandom internals.
      31             :  *
      32             :  *======================================================================*/
      33             : #define RTL_RANDOM_RNG_1(a) ((a) * 16807L)
      34             : #define RTL_RANDOM_RNG_2(a) ((a) * 65539L)
      35             : 
      36             : #define RTL_RANDOM_RNG(x, y, z) \
      37             : { \
      38             :     (x) = 170 * ((x) % 178) - 63 * ((x) / 178); \
      39             :     if ((x) < 0) (x) += 30328L; \
      40             :     \
      41             :     (y) = 171 * ((y) % 177) -  2 * ((y) / 177); \
      42             :     if ((y) < 0) (y) += 30269L; \
      43             :     \
      44             :     (z) = 172 * ((z) % 176) - 35 * ((z) / 176); \
      45             :     if ((z) < 0) (z) += 30307L; \
      46             : }
      47             : 
      48             : /** RandomData_Impl.
      49             :  */
      50             : struct RandomData_Impl
      51             : {
      52             :     sal_Int16 m_nX;
      53             :     sal_Int16 m_nY;
      54             :     sal_Int16 m_nZ;
      55             : };
      56             : 
      57             : /** __rtl_random_data.
      58             :  */
      59             : static double __rtl_random_data (RandomData_Impl *pImpl);
      60             : 
      61             : /** RandomPool_Impl.
      62             :  */
      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
      66             : 
      67             : struct RandomPool_Impl
      68             : {
      69             :     rtlDigest  m_hDigest;
      70             :     sal_uInt8  m_pDigest[RTL_RANDOM_SIZE_DIGEST];
      71             :     sal_uInt8  m_pData[RTL_RANDOM_SIZE_POOL + 1];
      72             :     sal_uInt32 m_nData;
      73             :     sal_uInt32 m_nIndex;
      74             :     sal_uInt32 m_nCount;
      75             : };
      76             : 
      77             : /** __rtl_random_initPool.
      78             :  */
      79             : static bool __rtl_random_initPool (
      80             :     RandomPool_Impl *pImpl);
      81             : 
      82             : /** __rtl_random_seedPool.
      83             :  */
      84             : static void __rtl_random_seedPool (
      85             :     RandomPool_Impl *pImpl, const sal_uInt8 *pBuffer, sal_Size nBufLen);
      86             : 
      87             : /** __rtl_random_readPool.
      88             :  */
      89             : static void __rtl_random_readPool (
      90             :     RandomPool_Impl *pImpl, sal_uInt8 *pBuffer, sal_Size nBufLen);
      91             : 
      92             : /*
      93             :  * __rtl_random_data.
      94             :  */
      95      169470 : static double __rtl_random_data (RandomData_Impl *pImpl)
      96             : {
      97             :     double random;
      98             : 
      99      169470 :     RTL_RANDOM_RNG (pImpl->m_nX, pImpl->m_nY, pImpl->m_nZ);
     100      338940 :     random = (((double)(pImpl->m_nX) / 30328.0) +
     101      169470 :               ((double)(pImpl->m_nY) / 30269.0) +
     102      169470 :               ((double)(pImpl->m_nZ) / 30307.0)   );
     103             : 
     104      169470 :     random -= ((double)((sal_uInt32)(random)));
     105      169470 :     return random;
     106             : }
     107             : 
     108             : /*
     109             :  * __rtl_random_initPool.
     110             :  */
     111        1345 : static bool __rtl_random_initPool (RandomPool_Impl *pImpl)
     112             : {
     113        1345 :     pImpl->m_hDigest = rtl_digest_create (RTL_RANDOM_DIGEST);
     114        1345 :     if (pImpl->m_hDigest)
     115             :     {
     116             :         oslThreadIdentifier tid;
     117             :         TimeValue           tv;
     118             :         RandomData_Impl     rd;
     119             :         double              seed;
     120             : 
     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.
     124             :          */
     125             : 
     126             :         /*
     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));
     130             :         */
     131             : 
     132        1345 :         tid = osl::Thread::getCurrentIdentifier();
     133        1345 :         tid = RTL_RANDOM_RNG_2(RTL_RANDOM_RNG_1(tid));
     134        1345 :         __rtl_random_seedPool (pImpl, reinterpret_cast<sal_uInt8*>(&tid), sizeof(tid));
     135             : 
     136        1345 :         osl_getSystemTime (&tv);
     137        1345 :         tv.Seconds = RTL_RANDOM_RNG_2(tv.Seconds);
     138        1345 :         tv.Nanosec = RTL_RANDOM_RNG_2(tv.Nanosec);
     139        1345 :         __rtl_random_seedPool (pImpl, reinterpret_cast<sal_uInt8*>(&tv), sizeof(tv));
     140             : 
     141        1345 :         rd.m_nX = (sal_Int16)(((tid         >> 1) << 1) + 1);
     142        1345 :         rd.m_nY = (sal_Int16)(((tv.Seconds >> 1) << 1) + 1);
     143        1345 :         rd.m_nZ = (sal_Int16)(((tv.Nanosec >> 1) << 1) + 1);
     144        1345 :         __rtl_random_seedPool (pImpl, reinterpret_cast<sal_uInt8*>(&rd), sizeof(rd));
     145             : 
     146      172160 :         while (pImpl->m_nData < RTL_RANDOM_SIZE_POOL)
     147             :         {
     148      169470 :             seed = __rtl_random_data (&rd);
     149      169469 :             __rtl_random_seedPool (pImpl, reinterpret_cast<sal_uInt8*>(&seed), sizeof(seed));
     150             :         }
     151        1345 :         return true;
     152             :     }
     153           0 :     return false;
     154             : }
     155             : 
     156             : /*
     157             :  * __rtl_random_seedPool.
     158             :  */
     159      174339 : static void __rtl_random_seedPool (
     160             :     RandomPool_Impl *pImpl, const sal_uInt8 *pBuffer, sal_Size nBufLen)
     161             : {
     162             :     sal_Size i;
     163             :     sal_sSize  j, k;
     164             : 
     165      348680 :     for (i = 0; i < nBufLen; i += RTL_RANDOM_SIZE_DIGEST)
     166             :     {
     167      174339 :         j = nBufLen - i;
     168      174339 :         if (j > RTL_RANDOM_SIZE_DIGEST)
     169           0 :             j = RTL_RANDOM_SIZE_DIGEST;
     170             : 
     171             :         rtl_digest_update (
     172      174339 :             pImpl->m_hDigest, pImpl->m_pDigest, RTL_RANDOM_SIZE_DIGEST);
     173             : 
     174      174339 :         k = (pImpl->m_nIndex + j) - RTL_RANDOM_SIZE_POOL;
     175      174339 :         if (k > 0)
     176             :         {
     177             :             rtl_digest_update (
     178        1345 :                 pImpl->m_hDigest, &(pImpl->m_pData[pImpl->m_nIndex]), j - k);
     179             :             rtl_digest_update (
     180        1345 :                 pImpl->m_hDigest, &(pImpl->m_pData[0]), k);
     181             :         }
     182             :         else
     183             :         {
     184             :             rtl_digest_update (
     185      172994 :                 pImpl->m_hDigest, &(pImpl->m_pData[pImpl->m_nIndex]), j);
     186             :         }
     187             : 
     188      174339 :         rtl_digest_update (pImpl->m_hDigest, pBuffer, j);
     189      174336 :         pBuffer += j;
     190             : 
     191             :         rtl_digest_get (
     192      174336 :             pImpl->m_hDigest, pImpl->m_pDigest, RTL_RANDOM_SIZE_DIGEST);
     193     1560991 :         for (k = 0; k < j; k++)
     194             :         {
     195     1386650 :             pImpl->m_pData[pImpl->m_nIndex++] ^= pImpl->m_pDigest[k];
     196     1386650 :             if (pImpl->m_nIndex >= RTL_RANDOM_SIZE_POOL)
     197             :             {
     198        1345 :                 pImpl->m_nData  = RTL_RANDOM_SIZE_POOL;
     199        1345 :                 pImpl->m_nIndex = 0;
     200             :             }
     201             :         }
     202             :     }
     203             : 
     204      174341 :     if (pImpl->m_nIndex > pImpl->m_nData)
     205      172159 :         pImpl->m_nData = pImpl->m_nIndex;
     206      174341 : }
     207             : 
     208             : /*
     209             :  * __rtl_random_readPool.
     210             :  */
     211       49417 : static void __rtl_random_readPool (
     212             :     RandomPool_Impl *pImpl, sal_uInt8 *pBuffer, sal_Size nBufLen)
     213             : {
     214             :     sal_Int32 j, k;
     215             : 
     216      151821 :     while (nBufLen > 0)
     217             :     {
     218       52987 :         j = nBufLen;
     219       52987 :         if (j > RTL_RANDOM_SIZE_DIGEST/2)
     220        3570 :             j = RTL_RANDOM_SIZE_DIGEST/2;
     221       52987 :         nBufLen -= j;
     222             : 
     223             :         rtl_digest_update (
     224             :             pImpl->m_hDigest,
     225             :             &(pImpl->m_pDigest[RTL_RANDOM_SIZE_DIGEST/2]),
     226       52987 :             RTL_RANDOM_SIZE_DIGEST/2);
     227             : 
     228       52987 :         k = (pImpl->m_nIndex + j) - pImpl->m_nData;
     229       52987 :         if (k > 0)
     230             :         {
     231             :             rtl_digest_update (
     232         312 :                 pImpl->m_hDigest, &(pImpl->m_pData[pImpl->m_nIndex]), j - k);
     233             :             rtl_digest_update (
     234         312 :                 pImpl->m_hDigest, &(pImpl->m_pData[0]), k);
     235             :         }
     236             :         else
     237             :         {
     238             :             rtl_digest_update (
     239       52675 :                 pImpl->m_hDigest, &(pImpl->m_pData[pImpl->m_nIndex]), j);
     240             :         }
     241             : 
     242             :         rtl_digest_get (
     243       52987 :             pImpl->m_hDigest, pImpl->m_pDigest, RTL_RANDOM_SIZE_DIGEST);
     244      463148 :         for (k = 0; k < j; k++)
     245             :         {
     246      410161 :             if (pImpl->m_nIndex >= pImpl->m_nData) pImpl->m_nIndex = 0;
     247      410161 :             pImpl->m_pData[pImpl->m_nIndex++] ^= pImpl->m_pDigest[k];
     248      410161 :             *pBuffer++ = pImpl->m_pDigest[k + RTL_RANDOM_SIZE_DIGEST/2];
     249             :         }
     250             :     }
     251             : 
     252       49417 :     pImpl->m_nCount++;
     253             :     rtl_digest_update (
     254       49417 :         pImpl->m_hDigest, &(pImpl->m_nCount), sizeof(pImpl->m_nCount));
     255             :     rtl_digest_update (
     256       49417 :         pImpl->m_hDigest, pImpl->m_pDigest, RTL_RANDOM_SIZE_DIGEST);
     257             :     rtl_digest_get (
     258       49417 :         pImpl->m_hDigest, pImpl->m_pDigest, RTL_RANDOM_SIZE_DIGEST);
     259       49417 : }
     260             : 
     261             : /*========================================================================
     262             :  *
     263             :  * rtlRandom implementation.
     264             :  *
     265             :  *======================================================================*/
     266             : /*
     267             :  * rtl_random_createPool.
     268             :  */
     269        1345 : rtlRandomPool SAL_CALL rtl_random_createPool() SAL_THROW_EXTERN_C()
     270             : {
     271        1345 :     RandomPool_Impl *pImpl = nullptr;
     272        1345 :     pImpl = static_cast<RandomPool_Impl*>(rtl_allocateZeroMemory (sizeof(RandomPool_Impl)));
     273        1345 :     if (pImpl)
     274             :     {
     275        1345 :         if (!__rtl_random_initPool (pImpl))
     276             :         {
     277           0 :             rtl_freeZeroMemory (pImpl, sizeof(RandomPool_Impl));
     278           0 :             pImpl = nullptr;
     279             :         }
     280             :     }
     281        1345 :     return static_cast<rtlRandomPool>(pImpl);
     282             : }
     283             : 
     284             : /*
     285             :  * rtl_random_destroyPool.
     286             :  */
     287         906 : void SAL_CALL rtl_random_destroyPool (rtlRandomPool Pool) SAL_THROW_EXTERN_C()
     288             : {
     289         906 :     RandomPool_Impl *pImpl = static_cast<RandomPool_Impl *>(Pool);
     290         906 :     if (pImpl)
     291             :     {
     292         906 :         rtl_digest_destroy (pImpl->m_hDigest);
     293         906 :         rtl_freeZeroMemory (pImpl, sizeof (RandomPool_Impl));
     294             :     }
     295         906 : }
     296             : 
     297             : /*
     298             :  * rtl_random_addBytes.
     299             :  */
     300         836 : rtlRandomError SAL_CALL rtl_random_addBytes (
     301             :     rtlRandomPool Pool, const void *Buffer, sal_Size Bytes) SAL_THROW_EXTERN_C()
     302             : {
     303         836 :     RandomPool_Impl *pImpl   = static_cast<RandomPool_Impl *>(Pool);
     304         836 :     const sal_uInt8 *pBuffer = static_cast<const sal_uInt8 *>(Buffer);
     305             : 
     306         836 :     if ((pImpl == NULL) || (pBuffer == NULL))
     307           0 :         return rtl_Random_E_Argument;
     308             : 
     309         836 :     __rtl_random_seedPool (pImpl, pBuffer, Bytes);
     310         836 :     return rtl_Random_E_None;
     311             : }
     312             : 
     313             : /*
     314             :  * rtl_random_getBytes.
     315             :  */
     316       49417 : rtlRandomError SAL_CALL rtl_random_getBytes (
     317             :     rtlRandomPool Pool, void *Buffer, sal_Size Bytes) SAL_THROW_EXTERN_C()
     318             : {
     319       49417 :     RandomPool_Impl *pImpl   = static_cast<RandomPool_Impl *>(Pool);
     320       49417 :     sal_uInt8       *pBuffer = static_cast<sal_uInt8 *>(Buffer);
     321             : 
     322       49417 :     if ((pImpl == NULL) || (pBuffer == NULL))
     323           0 :         return rtl_Random_E_Argument;
     324             : 
     325       49417 :     __rtl_random_readPool (pImpl, pBuffer, Bytes);
     326       49417 :     return rtl_Random_E_None;
     327             : }
     328             : 
     329             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11