source: branches/eraser6/CodeReview/Eraser.Manager/EntropySource.cs @ 1566

Revision 1566, 21.6 KB checked in by lowjoel, 5 years ago (diff)

Moved KernelApi?.GetHRForWin32Error and GetExceptionForWin32Error to the Win32ErrorCode class

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