source: trunk/EraserDll/Random.cpp @ 4

Revision 4, 52.7 KB checked in by lowjoel, 7 years ago (diff)

Added the source files from EraserDll? (SVN migration commit 2)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1// Random.cpp
2//
3// Eraser. Secure data removal. For Windows.
4// Copyright © 1997-2001  Sami Tolvanen (sami@tolvanen.com).
5//
6// This program is free software; you can redistribute it and/or
7// modify it under the terms of the GNU General Public License
8// as published by the Free Software Foundation; either version 2
9// of the License, or (at your option) any later version.
10//
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14// GNU General Public License for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with this program; if not, write to the Free Software
18// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19// 02111-1307, USA.
20//
21//
22//   Yes, all this only for overwriting. Call me crazy.
23//
24// A slightly modified version of cryptlib's cryptographically strong
25// pseudorandom number generator generator described in Peter
26// Gutmann's paper "Software generation of practically strong random
27// numbers" (1998).
28//
29// This generator also includes another output PRNG for creating large
30// amounts of random data - fast. It uses the ISAAC algorithm by Bob
31// Jenkins.
32//
33// An implementation of the Tiger/192 hash function by Ross Anderson
34// and Eli Biham is used for pool mixing and output instead of SHA-1
35// or MD5 suggested in the paper.
36//
37// The code for entropy polling has been borrowed from GNU Privacy
38// Guard 1.0.6 and cryptlib 3.0. The original source code contained
39// this copyright notice:
40
41/*
42** The random pool handling code in this module and the misc/rnd*.c
43** modules represent the cryptlib continuously seeded pseudorandom
44** number generator (CSPRNG) as described in my 1998 Usenix Security
45** Symposium paper "The generation of practically strong random
46** numbers".
47**
48** The CSPRNG code is copyright Peter Gutmann (and various others)
49** 1995-1999 all rights reserved.  Redistribution of the CSPRNG
50** modules and use in source and binary forms, with or without
51** modification, are permitted provided that the following conditions
52** are met:
53**
54** 1. Redistributions of source code must retain the above copyright
55** notice and this permission notice in its entirety.
56**
57** 2. Redistributions in binary form must reproduce the copyright
58** notice in the documentation and/or other materials provided with
59** the distribution.
60**
61** 3. A copy of any bugfixes or enhancements made must be provided
62** to the author, <pgut001@cs.auckland.ac.nz> to allow them to be
63** added to the baseline version of the code.
64**
65** ALTERNATIVELY, the code may be distributed under the terms of the
66** GNU General Public License, version 2 or any later version
67** published by the Free Software Foundation, in which case the
68** provisions of the GNU GPL are required INSTEAD OF the above
69** restrictions.
70**
71** Although not required under the terms of the GPL, it would still
72** be nice if you could make any changes available to the author to
73** allow a consistent code base to be maintained
74*/
75
76
77#include "stdafx.h"
78#include "EraserDll.h"
79#include "Common.h"
80#include "Tiger.h"
81#include "..\shared\UserInfo.h"
82#include "..\shared\key.h"
83#include "Random.h"
84#include <winioctl.h>
85#include <winperf.h>
86#include <process.h>
87
88/*
89** Variables
90*/
91
92static CRITICAL_SECTION pageLock;
93
94static E_PUINT8 poolPage = 0;
95
96static ISAAC_STATE *isaacState = 0;
97static E_PUINT32 isaacOutput = 0;
98static E_PUINT8 entropyPool = 0;
99static E_PUINT8 tempBuffer = 0;
100static E_PUINT8 outputBuffer = 0;
101
102static E_INT32 randomQuality = 0;
103static E_INT32 poolMixes = 0;
104
105static E_UINT32 isaacOutputPosition = 0;
106static LARGE_INTEGER lastCall;
107
108/*
109** Reference counter
110*/
111
112static E_INT32 refCount = 0;
113static CRITICAL_SECTION refLock;
114
115/*
116** Thread control
117*/
118
119static bool   enableSlowPoll = false;
120static HANDLE stopThreads = NULL;
121static HANDLE refreshThreadStopped = NULL;
122static HANDLE pollThreadStopped = NULL;
123
124/*
125** Declarations
126*/
127
128static UINT refreshThread(LPVOID);
129static UINT pollThread(LPVOID);
130
131
132/*
133** CryptoAPI function pointers and handles
134*/
135
136static HINSTANCE dllAdvAPI = NULL;
137static HCRYPTPROV cryptoContext = NULL;
138
139static CRYPTACQUIRECONTEXT pCryptAcquireContext = NULL;
140static CRYPTGENRANDOM pCryptGenRandom = NULL;
141static CRYPTRELEASECONTEXT pCryptReleaseContext = NULL;
142
143/*
144** CryptoAPI variables
145*/
146
147static E_UINT32 qualityCryptoAPI = qualityMicrosoft;
148
149/*
150** CryptoAPI initialization
151*/
152
153static void
154releaseCryptoAPI()
155{
156    /*
157    ** If we have acquired a context, try to release it
158    */
159
160    if (pCryptReleaseContext != NULL && cryptoContext != NULL) {
161        try {
162            pCryptReleaseContext(cryptoContext, 0);
163        } catch (...) {
164            ASSERT(0);
165        }
166    }
167    cryptoContext = NULL;
168
169    /*
170    ** Release library
171    */
172
173    if (dllAdvAPI != NULL) {
174        AfxFreeLibrary(dllAdvAPI);
175        dllAdvAPI = NULL;
176    }
177
178    /*
179    ** Clear function pointers and variables
180    */
181
182    pCryptAcquireContext = NULL;
183    pCryptGenRandom = NULL;
184    pCryptReleaseContext = NULL;
185    qualityCryptoAPI = qualityMicrosoft;
186}
187
188static void
189loadCryptoAPI()
190{
191    /*
192    ** If library isn't loaded, load it now
193    */
194
195    if (dllAdvAPI == NULL) {
196        dllAdvAPI = AfxLoadLibrary(RANDOM_MODULE_ADVAPI32);
197    }
198
199    /*
200    ** If library was found, locate functions
201    */
202
203    if (dllAdvAPI != NULL) {
204        pCryptAcquireContext = (CRYPTACQUIRECONTEXT)GetProcAddress(dllAdvAPI,
205                                                        RANDOM_FUNCTION_CRYPTACQUIRECONTEXT);
206        pCryptGenRandom = (CRYPTGENRANDOM)GetProcAddress(dllAdvAPI,
207                                                        RANDOM_FUNCTION_CRYPTGENRANDOM);
208        pCryptReleaseContext = (CRYPTRELEASECONTEXT)GetProcAddress(dllAdvAPI,
209                                                        RANDOM_FUNCTION_CRYPTRELEASECONTEXT);
210
211        if (pCryptAcquireContext != NULL && pCryptGenRandom != NULL &&
212            pCryptReleaseContext != NULL) {
213            try {
214                /*
215                ** Try to connect to Intel's hardware RNG if one is installed
216                */
217
218                if (pCryptAcquireContext(&cryptoContext, NULL, INTEL_DEF_PROV,
219                                         PROV_INTEL_SEC, 0)) {
220                    qualityCryptoAPI = qualityIntel;
221                    return;
222                }
223
224                /*
225                ** Default cryptographic service provider
226                */
227
228                qualityCryptoAPI = qualityMicrosoft;
229
230                if (pCryptAcquireContext(&cryptoContext, NULL, NULL, PROV_RSA_FULL, 0)) {
231                    return;
232                } else if (GetLastError() == NTE_BAD_KEYSET) {
233                    /*
234                    ** Default keyset may not exist, attempt to create new
235                    */
236
237                    if (pCryptAcquireContext(&cryptoContext, NULL, NULL, PROV_RSA_FULL,
238                                             CRYPT_NEWKEYSET)) {
239                        return;
240                    }
241                }
242            } catch (...) {
243                ASSERT(0);
244            }
245        }
246
247        /*
248        ** CryptoAPI not present or couldn't connect to a CSP
249        */
250
251        releaseCryptoAPI();
252    }
253}
254
255/*
256** Windows ToolHelp32 API function pointers and handles
257*/
258
259static HINSTANCE dllKernel = NULL;
260
261static CREATESNAPSHOT pCreateToolhelp32Snapshot = NULL;
262static MODULEWALK pModule32First = NULL;
263static MODULEWALK pModule32Next = NULL;
264static PROCESSWALK pProcess32First = NULL;
265static PROCESSWALK pProcess32Next = NULL;
266static THREADWALK pThread32First = NULL;
267static THREADWALK pThread32Next = NULL;
268static HEAPLISTWALK pHeap32ListFirst = NULL;
269static HEAPLISTWALK pHeap32ListNext = NULL;
270static HEAPFIRST pHeap32First = NULL;
271static HEAPNEXT pHeap32Next = NULL;
272
273/*
274** Windows ToolHelp32 API initialization
275*/
276
277static void
278releaseToolHelpAPI()
279{
280    /*
281    ** Free library
282    */
283
284    if (dllKernel != NULL) {
285        AfxFreeLibrary(dllKernel);
286        dllKernel = NULL;
287    }
288
289    /*
290    ** Clear function pointers
291    */
292
293    pCreateToolhelp32Snapshot = NULL;
294    pModule32First = NULL;
295    pModule32Next = NULL;
296    pProcess32First = NULL;
297    pProcess32Next = NULL;
298    pThread32First = NULL;
299    pThread32Next = NULL;
300    pHeap32ListFirst = NULL;
301    pHeap32ListNext = NULL;
302    pHeap32First = NULL;
303    pHeap32Next = NULL;
304}
305
306static void
307loadToolHelpAPI()
308{
309    /*
310    ** Load library, kernel should at least be present
311    */
312
313    if (dllKernel == NULL) {
314        dllKernel = AfxLoadLibrary(RANDOM_MODULE_KERNEL32);
315    }
316
317    /*
318    ** Try to locate ToolHelp32 functions
319    */
320
321    if (dllKernel != NULL) {
322        pModule32First   = (MODULEWALK)GetProcAddress(dllKernel, RANDOM_FUNCTION_MODULE32FIRST);
323        pModule32Next    = (MODULEWALK)GetProcAddress(dllKernel, RANDOM_FUNCTION_MODULE32NEXT);
324        pProcess32First  = (PROCESSWALK)GetProcAddress(dllKernel, RANDOM_FUNCTION_PROCESS32FIRST);
325        pProcess32Next   = (PROCESSWALK)GetProcAddress(dllKernel, RANDOM_FUNCTION_PROCESS32NEXT);
326        pThread32First   = (THREADWALK)GetProcAddress(dllKernel, RANDOM_FUNCTION_THREAD32FIRST);
327        pThread32Next    = (THREADWALK)GetProcAddress(dllKernel, RANDOM_FUNCTION_THREAD32NEXT);
328        pHeap32ListFirst = (HEAPLISTWALK)GetProcAddress(dllKernel, RANDOM_FUNCTION_HEAP32LISTFIRST);
329        pHeap32ListNext  = (HEAPLISTWALK)GetProcAddress(dllKernel, RANDOM_FUNCTION_HEAP32LISTNEXT);
330        pHeap32First     = (HEAPFIRST)GetProcAddress(dllKernel, RANDOM_FUNCTION_HEAPFIRST);
331        pHeap32Next      = (HEAPNEXT)GetProcAddress(dllKernel, RANDOM_FUNCTION_HEAPNEXT);
332        pCreateToolhelp32Snapshot = (CREATESNAPSHOT)GetProcAddress(dllKernel, RANDOM_FUNCTION_CREATESNAPSHOT);
333
334        if (pModule32First   != NULL && pModule32Next   != NULL &&
335            pProcess32First  != NULL && pProcess32Next  != NULL &&
336            pThread32First   != NULL && pThread32Next   != NULL &&
337            pHeap32ListFirst != NULL && pHeap32ListNext != NULL &&
338            pHeap32First     != NULL && pHeap32Next     != NULL &&
339            pCreateToolhelp32Snapshot != NULL) {
340            /*
341            ** ToolHelp32 loaded successfully
342            */
343            return;
344        }
345    }
346
347    /*
348    ** Failed to load all
349    */
350
351    releaseToolHelpAPI();
352}
353
354/*
355** Windows NT NetAPI32 function pointers and handles
356*/
357
358static HINSTANCE dllNetAPI = NULL;
359
360static NETSTATISTICSGET2 pNetStatisticsGet = NULL;
361static NETAPIBUFFERSIZE pNetApiBufferSize = NULL;
362static NETAPIBUFFERFREE pNetApiBufferFree = NULL;
363
364/*
365** Windows NT Native function pointers and handles
366*/
367
368static HINSTANCE dllNTAPI = NULL;
369static NTQUERYSYSTEMINFO pNtQuerySystemInfo = NULL;
370
371/*
372** Windows NT-specific variables
373*/
374
375static bool isNTWorkstation = false;
376
377/*
378** Windows NT-specific initialization
379*/
380
381static void
382releaseDependenciesNetAPI()
383{
384    /*
385    ** Release library
386    */
387
388    if (dllNetAPI != NULL) {
389        AfxFreeLibrary(dllNetAPI);
390        dllNetAPI = NULL;
391    }
392
393    /*
394    ** Clear function pointers
395    */
396
397    pNetStatisticsGet = NULL;
398    pNetApiBufferSize = NULL;
399    pNetApiBufferFree = NULL;
400}
401
402static void
403releaseDependenciesNativeAPI()
404{
405    /*
406    ** Release library for Native API and clean up
407    */
408
409    if (dllNTAPI != NULL) {
410        AfxFreeLibrary(dllNTAPI);
411        dllNTAPI = NULL;
412    }
413    pNtQuerySystemInfo = NULL;
414}
415
416static void
417releaseDependenciesNT()
418{
419    releaseDependenciesNetAPI();
420    releaseDependenciesNativeAPI();
421}
422
423static void
424loadDependenciesNT()
425{
426    HKEY hKey;
427
428    /*
429    ** Attempt to load NetAPI32 and locate functions
430    */
431
432    if (dllNetAPI == NULL) {
433        dllNetAPI = AfxLoadLibrary(RANDOM_MODULE_NETAPI);
434    }
435
436    if (dllNetAPI != NULL) {
437        pNetStatisticsGet = (NETSTATISTICSGET2)GetProcAddress(dllNetAPI, RANDOM_FUNCTION_NETSTATISTICSGET2);
438        pNetApiBufferSize = (NETAPIBUFFERSIZE)GetProcAddress(dllNetAPI, RANDOM_FUNCTION_NETAPIBUFFERSIZE);
439        pNetApiBufferFree = (NETAPIBUFFERFREE)GetProcAddress(dllNetAPI, RANDOM_FUNCTION_NETAPIBUFFERFREE);
440
441        if (pNetStatisticsGet == NULL || pNetApiBufferSize == NULL || pNetApiBufferFree == NULL) {
442            releaseDependenciesNetAPI();
443        }
444    }
445
446    /*
447    ** Attempt to locate Native API and load functions
448    */
449
450    if (dllNTAPI == NULL) {
451        dllNTAPI = AfxLoadLibrary(RANDOM_MODULE_NTDLL);
452    }
453
454    if (dllNTAPI != NULL) {
455        pNtQuerySystemInfo = (NTQUERYSYSTEMINFO)GetProcAddress(dllNTAPI, RANDOM_FUNCTION_NTQUERYSYSTEMINFO);
456        if (pNtQuerySystemInfo == NULL) {
457            releaseDependenciesNativeAPI();
458        }
459    }
460
461    /*
462    ** Determine whether this is NT Workstation or NT Server (for querying network statistics)
463    */
464
465    if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, RANDOM_KEY_PRODUCTOPTIONS,
466                     0, KEY_READ, &hKey) == ERROR_SUCCESS) {
467        E_UINT8 szValue[32];
468        E_UINT32 status;
469        E_UINT32 uSize = sizeof(szValue);
470
471        isNTWorkstation = true;
472        status = RegQueryValueEx(hKey, RANDOM_KEY_PRODUCTTYPE, 0,
473                                 NULL, szValue, &uSize);
474
475        if (status == ERROR_SUCCESS &&
476            stricmp((const char*)szValue, RANDOM_NTWORKSTATION_TOKEN)) {
477            isNTWorkstation = false;
478        }
479
480        RegCloseKey(hKey);
481    }
482}
483
484/*
485** Helpers
486*/
487
488static void
489clearBuffer(E_PUINT8 buffer, E_UINT32 size)
490{
491    if (size == 0) {
492        return;
493    }
494
495    /*
496    ** Fills given buffer with random, but not necessarily unpredictable data
497    */
498
499    ASSERT(hashSize >= sizeof(SYSTEMTIME));
500
501    E_UINT32 copied = 0;
502    E_UINT8 data[hashSize];
503    E_UINT8 output[hashSize];
504
505    /*
506    ** Zero fill first
507    */
508
509    ZeroMemory(buffer, size);
510
511    try {
512        /*
513        ** Hash current time N times to fill the buffer
514        */
515
516        GetSystemTime((LPSYSTEMTIME)data);
517
518        while (copied < size) {
519            tiger((E_PUINT64)data, hashSize, (E_PUINT64)output);
520
521            memcpy(&buffer[copied], output, min(hashSize, (size - copied)));
522            memcpy(data, output, hashSize);
523
524            copied += hashSize;
525        }
526    } catch (...) {
527        ASSERT(0);
528    }
529
530    ZeroMemory(data, hashSize);
531    ZeroMemory(output, hashSize);
532}
533
534/*
535** Pool management
536*/
537
538static void
539setPoolPointers(E_PUINT8 page)
540{
541    isaacState   = (ISAAC_STATE*)(page + isaacStateOffset);
542    isaacOutput  =    (E_PUINT32)(page + isaacOutputOffset);
543    entropyPool  =     (E_PUINT8)(page + poolOffset);
544    outputBuffer =     (E_PUINT8)(page + outputOffset);
545    tempBuffer   =     (E_PUINT8)(page + tempOffset);
546}
547
548static E_PUINT8
549allocatePoolPage()
550{
551    E_PUINT8 newPage = (E_PUINT8)VirtualAlloc(NULL, pageSize, MEM_COMMIT, PAGE_READWRITE);
552
553    if (newPage != NULL) {
554        /*
555        ** VirtualLock doesn't work outside NT, and even there it is
556        ** not respected when no threads are active. However, I suppose
557        ** everything helps.
558        */
559
560        VirtualLock(newPage, pageSize);
561        clearBuffer(newPage, pageSize);
562    }
563
564    return newPage;
565}
566
567static void
568freePoolPage(E_PUINT8 *page)
569{
570    if (page != NULL && *page != NULL) {
571        /*
572        ** Clear page contents and unlock before releasing memory
573        */
574
575        clearBuffer(*page, pageSize);
576        VirtualUnlock(*page, pageSize);
577
578        VirtualFree(*page, 0, MEM_RELEASE);
579        *page = NULL;
580    }
581}
582
583inline static void
584touchPool()
585{
586    static E_UINT32 index = 0;
587
588    /*
589    ** Try to keep the page in memory by touching it regularly.
590    */
591
592    /*
593    ** This won't require page locking as no significant data
594    ** is touched and the page cannot be released or moved.
595    */
596
597    try {
598        if (index >= unusedSize) {
599            index = 0;
600        }
601        poolPage[index++]--;
602    } catch (...) {
603        ASSERT(0);
604    }
605}
606
607static bool
608movePool()
609{
610    /*
611    ** Try to make it more difficult to find the pool by changing page
612    ** location in memory every now and then. May also help when trying
613    ** to keep this out of swap file.
614    */
615
616    E_PUINT8 newPage = allocatePoolPage();
617
618    if (newPage != NULL) {
619        bool result = false;
620
621        EnterCriticalSection(&pageLock);
622
623        try {
624            /*
625            ** Copy only significant portion of the page
626            */
627            memcpy(&newPage[unusedSize], &poolPage[unusedSize], pageSize - unusedSize);
628            freePoolPage(&poolPage);
629
630            poolPage = newPage;
631            newPage = NULL;
632
633            setPoolPointers(poolPage);
634
635            result = true;
636        } catch (...) {
637            if (newPage != NULL) {
638                freePoolPage(&newPage);
639            }
640            ASSERT(0);
641        }
642
643        LeaveCriticalSection(&pageLock);
644
645        return result;
646    }
647    return false;
648}
649
650/*
651** Pool mixing and adding entropy
652*/
653
654inline static void
655creditPool(const E_INT32 quality)
656{
657    if (randomQuality < requiredQuality) {
658        randomQuality += quality;
659    }
660}
661
662inline static void
663mixPool(E_PUINT8 poolPtr)
664{
665    /*
666    ** We use the temporary work area, so it cannot be mixed
667    */
668
669    ASSERT(poolPtr != tempBuffer);
670
671    /*
672    ** If no pool pointer is given, use the default entropy pool
673    */
674
675    if (poolPtr == NULL) {
676        poolPtr = entropyPool;
677
678        /*
679        ** Mixing again
680        */
681
682        if (poolMixes < requiredMixes) {
683            poolMixes++;
684        }
685    }
686
687    /*
688    ** Change something every time before generating output,
689    ** increasing the counter will do (first 64 bits of the pool)
690    */
691
692    ((E_PUINT64)poolPtr)[0]++;
693
694    /*
695    ** Treat entropyPool as a circular buffer and mix (starting from n = 0) using
696    ** hash function's compression function only:
697    **
698    ** [n] ... [n + hashSize - 1] = hash_compress([n - hashSize] ... [n + dataSize - 1])
699    */
700
701    E_UINT32 i;
702
703    /*
704    ** First hashSize bytes
705    */
706
707    memcpy(tempBuffer, &poolPtr[entropyPoolSize - hashSize], hashSize);
708    memcpy(&tempBuffer[hashSize], poolPtr, dataSize);
709
710    tiger_compress((E_PUINT64)&tempBuffer[0], (E_PUINT64)poolPtr);
711    tiger_compress((E_PUINT64)&tempBuffer[blockSize], (E_PUINT64)poolPtr);
712
713    /*
714    ** Middle blocks
715    */
716
717    for (i = 0; i < (entropyPoolSize - mixSize); i += hashSize) {
718        memcpy(tempBuffer, &poolPtr[i], mixSize);
719
720        tiger_compress((E_PUINT64)&tempBuffer[0], (E_PUINT64)&poolPtr[i + hashSize]);
721        tiger_compress((E_PUINT64)&tempBuffer[blockSize], (E_PUINT64)&poolPtr[i + hashSize]);
722    }
723
724    /*
725    ** Last < mixSize bytes
726    */
727
728    for (; i < (entropyPoolSize - hashSize); i += hashSize) {
729        memcpy(tempBuffer, &poolPtr[i], entropyPoolSize - i);
730        memcpy(&tempBuffer[entropyPoolSize - i], poolPtr, mixSize - (entropyPoolSize - i));
731
732        tiger_compress((E_PUINT64)&tempBuffer[0], (E_PUINT64)&poolPtr[i + hashSize]);
733        tiger_compress((E_PUINT64)&tempBuffer[blockSize], (E_PUINT64)&poolPtr[i + hashSize]);
734    }
735
736    /*
737    ** Clean used work area
738    */
739
740    clearBuffer(tempBuffer, mixSize);
741}
742
743inline static void
744invertPool(E_PUINT8 poolPtr)
745{
746    if (poolPtr == NULL) {
747        poolPtr = entropyPool;
748    }
749
750    /*
751    ** Invert every bit in the pool
752    */
753
754    E_PUINT32 pool = (E_PUINT32)poolPtr;
755
756    for (E_UINT32 i = 0; i < (entropyPoolSize / sizeof(E_UINT32)); i++) {
757        pool[i] ^= (E_UINT32)-1;
758    }
759}
760
761static void
762addEntropyString(E_PUINT8 buffer, E_UINT32 bytes)
763{
764    static int poolPosition = 0;
765
766    if (entropyPool == NULL) {
767        return;
768    }
769
770    /*
771    ** Adds given data to the pool, when the end is reached,
772    ** remix pools contents.
773    */
774
775    EnterCriticalSection(&pageLock);
776
777    try {
778        if (buffer == NULL) {
779            mixPool(NULL);
780        } else {
781            while (bytes--) {
782                if (poolPosition > entropyPoolSize - 1) {
783                    mixPool(NULL);
784                    poolPosition = 0;
785                }
786                entropyPool[poolPosition++] ^= *buffer++;
787            }
788        }
789    } catch (...) {
790        ASSERT(0);
791    }
792
793    LeaveCriticalSection(&pageLock);
794}
795
796#define addEntropy(pointer, size) \
797    addEntropyString((E_PUINT8)(pointer), (size))
798
799#define addEntropyValue(x) \
800    entropyValue = (E_UINT32)(x); \
801    addEntropy(&entropyValue, sizeof(E_UINT32))
802
803
804/*
805** Entropy polling
806*/
807
808#define checkStatus(x) \
809    if (WaitForSingleObject(stopThreads, 0) == WAIT_OBJECT_0) { goto x; }
810
811inline static void
812fastPoll()
813{
814    static bool fixedItemsAdded = false;
815
816    E_UINT32 entropyValue;
817    POINT point;
818    LARGE_INTEGER uCounter;
819    ULARGE_INTEGER uSpace;
820    MEMORYSTATUS msStatus;
821    FILETIME ftCreationTime;
822    FILETIME ftExitTime;
823    FILETIME ftKernelTime;
824    FILETIME ftUserTime;
825    SYSTEMTIME systemTime;
826//  PSIZE_T lpMinimumWorkingSetSize;
827//   PSIZE_T lpMaximumWorkingSetSize;
828
829   
830    try {
831        checkStatus(ExitPoll_Fast);
832
833        /*
834        ** Free disk space
835        */
836
837        eraserGetFreeDiskSpace((E_IN LPVOID)"C:\\", 3, &uSpace.QuadPart);
838        addEntropy(&uSpace, sizeof(ULARGE_INTEGER));
839
840        /*
841        ** Mouse and caret position
842        */
843
844        GetCaretPos(&point);
845        addEntropy(&point, sizeof(POINT));
846        GetCursorPos(&point);
847        addEntropy(&point, sizeof(POINT));
848
849        checkStatus(ExitPoll_Fast);
850
851        /*
852        ** Process and system information
853        */
854
855        addEntropyValue(GetActiveWindow());
856        addEntropyValue(GetCapture());
857        addEntropyValue(GetClipboardOwner());
858        addEntropyValue(GetClipboardViewer());
859        addEntropyValue(GetCurrentProcess());
860        addEntropyValue(GetCurrentProcessId());
861        addEntropyValue(GetCurrentThread());
862        addEntropyValue(GetCurrentThreadId());
863        addEntropyValue(GetDesktopWindow());
864        addEntropyValue(GetFocus());
865        addEntropyValue(GetForegroundWindow());
866        addEntropyValue(GetInputState());
867        addEntropyValue(GetMessagePos());
868        addEntropyValue(GetMessageTime());
869        addEntropyValue(GetOpenClipboardWindow());
870        addEntropyValue(GetProcessHeap());
871        addEntropyValue(GetProcessWindowStation());
872
873        checkStatus(ExitPoll_Fast);
874
875        /*
876        ** Memory status
877        */
878
879        msStatus.dwLength = sizeof(MEMORYSTATUS);
880        GlobalMemoryStatus(&msStatus);
881        addEntropy(&msStatus, sizeof(MEMORYSTATUS));
882
883        /*
884        ** These exist on NT
885        */
886
887        if (GetThreadTimes(GetCurrentThread(), &ftCreationTime, &ftExitTime,
888                &ftKernelTime, &ftUserTime)) {
889            addEntropy(&ftCreationTime, sizeof(FILETIME));
890            addEntropy(&ftExitTime,     sizeof(FILETIME));
891            addEntropy(&ftKernelTime,   sizeof(FILETIME));
892            addEntropy(&ftUserTime,     sizeof(FILETIME));
893        }
894        if (GetProcessTimes(GetCurrentProcess(), &ftCreationTime, &ftExitTime,
895                &ftKernelTime, &ftUserTime)) {
896            addEntropy(&ftCreationTime, sizeof(FILETIME));
897            addEntropy(&ftExitTime,     sizeof(FILETIME));
898            addEntropy(&ftKernelTime,   sizeof(FILETIME));
899            addEntropy(&ftUserTime,     sizeof(FILETIME));
900        }
901        //if (GetProcessWorkingSetSize(GetCurrentProcess(), &uSpace.LowPart,
902        //         &uSpace.HighPart)) {
903        //    addEntropy(&uSpace, sizeof(ULARGE_INTEGER));
904        //if (GetProcessWorkingSetSize(GetCurrentProcess(), &lpMinimumWorkingSetSize,
905        //         lpMaximumWorkingSetSize)) {
906        //    addEntropy(&lpMinimumWorkingSetSize, sizeof(PSIZE_T));
907        //  addEntropy(&lpMaximumWorkingSetSize,  sizeof(PSIZE_T));
908        //}
909
910
911        if (!fixedItemsAdded) {
912            STARTUPINFO startupInfo;
913            TIME_ZONE_INFORMATION tzi;
914            SYSTEM_INFO systemInfo;
915            OSVERSIONINFO versionInfo;
916
917            checkStatus(ExitPoll_Fast);
918
919            /*
920            ** User information
921            */
922
923            if (isWindowsNT) {
924                CString strUser, strDomain;
925
926                GetUserAndDomainName(strUser, strDomain);
927                addEntropy((LPCTSTR)strUser, strUser.GetLength());
928                addEntropy((LPCTSTR)strDomain, strDomain.GetLength());
929
930                GetCurrentUserTextualSid(strUser);
931                addEntropy((LPCTSTR)strUser, strUser.GetLength());
932            }
933            addEntropyValue(GetUserDefaultLangID());
934            addEntropyValue(GetUserDefaultLCID());
935
936            checkStatus(ExitPoll_Fast);
937
938            /*
939            ** Desktop geometry and colours
940            */
941
942            addEntropyValue(GetSystemMetrics(SM_CXSCREEN));
943            addEntropyValue(GetSystemMetrics(SM_CYSCREEN));
944            addEntropyValue(GetSystemMetrics(SM_CXHSCROLL));
945            addEntropyValue(GetSystemMetrics(SM_CYHSCROLL));
946            addEntropyValue(GetSystemMetrics(SM_CXMAXIMIZED));
947            addEntropyValue(GetSystemMetrics(SM_CYMAXIMIZED));
948            addEntropyValue(GetSysColor(COLOR_3DFACE));
949            addEntropyValue(GetSysColor(COLOR_DESKTOP));
950            addEntropyValue(GetSysColor(COLOR_INFOBK));
951            addEntropyValue(GetSysColor(COLOR_WINDOW));
952            addEntropyValue(GetDialogBaseUnits());
953
954            checkStatus(ExitPoll_Fast);
955
956            /*
957            ** System information
958            */
959
960            if (GetTimeZoneInformation(&tzi) != TIME_ZONE_ID_INVALID) {
961                addEntropy(&tzi, sizeof(TIME_ZONE_INFORMATION));
962            }
963            addEntropyValue(GetSystemDefaultLangID());
964            addEntropyValue(GetSystemDefaultLCID());
965            addEntropyValue(GetOEMCP());
966            addEntropyValue(GetACP());
967            addEntropyValue(GetKeyboardLayout(0));
968            addEntropyValue(GetKeyboardType(0));
969            addEntropyValue(GetKeyboardType(1));
970            addEntropyValue(GetKeyboardType(2));
971            addEntropyValue(GetDoubleClickTime());
972            addEntropyValue(GetCaretBlinkTime());
973            addEntropyValue(GetLogicalDrives());
974
975            checkStatus(ExitPoll_Fast);
976
977            versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
978            if (GetVersionEx(&versionInfo)) {
979                addEntropy(&versionInfo, sizeof(OSVERSIONINFO));
980            }
981
982            GetSystemInfo(&systemInfo);
983            addEntropy(&systemInfo, sizeof(SYSTEM_INFO));
984
985            checkStatus(ExitPoll_Fast);
986
987
988            /*
989            ** Process startup info
990            */
991
992            startupInfo.cb = sizeof(STARTUPINFO);
993            GetStartupInfo(&startupInfo);
994            addEntropy(&startupInfo, sizeof(STARTUPINFO));
995
996            /*
997            ** Clear memory
998            */
999
1000            ZeroMemory(&startupInfo, sizeof(STARTUPINFO));
1001            ZeroMemory(&tzi,         sizeof(TIME_ZONE_INFORMATION));
1002            ZeroMemory(&systemInfo,  sizeof(SYSTEM_INFO));
1003            ZeroMemory(&versionInfo, sizeof(OSVERSIONINFO));
1004
1005            /*
1006            ** Don't add these again
1007            */
1008
1009            fixedItemsAdded = true;
1010        }
1011
1012        checkStatus(ExitPoll_Fast);
1013
1014        /*
1015        ** Counters
1016        */
1017
1018        if (QueryPerformanceCounter(&uCounter)) {
1019            addEntropy(&uCounter, sizeof(LARGE_INTEGER));
1020
1021            /*
1022            ** Ticks since last call
1023            */
1024
1025            lastCall.QuadPart = uCounter.QuadPart - lastCall.QuadPart;
1026            addEntropy(&lastCall, sizeof(LARGE_INTEGER));
1027
1028            lastCall.QuadPart = uCounter.QuadPart;
1029        }
1030
1031        addEntropyValue(GetTickCount());
1032
1033        /*
1034        ** Time
1035        */
1036
1037        GetSystemTime(&systemTime);
1038        addEntropy(&systemTime, sizeof(SYSTEMTIME));
1039
1040        checkStatus(ExitPoll_Fast);
1041
1042        /*
1043        ** Something from CryptoAPI
1044        */
1045
1046        if (cryptoContext != NULL) {
1047            E_UINT8 bytes[fastPollSize];
1048
1049            if (pCryptGenRandom(cryptoContext, fastPollSize, bytes)) {
1050                addEntropy(bytes, fastPollSize);
1051                ZeroMemory(bytes, fastPollSize);
1052            }
1053        }
1054
1055        checkStatus(ExitPoll_Fast);
1056
1057        /*
1058        ** Quality of randomness
1059        */
1060
1061        creditPool(qualityFastPoll);
1062    } catch (...) {
1063        ASSERT(0);
1064    }
1065
1066
1067    /*
1068    ** Clear memory
1069    */
1070
1071ExitPoll_Fast:
1072
1073    entropyValue = 0;
1074
1075    ZeroMemory(&point,          sizeof(POINT));
1076    ZeroMemory(&uSpace,         sizeof(ULARGE_INTEGER));
1077    ZeroMemory(&uCounter,       sizeof(LARGE_INTEGER));
1078    ZeroMemory(&msStatus,       sizeof(MEMORYSTATUS));
1079    ZeroMemory(&ftCreationTime, sizeof(FILETIME));
1080    ZeroMemory(&ftExitTime,     sizeof(FILETIME));
1081    ZeroMemory(&ftKernelTime,   sizeof(FILETIME));
1082    ZeroMemory(&ftUserTime,     sizeof(FILETIME));
1083    ZeroMemory(&systemTime,     sizeof(SYSTEMTIME));
1084}
1085
1086
1087static void
1088slowPollNT()
1089{
1090    static bool isInitialized = false;
1091    static bool isWorkstation = false;
1092
1093    static E_UINT32 cbPerfData = PERFORMANCE_BUFFER_SIZE;
1094
1095    E_PUINT8 buffer = NULL;
1096    E_UINT32 uSize;
1097    E_UINT32 status;
1098
1099    DISK_PERFORMANCE diskPerformance;
1100    HANDLE hDevice;
1101    CString strDevice;
1102
1103    E_INT32 nDrive;
1104    E_INT32 iterations = 0;
1105    E_INT32 performanceResults = 0;
1106
1107    PPERF_DATA_BLOCK pPerfData = NULL;
1108
1109    try {
1110        pPerfData = (PPERF_DATA_BLOCK)malloc(cbPerfData);
1111
1112        /*
1113        ** Get network statistics.
1114        */
1115
1116        if (dllNetAPI != NULL &&
1117            pNetStatisticsGet(NULL, isNTWorkstation ? SERVICE_WORKSTATION : SERVICE_SERVER,
1118                              0, 0, &buffer) == 0) {
1119            pNetApiBufferSize(buffer, &uSize);
1120            addEntropy(buffer, uSize);
1121
1122            pNetApiBufferFree(buffer);
1123            buffer = NULL;
1124        }
1125
1126        /*
1127        ** Get disk I/O statistics for all the hard drives
1128        */
1129        for (nDrive = 0; ; nDrive++) {
1130            /*
1131            ** If we are done, stop polling
1132            */
1133
1134            checkStatus(ExitPoll_NT);
1135
1136            /*
1137            ** Check whether we can access this device
1138            */
1139
1140            strDevice.Format("\\\\.\\PhysicalDrive%d", nDrive);
1141
1142            hDevice = CreateFile((LPCTSTR)strDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
1143                                 NULL, OPEN_EXISTING, 0, NULL);
1144
1145            if (hDevice == INVALID_HANDLE_VALUE) {
1146                break;
1147            }
1148
1149            /*
1150            ** Note: This only works if the user has turned on the disk
1151            ** performance counters with 'diskperf -y'.  These counters are off
1152            ** by default
1153            */
1154
1155            if (DeviceIoControl(hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0,
1156                                &diskPerformance, sizeof(DISK_PERFORMANCE),
1157                                &uSize, NULL)) {
1158                addEntropy(&diskPerformance, uSize);
1159            }
1160            CloseHandle(hDevice);
1161        }
1162
1163        /*
1164        ** Query performance data. Because the Win32 version of this API (through
1165        ** registry) may be buggy, try to use the NT Native API instead.
1166        */
1167
1168        if (dllNTAPI != NULL && pPerfData != NULL) {
1169            E_UINT32 uType;
1170            performanceResults = 0;
1171
1172            /*
1173            ** Scan the first 64 possible information types (we don't bother
1174            ** with increasing the buffer size as we do with the Win32
1175            ** version of the performance data read, we may miss a few classes
1176            ** but it's no big deal).  In addition the returned size value for
1177            ** some classes is wrong (eg 23 and 24 return a size of 0) so we
1178            ** miss a few more things, but again it's no big deal.  This scan
1179            ** typically yields around 20 pieces of data, there's nothing in
1180            ** the range 65...128 so chances are there won't be anything above
1181            ** there either
1182            */
1183
1184            for (uType = 0; uType < 64; uType++) {
1185                uSize = cbPerfData;
1186
1187                status = pNtQuerySystemInfo(uType, (E_UINT32)pPerfData,
1188                                            32768, (E_UINT32)&uSize);
1189
1190                if (status == ERROR_SUCCESS && uSize > 0) {
1191                    addEntropy(pPerfData, uSize);
1192                    performanceResults++;
1193
1194                    /*
1195                    ** Quitting already?
1196                    */
1197
1198                    checkStatus(ExitPoll_NT);
1199                }
1200            }
1201        }
1202
1203        /*
1204        ** If we got enough data from Native API, we can leave now without
1205        ** having to try for a Win32-level performance information query
1206        */
1207
1208        if (performanceResults < 15) {
1209            while (pPerfData != NULL && iterations++ < 10) {
1210                /*
1211                ** Done?
1212                */
1213
1214                checkStatus(ExitPoll_NT);
1215
1216                uSize = cbPerfData;
1217                status = RegQueryValueEx(HKEY_PERFORMANCE_DATA, "Global", NULL,
1218                                         NULL, (E_PUINT8)pPerfData, &uSize);
1219
1220                if (status == ERROR_SUCCESS) {
1221                    if (!memcmp(pPerfData->Signature, L"PERF", 8)) {
1222                        addEntropy(pPerfData, uSize);
1223                        /*
1224                        ** Quality of randomness
1225                        */
1226
1227                        creditPool(qualitySlowPoll);
1228                        break;
1229                    }
1230                } else if (status == ERROR_MORE_DATA) {
1231                    ZeroMemory(pPerfData, cbPerfData);
1232
1233                    cbPerfData += PERFORMANCE_BUFFER_STEP;
1234                    pPerfData = (PPERF_DATA_BLOCK)realloc(pPerfData, cbPerfData);
1235                }
1236            }
1237
1238            RegCloseKey(HKEY_PERFORMANCE_DATA);
1239        } else {
1240            /*
1241            ** Quality of randomness
1242            */
1243
1244            creditPool(qualitySlowPoll);
1245        }
1246    } catch (...) {
1247        ASSERT(0);
1248    }
1249
1250    /*
1251    ** Make like a tree and leave.
1252    */
1253
1254ExitPoll_NT:
1255
1256    if (pPerfData != NULL) {
1257        ZeroMemory(pPerfData, sizeof(PPERF_DATA_BLOCK));
1258        free(pPerfData); pPerfData = NULL;
1259    }
1260
1261    ZeroMemory(&diskPerformance, sizeof(DISK_PERFORMANCE));
1262}
1263
1264static void
1265slowPollToolHelp()
1266{
1267    PROCESSENTRY32 pe32;
1268    THREADENTRY32 te32;
1269    MODULEENTRY32 me32;
1270    HEAPLIST32 hl32;
1271    HEAPENTRY32 he32;
1272    HANDLE hSnapshot = NULL;
1273
1274    try {
1275        /*
1276        ** Make sure ToolHelp32 API is loaded
1277        */
1278
1279        if (pCreateToolhelp32Snapshot == NULL) {
1280            return;
1281        }
1282
1283        /*
1284        ** Take a snapshot of everything we can get to which is currently
1285        ** in the system
1286        */
1287
1288        hSnapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
1289
1290        if (!hSnapshot) {
1291            return;
1292        }
1293
1294        /*
1295        ** Walk through the local heap
1296        */
1297
1298        hl32.dwSize = sizeof(HEAPLIST32);
1299        he32.dwSize = sizeof(HEAPENTRY32);
1300
1301        if (pHeap32ListFirst(hSnapshot, &hl32)) {
1302            do {
1303                /*
1304                ** First add the information from the basic Heaplist32
1305                ** structure
1306                */
1307
1308                addEntropy(&hl32, sizeof(HEAPLIST32));
1309
1310                /*
1311                ** Now walk through the heap blocks getting information
1312                ** on each of them
1313                */
1314
1315                if (pHeap32First(&he32, hl32.th32ProcessID, hl32.th32HeapID)) {
1316                    do {
1317                        addEntropy(&he32, sizeof(HEAPENTRY32));
1318                        checkStatus(ExitPoll_ToolHelp);
1319                    } while (pHeap32Next(&he32));
1320                }
1321
1322                checkStatus(ExitPoll_ToolHelp);
1323
1324            } while (pHeap32ListNext(hSnapshot, &hl32));
1325        }
1326
1327        /*
1328        ** Walk through all processes
1329        */
1330
1331        pe32.dwSize = sizeof(PROCESSENTRY32);
1332
1333        if (pProcess32First(hSnapshot, &pe32)) {
1334            do {
1335                addEntropy(&pe32, sizeof(PROCESSENTRY32));
1336                checkStatus(ExitPoll_ToolHelp);
1337            } while(pProcess32Next(hSnapshot, &pe32));
1338        }
1339
1340        /*
1341        ** Walk through all threads
1342        */
1343
1344        te32.dwSize = sizeof(THREADENTRY32);
1345
1346        if (pThread32First(hSnapshot, &te32)) {
1347            do {
1348                addEntropy(&te32, sizeof(THREADENTRY32));
1349                checkStatus(ExitPoll_ToolHelp);
1350            } while (pThread32Next(hSnapshot, &te32));
1351        }
1352
1353        /*
1354        ** Walk through all modules associated with the process
1355        */
1356
1357        me32.dwSize = sizeof(MODULEENTRY32);
1358
1359        if (pModule32First(hSnapshot, &me32)) {
1360            do {
1361                addEntropy(&me32, sizeof(MODULEENTRY32));
1362                checkStatus(ExitPoll_ToolHelp);
1363            } while (pModule32Next(hSnapshot, &me32));
1364        }
1365
1366        /*
1367        ** Quality of randomness
1368        */
1369
1370        creditPool(qualitySlowPoll);
1371
1372    } catch (...) {
1373        ASSERT(0);
1374    }
1375
1376ExitPoll_ToolHelp:
1377
1378    /*
1379    ** Clean up the snapshot
1380    */
1381
1382    CloseHandle(hSnapshot);
1383
1384    ZeroMemory(&pe32, sizeof(PROCESSENTRY32));
1385    ZeroMemory(&te32, sizeof(THREADENTRY32));
1386    ZeroMemory(&me32, sizeof(MODULEENTRY32));
1387    ZeroMemory(&hl32, sizeof(HEAPLIST32));
1388    ZeroMemory(&he32, sizeof(HEAPENTRY32));
1389}
1390
1391inline static void
1392slowPoll()
1393{
1394    try {
1395        /*
1396        ** Start OS specific poll
1397        */
1398
1399        if (isWindowsNT) {
1400            slowPollNT();
1401        }
1402
1403        /*
1404        ** Should we be stopping right about now?
1405        */
1406
1407        checkStatus(ExitSlowPoll);
1408
1409        /*
1410        ** See if ToolHelp API is available
1411        */
1412
1413        slowPollToolHelp();
1414
1415        /*
1416        ** Should we be stopping right about now?
1417        */
1418
1419        checkStatus(ExitSlowPoll);
1420
1421        /*
1422        ** CryptoAPI
1423        */
1424
1425        if (cryptoContext != NULL) {
1426            E_UINT8 bytes[slowPollSize];
1427
1428            if (pCryptGenRandom(cryptoContext, slowPollSize, bytes)) {
1429                addEntropy(bytes, slowPollSize);
1430                ZeroMemory(bytes, slowPollSize);
1431
1432                /*
1433                ** Quality of randomness
1434                */
1435
1436                creditPool(qualityCryptoAPI);
1437            }
1438        }
1439
1440ExitSlowPoll:
1441
1442        /*
1443        ** Process any unmixed bytes
1444        */
1445
1446        addEntropy(NULL, 0);
1447
1448    } catch (...) {
1449        ASSERT(0);
1450    }
1451}
1452
1453/*
1454** Thread functions
1455*/
1456
1457static UINT
1458refreshThread(LPVOID)
1459{
1460    E_UINT32 waitTime = 0;
1461    E_UINT64 counter = 0;
1462    E_UINT64 difference = 0;
1463    E_UINT64 previous = 0;
1464
1465    ResetEvent(refreshThreadStopped);
1466
1467    try {
1468        while (WaitForSingleObject(stopThreads, 0) != WAIT_OBJECT_0) {
1469            touchPool();
1470
1471            if (waitTime >= poolMoveInterval) {
1472                movePool();
1473
1474                /*
1475                ** Add some more entropy to the pool
1476                */
1477
1478                waitTime -= poolMoveInterval;
1479                addEntropy(&waitTime, sizeof(E_UINT8));
1480
1481                waitTime = 0;
1482            }
1483
1484            /*
1485            ** Measure how much sleep time differs from the previous wait time
1486            ** and add some entropy to the pool.
1487            */
1488
1489            QueryPerformanceCounter((PLARGE_INTEGER)&difference);
1490
1491            /*
1492            ** Sleep for a while before retouching the pool
1493            */
1494
1495            if (WaitForSingleObject(stopThreads, poolTouchInterval) == WAIT_OBJECT_0) {
1496                break;
1497            }
1498
1499            QueryPerformanceCounter((PLARGE_INTEGER)&counter);
1500            counter -= difference;
1501
1502            if (previous > 0) {
1503                if (counter > previous) {
1504                    difference = counter - previous;
1505                } else {
1506                    difference = previous - counter;
1507                }
1508
1509                /*
1510                ** Add one byte to the entropy pool. According to ent, this data
1511                ** has ~7.24 bits of entropy for each byte, but it's not random.
1512                */
1513
1514                addEntropy(&difference, sizeof(E_UINT8));
1515            }
1516
1517            previous = counter;
1518            waitTime += poolTouchInterval;
1519
1520            /*
1521            ** The waitTime is naturally an approximate, we may have to wait in
1522            ** addEntropy for a while and Sleep isn't obviously that accurate either.
1523            */
1524        }
1525    } catch (...) {
1526        ASSERT(0);
1527    }
1528
1529    SetEvent(refreshThreadStopped);
1530    return 0;
1531}
1532
1533static UINT
1534pollThread(LPVOID)
1535{
1536    ResetEvent(pollThreadStopped);
1537
1538    try {
1539        fastPoll();
1540        slowPoll();
1541    } catch (...) {
1542        ASSERT(0);
1543    }
1544
1545    SetEvent(pollThreadStopped);
1546    return 0;
1547}
1548
1549
1550/*
1551** Exported functions
1552*/
1553
1554void
1555randomAddEntropy(E_PUINT8 buffer, E_UINT32 size)
1556{
1557    /*
1558    ** User-provided entropy, mmm.
1559    */
1560
1561    if (buffer != NULL && !AfxIsValidAddress(buffer, size)) {
1562        return;
1563    }
1564    addEntropy(buffer, size);
1565}
1566
1567bool
1568randomFill(E_PUINT8 buffer, E_UINT32 size)
1569{
1570    if (!AfxIsValidAddress(buffer, size)) {
1571        return false;
1572    }
1573
1574    /*
1575    ** Make sure we have enough entropy in the pool
1576    */
1577
1578    if (randomQuality < requiredQuality) {
1579        /*
1580        ** If not, poll for more
1581        */
1582
1583        if (enableSlowPoll) {
1584            if (WaitForSingleObject(pollThreadStopped, slowPollWait) != WAIT_OBJECT_0) {
1585                slowPoll();
1586            }
1587        }
1588
1589        /*
1590        ** If there is still not enough entropy (i.e. slow poll failed),
1591        ** run fast poll a couple of times
1592        */
1593
1594        while (randomQuality < requiredQuality) {
1595            fastPoll();
1596        }
1597    }
1598
1599    bool bResult = false;
1600
1601    EnterCriticalSection(&pageLock);
1602
1603    try {
1604        /*
1605        ** Do one final fast poll and mix the pool. If the pool hasn't been
1606        ** mixed at least requiredMixes times, continue until it has.
1607        */
1608
1609        do {
1610            fastPoll();
1611            mixPool(NULL);
1612        } while (poolMixes < requiredMixes);
1613
1614        /*
1615        ** Generate output
1616        */
1617
1618        E_UINT32 bytesToCopy;
1619        E_UINT32 bytesCopied;
1620
1621        for (bytesCopied = 0; bytesCopied < size; bytesCopied += outputSize) {
1622
1623            bytesToCopy = min(outputSize, (size - bytesCopied));
1624
1625            /*
1626            ** Copy pool contents to a temporary buffer and invert it
1627            */
1628
1629            memcpy(outputBuffer, entropyPool, entropyPoolSize);
1630            invertPool(NULL);
1631
1632            /*
1633            ** Mix the temporary buffer and the entropy pool
1634            */
1635
1636            mixPool(outputBuffer);
1637            mixPool(NULL);
1638
1639            /*
1640            ** The truly paranoid would at this point perform statistical
1641            ** tests to make sure the output really is random, and to catch
1642            ** catastrophical failures (e.g. no/wrong/repeated output).
1643            **
1644            ** Luckily, this generator seems to provide satisfactory results
1645            ** for me - and I am not that paranoid...
1646            */
1647
1648            /*
1649            ** Fold output to hide even a hash of previous pool contents,
1650            ** and copy it to the output buffer
1651            */
1652
1653            for (E_UINT32 i = 0; i < bytesToCopy; i++) {
1654                buffer[bytesCopied + i] = (E_UINT8)(outputBuffer[i] ^ outputBuffer[outputSize + i]);
1655            }
1656        }
1657
1658        /*
1659        ** Clear work area
1660        */
1661
1662        clearBuffer(outputBuffer, entropyPoolSize);
1663
1664        bResult = true;
1665    } catch (...) {
1666        ASSERT(0);
1667        try {
1668            clearBuffer(outputBuffer, entropyPoolSize);
1669            ZeroMemory(buffer, size);
1670        } catch (...) {
1671        }
1672        bResult = false;
1673    }
1674
1675    LeaveCriticalSection(&pageLock);
1676
1677    return bResult;
1678}
1679
1680/*
1681** ISAAC
1682*/
1683
1684#define isaacInd(mm, x) \
1685  (* (E_PUINT32) ((E_PINT8) (mm) + ((x) & (RANDOM_ISAAC_WORDS - 1) * sizeof(E_UINT32))))
1686
1687#define isaacStep(mix, a, b, mm, m, off, r) \
1688    ( a = ((a) ^ (mix)) + (m)[off], \
1689      x = *(m), \
1690      *(m) = y = isaacInd(mm, x) + (a) + (b), \
1691      *(r) = b = isaacInd(mm, (y) >> RANDOM_ISAAC_LOG) + x )
1692
1693#define isaacMix(a,b,c,d,e,f,g,h) \
1694    (        a ^= b << 11, d += a, \
1695     b += c, b ^= c >>  2, e += b, \
1696     c += d, c ^= d <<  8, f += c, \
1697     d += e, d ^= e >> 16, g += d, \
1698     e += f, e ^= f << 10, h += e, \
1699     f += g, f ^= g >>  4, a += f, \
1700     g += h, g ^= h <<  8, b += g, \
1701     h += a, h ^= a >>  9, c += h, \
1702     a += b                        )
1703
1704inline static void
1705isaacReload()
1706{
1707    E_UINT32 a, b;                  // Caches of a and b
1708    E_UINT32 x, y;                  // Temps needed by isaacStep macro
1709    E_PUINT32 m = isaacState->mm;   // Pointer into state array
1710    E_PUINT32 r = isaacOutput;
1711
1712    a = isaacState->a;
1713    b = isaacState->b + (++isaacState->c);
1714
1715    do {
1716        isaacStep(a << 13, a, b, isaacState->mm, m,     RANDOM_ISAAC_WORDS / 2, r);
1717        isaacStep(a >> 6,  a, b, isaacState->mm, m + 1, RANDOM_ISAAC_WORDS / 2, r + 1);
1718        isaacStep(a << 2,  a, b, isaacState->mm, m + 2, RANDOM_ISAAC_WORDS / 2, r + 2);
1719        isaacStep(a >> 16, a, b, isaacState->mm, m + 3, RANDOM_ISAAC_WORDS / 2, r + 3);
1720        r += 4;
1721    } while ((m += 4) < isaacState->mm + RANDOM_ISAAC_WORDS / 2);
1722
1723    do {
1724        isaacStep(a << 13, a, b, isaacState->mm, m,     -RANDOM_ISAAC_WORDS / 2, r);
1725        isaacStep(a >> 6,  a, b, isaacState->mm, m + 1, -RANDOM_ISAAC_WORDS / 2, r + 1);
1726        isaacStep(a << 2,  a, b, isaacState->mm, m + 2, -RANDOM_ISAAC_WORDS / 2, r + 2);
1727        isaacStep(a >> 16, a, b, isaacState->mm, m + 3, -RANDOM_ISAAC_WORDS / 2, r + 3);
1728        r += 4;
1729    } while ((m += 4) < isaacState->mm + RANDOM_ISAAC_WORDS);
1730
1731    isaacState->a = a;
1732    isaacState->b = b;
1733
1734    a = b = x = y = 0;
1735    isaacOutputPosition = 0;
1736}
1737
1738inline static void
1739isaacInit()
1740{
1741    E_INT32 i, j;
1742
1743    E_UINT32 a = 0x1367df5a;
1744    E_UINT32 b = 0x95d90059;
1745    E_UINT32 c = 0xc3163e4b;
1746    E_UINT32 d = 0x0f421ad8;
1747    E_UINT32 e = 0xd92a4a78;
1748    E_UINT32 f = 0xa51a3c49;
1749    E_UINT32 g = 0xc4efea1b;
1750    E_UINT32 h = 0x30609119;
1751
1752#if 0
1753    /*
1754    ** The values above come from this calculation
1755    */
1756
1757    a = b = c = d = e = f = g = h = 0x9e3779b9;  /* the golden ratio */
1758    for (i = 0; i < 4; ++i) {
1759        isaacMix(a, b, c, d, e, f, g, h);   /* scramble it */
1760    }
1761#endif
1762
1763    isaacState->a = isaacState->b = isaacState->c = 0;
1764
1765    for (j = 0; j < 2; j++) {
1766        for (i = 0; i < RANDOM_ISAAC_WORDS; i += 8) {
1767            a += isaacState->mm[i    ];
1768            b += isaacState->mm[i + 1];
1769            c += isaacState->mm[i + 2];
1770            d += isaacState->mm[i + 3];
1771            e += isaacState->mm[i + 4];
1772            f += isaacState->mm[i + 5];
1773            g += isaacState->mm[i + 6];
1774            h += isaacState->mm[i + 7];
1775
1776            isaacMix(a, b, c, d, e, f, g, h);
1777
1778            isaacState->mm[i    ] = a;
1779            isaacState->mm[i + 1] = b;
1780            isaacState->mm[i + 2] = c;
1781            isaacState->mm[i + 3] = d;
1782            isaacState->mm[i + 4] = e;
1783            isaacState->mm[i + 5] = f;
1784            isaacState->mm[i + 6] = g;
1785            isaacState->mm[i + 7] = h;
1786        }
1787    }
1788
1789    a = b = c = d = e = f = g = h = 0;
1790}
1791
1792void
1793isaacSeed()
1794{
1795    EnterCriticalSection(&pageLock);
1796    try {
1797        if (!randomFill((E_PUINT8)isaacState->mm, RANDOM_ISAAC_SEED_BYTES)) {
1798            /*
1799            ** Quite unlikely, but we need a seed even if randomFill fails
1800            */
1801            clearBuffer((E_PUINT8)isaacState->mm, RANDOM_ISAAC_BYTES);
1802        }
1803
1804        isaacInit();
1805        isaacReload();
1806    } catch (...) {
1807        ASSERT(0);
1808    }
1809    LeaveCriticalSection(&pageLock);
1810}
1811
1812bool
1813isaacFill(E_PUINT8 puBuffer, E_UINT32 uSize)
1814{
1815    if (!AfxIsValidAddress(puBuffer, uSize)) {
1816        return false;
1817    }
1818
1819    bool bResult = true;
1820    EnterCriticalSection(&pageLock);
1821
1822    try {
1823        E_UINT32 uAvailableData, uPosition = 0;
1824        E_PUINT8 puRandom = (E_PUINT8)isaacOutput;
1825        while (uPosition < uSize) {
1826            /*
1827            ** Refill output buffer
1828            */
1829
1830            if (isaacOutputPosition >= RANDOM_ISAAC_BYTES) {
1831                isaacReload();
1832            }
1833
1834            /*
1835            ** Amount of data to copy
1836            */
1837
1838            uAvailableData = min((RANDOM_ISAAC_BYTES - isaacOutputPosition),
1839                                 (uSize - uPosition));
1840
1841            /*
1842            ** Copy random data to buffer
1843            */
1844
1845            memcpy((LPVOID)&puBuffer[uPosition], (LPVOID)&puRandom[isaacOutputPosition],
1846                   uAvailableData);
1847
1848            /*
1849            ** Increase counters
1850            */
1851
1852            isaacOutputPosition += uAvailableData;
1853            uPosition += uAvailableData;
1854        }
1855
1856        /*
1857        ** Clear used random data from output buffer
1858        */
1859
1860        clearBuffer(puRandom, isaacOutputPosition);
1861    } catch (...) {
1862        ASSERT(0);
1863        bResult = false;
1864    }
1865
1866    LeaveCriticalSection(&pageLock);
1867    return bResult;
1868}
1869
1870/*
1871** Initialization
1872*/
1873
1874void
1875randomInit()
1876{
1877    EnterCriticalSection(&refLock);
1878
1879    try {
1880        /*
1881        ** Initialize if first reference
1882        */
1883
1884        if (refCount == 0) {
1885            /*
1886            ** Load dynamically linked libraries and locate functions
1887            */
1888
1889            loadCryptoAPI();
1890
1891            if (isWindowsNT) {
1892                loadDependenciesNT();
1893            }
1894
1895            /*
1896            ** ToolHelp32 exists on Windows 9x and NT >= 5.0
1897            */
1898
1899            loadToolHelpAPI();
1900
1901            /*
1902            ** Allocate page and set pointers
1903            */
1904
1905            EnterCriticalSection(&pageLock);
1906
1907            try {
1908                poolPage = allocatePoolPage();
1909                setPoolPointers(poolPage);
1910            } catch (...) {
1911                ASSERT(0);
1912            }
1913
1914            LeaveCriticalSection(&pageLock);
1915
1916            /*
1917            ** Start threads
1918            */
1919
1920            ResetEvent(stopThreads);
1921
1922            SetEvent(pollThreadStopped);
1923            SetEvent(refreshThreadStopped);
1924
1925            if (enableSlowPoll) {
1926                /*
1927                ** It's OK to start entropy polling thread and another one
1928                ** to touch the allocated page every now and then
1929                */
1930                AfxBeginThread(refreshThread, 0, THREAD_PRIORITY_LOWEST);
1931                AfxBeginThread(pollThread, 0);
1932            }
1933        }
1934
1935        /*
1936        ** Increase reference counter
1937        */
1938
1939        refCount++;
1940    } catch (...) {
1941        ASSERT(0);
1942    }
1943
1944    LeaveCriticalSection(&refLock);
1945}
1946
1947void
1948randomEnd()
1949{
1950    EnterCriticalSection(&refLock);
1951
1952    try {
1953        /*
1954        ** Decrease reference counter
1955        */
1956
1957        if (refCount > 0) {
1958            refCount--;
1959
1960            /*
1961            ** Clean up if nobody needs us anymore
1962            */
1963
1964            if (refCount == 0) {
1965                /*
1966                ** Stop threads
1967                */
1968
1969                SetEvent(stopThreads);
1970                WaitForSingleObject(refreshThreadStopped, threadTermination);
1971
1972                /*
1973                ** Free page and clear pointers
1974                */
1975
1976                EnterCriticalSection(&pageLock);
1977
1978                try {
1979                    freePoolPage(&poolPage);
1980
1981                    isaacState = 0;
1982                    isaacOutput = 0;
1983                    entropyPool = 0;
1984                    tempBuffer = 0;
1985                    outputBuffer = 0;
1986                } catch (...) {
1987                    ASSERT(0);
1988                }
1989
1990                LeaveCriticalSection(&pageLock);
1991
1992                /*
1993                ** Release loaded libraries
1994                */
1995
1996                releaseCryptoAPI();
1997
1998                if (isWindowsNT) {
1999                    releaseDependenciesNT();
2000                }
2001
2002                releaseToolHelpAPI();
2003            }
2004        }
2005    } catch (...) {
2006        ASSERT(0);
2007    }
2008
2009    LeaveCriticalSection(&refLock);
2010}
2011
2012class __randomInit {
2013public:
2014    __randomInit() {
2015        /*
2016        ** Assumptions
2017        */
2018
2019        /* We must be able to address the entropy pool as 32-bit words */
2020        ASSERT(entropyPoolSize % sizeof(E_UINT32) == 0);
2021
2022        /* Tiger's compression function is called twice */
2023        ASSERT(mixSize == 2 * blockSize);
2024
2025        /* Area that is hashed needs to be multiple of hash function's block size */
2026        ASSERT((hashSize + dataSize) % blockSize == 0);
2027
2028        /* Entropy pool size must be multiple of hash size */
2029        ASSERT(entropyPoolSize % hashSize == 0);
2030
2031        /* Must have enough room for work area */
2032        ASSERT((pageSize - tempOffset) >= entropyPoolSize);
2033
2034        /*
2035        ** Initialize critical sections
2036        */
2037
2038        InitializeCriticalSection(&refLock);
2039        InitializeCriticalSection(&pageLock);
2040
2041        /*
2042        ** Initialize lastCall
2043        */
2044        QueryPerformanceCounter(&lastCall);
2045
2046        /*
2047        ** Create events
2048        */
2049
2050        stopThreads          = CreateEvent(NULL, TRUE, FALSE, NULL);
2051        refreshThreadStopped = CreateEvent(NULL, TRUE, TRUE,  NULL);
2052        pollThreadStopped    = CreateEvent(NULL, TRUE, TRUE,  NULL);
2053
2054        /*
2055        ** Should we disable slow polling and memory refreshing?
2056        */
2057
2058        enableSlowPoll = false;
2059        //Currently we have disabled the background threads for adding entropy.
2060
2061
2062
2063        /*
2064
2065        CKey kReg_reg;
2066        CIniKey kReg_ini;
2067        CKey &kReg = no_registry ? kReg_ini : kReg_reg;
2068        if (kReg.Open(HKEY_CURRENT_USER, ERASER_REGISTRY_BASE)) {
2069            E_UINT32 uValue;
2070            kReg.GetValue(uValue, ERASER_RANDOM_SLOW_POLL, 0);
2071
2072            if (uValue) {
2073                enableSlowPoll = true;
2074            }
2075
2076            kReg.Close();
2077        }
2078        */
2079
2080    }
2081
2082    ~__randomInit() {
2083
2084        /*
2085        ** Just in case...
2086        */
2087
2088        randomEnd();
2089
2090        /*
2091        ** Clean up events
2092        */
2093
2094        CloseHandle(stopThreads);
2095        CloseHandle(refreshThreadStopped);
2096        CloseHandle(pollThreadStopped);
2097
2098        stopThreads = NULL;
2099        refreshThreadStopped = NULL;
2100        pollThreadStopped = NULL;
2101
2102        /*
2103        ** Destroy critical sections
2104        */
2105
2106        DeleteCriticalSection(&pageLock);
2107        DeleteCriticalSection(&refLock);
2108    }
2109};
2110
2111static __randomInit init;
Note: See TracBrowser for help on using the repository browser.