source: branches/eraser6/Manager/EntropySource.cs @ 825

Revision 825, 21.0 KB checked in by lowjoel, 6 years ago (diff)

Fixed a problem with the 64-bit marshaller (rather, don't depend on a compatibility shim with the 32-bit marshaller, whichever way you see it) where IntPtr?'s and strings are different (holdover from LPWSTR in Windows). Fixes #97

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1/*
2 * $Id$
3 * Copyright 2008 The Eraser Project
4 * Original Author: Joel Low <lowjoel@users.sourceforge.net>
5 * Modified By: Kasra Nassiri <cjax@users.sourceforge.net>
6 *
7 * This file is part of Eraser.
8 *
9 * Eraser is free software: you can redistribute it and/or modify it under the
10 * terms of the GNU General Public License as published by the Free Software
11 * Foundation, either version 3 of the License, or (at your option) any later
12 * version.
13 *
14 * Eraser is distributed in the hope that it will be useful, but WITHOUT ANY
15 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
17 *
18 * A copy of the GNU General Public License can be found at
19 * <http://www.gnu.org/licenses/>.
20 */
21
22using System;
23using System.Collections.Generic;
24using System.Text;
25
26using System.Threading;
27using System.Security.Cryptography;
28using System.Runtime.InteropServices;
29using System.Diagnostics;
30using System.Reflection;
31using System.IO;
32using Microsoft.Win32.SafeHandles;
33using Eraser.Util;
34
35namespace Eraser.Manager
36{
37    /// <summary>
38    /// Provides an abstract interface to allow multiple sources of entropy into
39    /// the EntropyPoller class.
40    /// </summary>
41    public abstract class EntropySource
42    {
43        /// <summary>
44        /// Constructor.
45        /// </summary>
46        public EntropySource()
47        {
48        }
49
50        /// <summary>
51        /// The name of the entropy source
52        /// </summary>
53        public abstract string Name
54        {
55            get;
56        }
57
58        /// <summary>
59        /// The guid representing this entropy source
60        /// </summary>
61        public abstract Guid GUID
62        {
63            get;
64        }
65
66        /// <summary>
67        /// Gets a primer to add to the pool when this source is first initialised, to
68        /// further add entropy to the pool.
69        /// </summary>
70        /// <returns>A byte array containing the entropy.</returns>
71        public abstract byte[] GetPrimer();
72
73        /// <summary>
74        /// Retrieve entropy from a source which will have slow rate of
75        /// entropy polling.
76        /// </summary>
77        /// <returns></returns>
78        public abstract byte[] GetSlowEntropy();
79
80        /// <summary>
81        /// Retrieve entropy from a soruce which will have a fast rate of
82        /// entropy polling.
83        /// </summary>
84        /// <returns></returns>
85        public abstract byte[] GetFastEntropy();
86
87        /// <summary>
88        /// Gets entropy from the entropy source. This will be called repetitively.
89        /// </summary>
90        /// <returns>A byte array containing the entropy, both slow rate and fast rate.</returns>
91        public abstract byte[] GetEntropy();
92
93        /// <summary>
94        /// Converts value types into a byte array. This is a helper function to allow
95        /// inherited classes to convert value types into byte arrays which can be
96        /// returned to the EntropyPoller class.
97        /// </summary>
98        /// <typeparam name="T">Any value type</typeparam>
99        /// <param name="entropy">A value which will be XORed with pool contents.</param>
100        protected unsafe static byte[] StructToBuffer<T>(T entropy) where T : struct
101        {
102            int sizeofObject = Marshal.SizeOf(entropy);
103            IntPtr memory = Marshal.AllocHGlobal(sizeofObject);
104            try
105            {
106                Marshal.StructureToPtr(entropy, memory, false);
107                byte[] dest = new byte[sizeofObject];
108
109                //Copy the memory
110                Marshal.Copy(memory, dest, 0, sizeofObject);
111                return dest;
112            }
113            finally
114            {
115                Marshal.FreeHGlobal(memory);
116            }
117        }
118    }
119
120    /// <summary>
121    /// A class which manages all of the instances of the EntropySources
122    /// available. Plugins could register their entropy sources via this class.
123    /// </summary>
124    public class EntropySourceManager
125    {
126        /// <summary>
127        /// Constructor.
128        /// </summary>
129        public EntropySourceManager()
130        {
131            entropyThread.AddEntropySource(new KernelEntropySource());
132        }
133
134        /// <summary>
135        /// Retrieves all currently registered erasure methods.
136        /// </summary>
137        /// <returns>A mutable list, with an instance of each EntropySource.</returns>
138        public static Dictionary<Guid, EntropySource> GetAll()
139        {
140            lock (ManagerLibrary.Instance.EntropySourceManager.sources)
141                return ManagerLibrary.Instance.EntropySourceManager.sources;
142        }
143
144        /// <summary>
145        /// Retrieves the instance of the EntropySource with the given GUID.
146        /// </summary>
147        /// <param name="guid">The GUID of the EntropySource.</param>
148        /// <returns>The EntropySource instance.</returns>
149        public static EntropySource GetInstance(Guid guid)
150        {
151            try
152            {
153                lock (ManagerLibrary.Instance.EntropySourceManager.sources)
154                    return ManagerLibrary.Instance.EntropySourceManager.sources[guid];
155            }
156            catch (KeyNotFoundException)
157            {
158                throw new FatalException(S._("EntropySource GUID not found: {0}",
159                    guid.ToString()));
160            }
161        }
162
163        /// <summary>
164        /// Allows plugins to register EntropySources with the main program. Thread-safe.
165        /// </summary>
166        /// <param name="method"></param>
167        public static void Register(EntropySource source)
168        {
169            EntropySourceManager manager = ManagerLibrary.Instance.EntropySourceManager;
170            lock (ManagerLibrary.Instance.EntropySourceManager.sources)
171                manager.sources.Add(source.GUID, source);
172            manager.entropyThread.AddEntropySource(source);
173        }
174
175        /// <summary>
176        /// Performs the MethodUnregistered event handlers.
177        /// </summary>
178        /// <param name="guid">The GUID of the unregistered erasure method.</param>
179        private static void OnEntropySourceActivated(Guid guid)
180        {
181            if (EntropySourceActivated != null)
182                EntropySourceActivated(guid);
183        }
184
185        /// <summary>
186        /// Gets the entropy poller instance associated with this manager.
187        /// </summary>
188        public EntropyPoller Poller
189        {
190            get
191            {
192                return entropyThread;
193            }
194        }
195
196        /// <summary>
197        /// The delegate prototype of Entropy Source Registered event
198        /// </summary>
199        /// <param name="guid"></param>
200        public delegate void OnEntropySourceActivatedFunction(Guid guid);
201
202        /// <summary>
203        /// Global static instance of the EntropySourceRegisteredFunction,
204        /// called whenever the EntropySourceManager.Register is invoked.
205        /// </summary>
206        public static event OnEntropySourceActivatedFunction EntropySourceActivated;
207       
208        /// <summary>
209        /// The list of currently registered Entropy Sources.
210        /// </summary>
211        private Dictionary<Guid, EntropySource> sources = new Dictionary<Guid, EntropySource>();
212
213        /// <summary>
214        /// The entropy thread gathering entropy for the RNGs.
215        /// </summary>
216        private EntropyPoller entropyThread = new EntropyPoller();
217    };
218       
219    /// <summary>
220    /// Provides means of generating random entropy from the system or user space
221    /// randomness.
222    /// This class is hardcoded into the Manager Library as we need at least one
223    /// instance of such behaviour within our system. The other classes could be
224    /// implemented as plugins, managed by EntropySourceManager.
225    /// </summary>
226    public class KernelEntropySource : EntropySource
227    {
228        public override byte[] GetPrimer()
229        {
230            List<byte> result = new List<byte>();
231
232            //Process startup information
233            KernelAPI.STARTUPINFO startupInfo = new KernelAPI.STARTUPINFO();
234            startupInfo.cbSize = (uint)Marshal.SizeOf(typeof(KernelAPI.STARTUPINFO));
235            KernelAPI.GetStartupInfo(out startupInfo);
236            result.AddRange(StructToBuffer(startupInfo));
237
238            //System information
239            KernelAPI.SYSTEM_INFO systemInfo = new KernelAPI.SYSTEM_INFO();
240            KernelAPI.GetSystemInfo(out systemInfo);
241            result.AddRange(StructToBuffer(systemInfo));
242
243            result.AddRange(GetFastEntropy());
244            result.AddRange(GetSlowEntropy());
245            return result.ToArray();
246        }
247
248        public override Guid GUID
249        {
250            get
251            {
252                return new Guid("{11EDCECF-AD81-4e50-A73D-B9CF1F813093}");
253            }
254        }
255
256        public override string Name
257        {
258            get
259            {
260                return "Kernel Entropy Source";
261            }
262        }
263
264        public override byte[] GetEntropy()
265        {
266            List<byte> result = new List<byte>();
267            result.AddRange(GetFastEntropy());
268            result.AddRange(GetSlowEntropy());
269
270            return result.ToArray();
271        }
272
273        /// <summary>
274        /// Retrieves entropy from quick sources.
275        /// </summary>
276        public override byte[] GetFastEntropy()
277        {
278            List<byte> result = new List<byte>();
279
280            //Add the free disk space to the pool
281            result.AddRange(StructToBuffer(new DriveInfo(new DirectoryInfo(Environment.SystemDirectory).
282                Root.FullName).TotalFreeSpace));
283
284            //Miscellaneous window handles
285            result.AddRange(StructToBuffer(UserAPI.GetCapture()));
286            result.AddRange(StructToBuffer(UserAPI.GetClipboardOwner()));
287            result.AddRange(StructToBuffer(UserAPI.GetClipboardViewer()));
288            result.AddRange(StructToBuffer(UserAPI.GetDesktopWindow()));
289            result.AddRange(StructToBuffer(UserAPI.GetForegroundWindow()));
290            result.AddRange(StructToBuffer(UserAPI.GetMessagePos()));
291            result.AddRange(StructToBuffer(UserAPI.GetMessageTime()));
292            result.AddRange(StructToBuffer(UserAPI.GetOpenClipboardWindow()));
293            result.AddRange(StructToBuffer(UserAPI.GetProcessWindowStation()));
294            result.AddRange(StructToBuffer(KernelAPI.GetCurrentProcessId()));
295            result.AddRange(StructToBuffer(KernelAPI.GetCurrentThreadId()));
296            result.AddRange(StructToBuffer(KernelAPI.GetProcessHeap()));
297
298            //The caret and cursor positions
299            UserAPI.POINT point;
300            UserAPI.GetCaretPos(out point);
301            result.AddRange(StructToBuffer(point));
302            UserAPI.GetCursorPos(out point);
303            result.AddRange(StructToBuffer(point));
304
305            //Amount of free memory
306            KernelAPI.MEMORYSTATUSEX memoryStatus = new KernelAPI.MEMORYSTATUSEX();
307            memoryStatus.dwLength = (uint)Marshal.SizeOf(memoryStatus);
308            if (KernelAPI.GlobalMemoryStatusEx(ref memoryStatus))
309            {
310                result.AddRange(StructToBuffer(memoryStatus.ullAvailPhys));
311                result.AddRange(StructToBuffer(memoryStatus.ullAvailVirtual));
312                result.AddRange(StructToBuffer(memoryStatus));
313            }
314
315            //Thread execution times
316            long creationTime, exitTime, kernelTime, userTime;
317            if (KernelAPI.GetThreadTimes(KernelAPI.GetCurrentThread(), out creationTime,
318                out exitTime, out kernelTime, out userTime))
319            {
320                result.AddRange(StructToBuffer(creationTime));
321                result.AddRange(StructToBuffer(kernelTime));
322                result.AddRange(StructToBuffer(userTime));
323            }
324
325            //Process execution times
326            if (KernelAPI.GetProcessTimes(KernelAPI.GetCurrentProcess(), out creationTime,
327                out exitTime, out kernelTime, out userTime))
328            {
329                result.AddRange(StructToBuffer(creationTime));
330                result.AddRange(StructToBuffer(kernelTime));
331                result.AddRange(StructToBuffer(userTime));
332            }
333
334            //Current system time
335            result.AddRange(StructToBuffer(DateTime.Now.Ticks));
336
337            //The high resolution performance counter
338            long perfCount = 0;
339            if (KernelAPI.QueryPerformanceCounter(out perfCount))
340                result.AddRange(StructToBuffer(perfCount));
341
342            //Ticks since start up
343            uint tickCount = KernelAPI.GetTickCount();
344            if (tickCount != 0)
345                result.AddRange(StructToBuffer(tickCount));
346
347            //CryptGenRandom
348            byte[] cryptGenRandom = new byte[160];
349            if (CryptAPI.CryptGenRandom(cryptGenRandom))
350                result.AddRange(cryptGenRandom);
351
352            return result.ToArray();
353        }
354
355        /// <summary>
356        /// Retrieves entropy from sources which are relatively slower than those from
357        /// the FastAddEntropy function.
358        /// </summary>
359        public override byte[] GetSlowEntropy()
360        {
361            List<byte> result = new List<byte>();
362
363            //NetAPI statistics
364            unsafe
365            {
366                IntPtr netAPIStats = IntPtr.Zero;
367                if (NetAPI.NetStatisticsGet(null, NetAPI.SERVICE_WORKSTATION,
368                    0, 0, out netAPIStats) == 0)
369                {
370                    try
371                    {
372                        //Get the size of the buffer
373                        uint size = 0;
374                        NetAPI.NetApiBufferSize(netAPIStats, out size);
375                        byte[] entropy = new byte[size];
376
377                        //Copy the buffer
378                        Marshal.Copy(entropy, 0, netAPIStats, entropy.Length);
379
380                        //And add it to the pool
381                        result.AddRange(entropy);
382                    }
383                    finally
384                    {
385                        //Free the statistics buffer
386                        NetAPI.NetApiBufferFree(netAPIStats);
387                    }
388                }
389            }
390
391#if false
392            //Get disk I/O statistics for all the hard drives
393            for (int drive = 0; ; ++drive)
394            {
395                //Try to open the drive.
396                using (SafeFileHandle hDevice = File.CreateFile(
397                    string.Format("\\\\.\\PhysicalDrive%d", drive), 0,
398                    File.FILE_SHARE_READ | File.FILE_SHARE_WRITE, IntPtr.Zero,
399                    File.OPEN_EXISTING, 0, IntPtr.Zero))
400                {
401                    if (hDevice.IsInvalid)
402                        break;
403
404                    //This only works if the user has turned on the disk performance
405                    //counters with 'diskperf -y'. These counters are off by default
406                    if (File.DeviceIoControl(hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0,
407                        &diskPerformance, sizeof(DISK_PERFORMANCE), &uSize, NULL))
408                    {
409                        addEntropy(&diskPerformance, uSize);
410                    }
411                }
412            }
413#endif
414
415            /*
416             Query performance data. Because the Win32 version of this API (through
417             registry) may be buggy, use the NT Native API instead.
418             
419             Scan the first 64 possible information types (we don't bother
420             with increasing the buffer size as we do with the Win32
421             version of the performance data read, we may miss a few classes
422             but it's no big deal).  In addition the returned size value for
423             some classes is wrong (eg 23 and 24 return a size of 0) so we
424             miss a few more things, but again it's no big deal.  This scan
425             typically yields around 20 pieces of data, there's nothing in
426             the range 65...128 so chances are there won't be anything above
427             there either.
428            */
429            uint dataWritten = 0;
430            byte[] infoBuffer = new byte[65536];
431            uint totalEntropy = 0;
432            for (uint infoType = 0; infoType < 64; ++infoType)
433            {
434                uint sysInfo = NTAPI.NtQuerySystemInformation(infoType, infoBuffer,
435                    (uint)infoBuffer.Length, out dataWritten);
436
437                if (sysInfo == 0 /*ERROR_SUCCESS*/ && dataWritten > 0)
438                {
439                    byte[] entropy = new byte[dataWritten];
440                    Buffer.BlockCopy(infoBuffer, 0, entropy, 0, (int)dataWritten);
441                    result.AddRange(entropy);
442                    totalEntropy += dataWritten;
443                }
444            }
445
446            result.AddRange(StructToBuffer(totalEntropy));
447
448            //Finally, our good friend CryptGenRandom()
449            byte[] cryptGenRandom = new byte[1536];
450            if (CryptAPI.CryptGenRandom(cryptGenRandom))
451                result.AddRange(cryptGenRandom);
452
453            return result.ToArray();
454        }
455    }
456
457    /// <summary>
458    /// A class which uses EntropyPoll class to fetch system data as a source of
459    /// randomness at "regular" but "random" intervals
460    /// </summary>
461    public class EntropyPoller
462    {
463        /// <summary>
464        /// The algorithm used for mixing
465        /// </summary>
466        private enum PRFAlgorithms
467        {
468            MD5,
469            SHA1,
470            RIPEMD160,
471            SHA256,
472            SHA384,
473            SHA512,
474        };
475
476        /// <summary>
477        /// Constructor.
478        /// </summary>
479        public EntropyPoller()
480        {
481            //Create the pool.
482            pool = new byte[sizeof(uint) << 7];
483
484            //Then start the thread which maintains the pool.
485            Thread = new Thread(delegate()
486                {
487                    this.Main();
488                }
489            );
490            Thread.Start();
491        }
492
493        /// <summary>
494        /// The PRNG entropy thread. This thread will run in the background, getting
495        /// random data to be used for entropy. This will maintain the integrity
496        /// of generated data from the PRNGs.
497        /// </summary>
498        private void Main()
499        {
500            //This entropy thread will utilize a polling loop.
501            DateTime lastAddedEntropy = DateTime.Now;
502            TimeSpan managerEntropySpan = new TimeSpan(0, 10, 0);
503            Stopwatch st = new Stopwatch();
504
505            while (Thread.ThreadState != System.Threading.ThreadState.AbortRequested)
506            {
507                st.Start();
508                lock (EntropySources)
509                    foreach (EntropySource src in EntropySources)
510                    {
511                        byte[] entropy = src.GetEntropy();
512                        AddEntropy(entropy);
513                    }
514
515                st.Stop();
516                // 2049 = bin '100000000001' ==> great avalanche
517                Thread.Sleep(2000 + (int)(st.ElapsedTicks % 2049L));
518                st.Reset();
519
520                // Send entropy to the PRNGs for new seeds.
521                if (DateTime.Now - lastAddedEntropy > managerEntropySpan)
522                    ManagerLibrary.Instance.PRNGManager.AddEntropy(GetPool());
523            }
524        }
525
526        /// <summary>
527        /// Stops the execution of the thread.
528        /// </summary>
529        public void Abort()
530        {
531            Thread.Abort();
532        }
533
534        /// <summary>
535        /// Adds a new Entropy Source to the Poller.
536        /// </summary>
537        /// <param name="source">The EntropySource object to add.</param>
538        public void AddEntropySource(EntropySource source)
539        {
540            lock (EntropySources)
541                EntropySources.Add(source);
542
543            AddEntropy(source.GetPrimer());
544            MixPool();
545
546            //Apply whitening effect
547            PRFAlgorithm = PRFAlgorithms.RIPEMD160;
548            MixPool();
549            PRFAlgorithm = PRFAlgorithms.SHA512;
550        }
551
552        /// <summary>
553        /// Retrieves the current contents of the entropy pool.
554        /// </summary>
555        /// <returns>A byte array containing all the randomness currently found.</returns>
556        public byte[] GetPool()
557        {
558            //Mix and invert the pool
559            MixPool();
560            InvertPool();
561
562            //Return a safe copy
563            lock (pool)
564            {
565                byte[] result = new byte[pool.Length];
566                pool.CopyTo(result, 0);
567
568                return result;
569            }
570        }
571
572        /// <summary>
573        /// Inverts the contents of the pool
574        /// </summary>
575        private void InvertPool()
576        {
577            lock (poolLock)
578                unsafe
579                {
580                    fixed (byte* fPool = pool)
581                    {
582                        uint* pPool = (uint*)fPool;
583                        uint poolLength = (uint)(pool.Length / sizeof(uint));
584                        while (poolLength-- != 0)
585                            *pPool = (uint)(*pPool++ ^ uint.MaxValue);
586                    }
587                }
588        }
589
590        /// <summary>
591        /// Mixes the contents of the pool.
592        /// </summary>
593        private void MixPool()
594        {
595            lock (poolLock)
596            {
597                //Mix the last 128 bytes first.
598                const int mixBlockSize = 128;
599                int hashSize = PRF.HashSize / 8;
600                PRF.ComputeHash(pool, pool.Length - mixBlockSize, mixBlockSize).CopyTo(pool, 0);
601
602                //Then mix the following bytes until wraparound is required
603                int i = 0;
604                for (; i < pool.Length - hashSize; i += hashSize)
605                    Buffer.BlockCopy(PRF.ComputeHash(pool, i,
606                        i + mixBlockSize >= pool.Length ? pool.Length - i : mixBlockSize),
607                        0, pool, i, i + hashSize >= pool.Length ? pool.Length - i : hashSize);
608
609                //Mix the remaining blocks which require copying from the front
610                byte[] combinedBuffer = new byte[mixBlockSize];
611                for (; i < pool.Length; i += hashSize)
612                {
613                    Buffer.BlockCopy(pool, i, combinedBuffer, 0, pool.Length - i);
614
615                    Buffer.BlockCopy(pool, 0, combinedBuffer, pool.Length - i,
616                                mixBlockSize - (pool.Length - i));
617
618                    Buffer.BlockCopy(PRF.ComputeHash(combinedBuffer, 0, mixBlockSize), 0,
619                        pool, i, pool.Length - i > hashSize ? hashSize : pool.Length - i);
620                }
621            }
622        }
623
624        /// <summary>
625        /// Adds data which is random to the pool
626        /// </summary>
627        /// <param name="entropy">An array of data which will be XORed with pool
628        /// contents.</param>
629        public unsafe void AddEntropy(byte[] entropy)
630        {
631            lock (poolLock)
632                fixed (byte* pEntropy = entropy)
633                fixed (byte* pPool = pool)
634                {
635                    int size = entropy.Length;
636                    byte* mpEntropy = pEntropy;
637                    while (size > 0)
638                    {
639                        //Bring the pool position back to the front if we are at our end
640                        if (poolPosition >= pool.Length)
641                            poolPosition = 0;
642
643                        int amountToMix = Math.Min(size, pool.Length - poolPosition);
644                        MemoryXor(pPool + poolPosition, mpEntropy, amountToMix);
645                        mpEntropy = mpEntropy + amountToMix;
646                        size -= amountToMix;
647                    }
648                }
649        }
650
651        /// <summary>
652        /// XOR's memory a DWORD at a time.
653        /// </summary>
654        /// <param name="destination">The destination buffer to be XOR'ed</param>
655        /// <param name="source">The source buffer to XOR with</param>
656        /// <param name="size">The size of the source buffer</param>
657        private static unsafe void MemoryXor(byte* destination, byte* source, int size)
658        {
659            // XXX: Further optomisation
660            // check the memory bus frame
661            // use BYTE / WORD / DWORD as required         
662           
663            int wsize = size / sizeof(uint);
664            size -= wsize * sizeof(uint);
665            uint* d = (uint*)destination;
666            uint* s = (uint*)source;
667
668            while (wsize-- > 0)
669                *d++ ^= *s++;
670
671            if (size > 0)
672            {
673                byte* db = (byte*)d,
674                      ds = (byte*)s;
675                while (size-- > 0)
676                    *db++ ^= *ds++;
677            }
678        }
679
680        /// <summary>
681        /// PRF algorithm handle
682        /// </summary>
683        private HashAlgorithm PRF
684        {
685            get
686            {
687                Type type = null;
688                switch (PRFAlgorithm)
689                {
690                    case PRFAlgorithms.MD5:
691                        type = typeof(MD5CryptoServiceProvider);
692                        break;
693                    case PRFAlgorithms.SHA1:
694                        type = typeof(SHA1Managed);
695                        break;
696                    case PRFAlgorithms.RIPEMD160:
697                        type = typeof(RIPEMD160Managed);
698                        break;
699                    case PRFAlgorithms.SHA256:
700                        type = typeof(SHA256Managed);
701                        break;
702                    case PRFAlgorithms.SHA384:
703                        type = typeof(SHA384Managed);
704                        break;
705                    default:
706                        type = typeof(SHA512Managed);
707                        break;
708                }
709
710                if (type.IsInstanceOfType(prfCache))
711                    return prfCache;
712                ConstructorInfo hashConstructor = type.GetConstructor(Type.EmptyTypes);
713                return prfCache = (HashAlgorithm)hashConstructor.Invoke(null);
714            }
715        }
716
717        /// <summary>
718        /// The last created PRF algorithm handle.
719        /// </summary>
720        private HashAlgorithm prfCache;
721
722        /// <summary>
723        /// PRF algorithm identifier
724        /// </summary>
725        private PRFAlgorithms PRFAlgorithm = PRFAlgorithms.SHA512;
726
727        /// <summary>
728        /// The pool of data which we currently maintain.
729        /// </summary>
730        private byte[] pool;
731
732        /// <summary>
733        /// The next position where entropy will be added to the pool.
734        /// </summary>
735        private int poolPosition = 0;
736
737        /// <summary>
738        /// The lock guarding the pool array and the current entropy addition index.
739        /// </summary>
740        private object poolLock = new object();
741
742        /// <summary>
743        /// The thread object.
744        /// </summary>
745        private Thread Thread;
746
747        /// <summary>
748        /// The list of entropy sources registered with the Poller.
749        /// </summary>
750        private List<EntropySource> EntropySources = new List<EntropySource>();
751    }
752}
Note: See TracBrowser for help on using the repository browser.