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

Revision 954, 21.3 KB checked in by lowjoel, 5 years ago (diff)

Use C# casing for the hash identifiers

  • 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        protected 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> Items
139        {
140            get
141            {
142                lock (ManagerLibrary.Instance.EntropySourceManager.sources)
143                    return ManagerLibrary.Instance.EntropySourceManager.sources;
144            }
145        }
146
147        /// <summary>
148        /// Retrieves the instance of the EntropySource with the given GUID.
149        /// </summary>
150        /// <param name="value">The GUID of the EntropySource.</param>
151        /// <returns>The EntropySource instance.</returns>
152        public static EntropySource GetInstance(Guid value)
153        {
154            try
155            {
156                lock (ManagerLibrary.Instance.EntropySourceManager.sources)
157                    return ManagerLibrary.Instance.EntropySourceManager.sources[value];
158            }
159            catch (KeyNotFoundException)
160            {
161                throw new FatalException(S._("EntropySource GUID not found: {0}",
162                    value.ToString()));
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 startup information
250            KernelAPI.STARTUPINFO startupInfo = new KernelAPI.STARTUPINFO();
251            startupInfo.cbSize = (uint)Marshal.SizeOf(typeof(KernelAPI.STARTUPINFO));
252            KernelAPI.GetStartupInfo(out startupInfo);
253            result.AddRange(StructToBuffer(startupInfo));
254
255            //System information
256            KernelAPI.SYSTEM_INFO systemInfo = new KernelAPI.SYSTEM_INFO();
257            KernelAPI.GetSystemInfo(out systemInfo);
258            result.AddRange(StructToBuffer(systemInfo));
259
260            result.AddRange(GetFastEntropy());
261            result.AddRange(GetSlowEntropy());
262            return result.ToArray();
263        }
264
265        public override Guid Guid
266        {
267            get
268            {
269                return new Guid("{11EDCECF-AD81-4e50-A73D-B9CF1F813093}");
270            }
271        }
272
273        public override string Name
274        {
275            get
276            {
277                return "Kernel Entropy Source";
278            }
279        }
280
281        public override byte[] GetEntropy()
282        {
283            List<byte> result = new List<byte>();
284            result.AddRange(GetFastEntropy());
285            result.AddRange(GetSlowEntropy());
286
287            return result.ToArray();
288        }
289
290        /// <summary>
291        /// Retrieves entropy from quick sources.
292        /// </summary>
293        public override byte[] GetFastEntropy()
294        {
295            List<byte> result = new List<byte>();
296
297            //Add the free disk space to the pool
298            result.AddRange(StructToBuffer(new DriveInfo(new DirectoryInfo(Environment.SystemDirectory).
299                Root.FullName).TotalFreeSpace));
300
301            //Miscellaneous window handles
302            result.AddRange(StructToBuffer(UserAPI.GetCapture()));
303            result.AddRange(StructToBuffer(UserAPI.GetClipboardOwner()));
304            result.AddRange(StructToBuffer(UserAPI.GetClipboardViewer()));
305            result.AddRange(StructToBuffer(UserAPI.GetDesktopWindow()));
306            result.AddRange(StructToBuffer(UserAPI.GetForegroundWindow()));
307            result.AddRange(StructToBuffer(UserAPI.GetMessagePos()));
308            result.AddRange(StructToBuffer(UserAPI.GetMessageTime()));
309            result.AddRange(StructToBuffer(UserAPI.GetOpenClipboardWindow()));
310            result.AddRange(StructToBuffer(UserAPI.GetProcessWindowStation()));
311            result.AddRange(StructToBuffer(KernelAPI.GetCurrentProcessId()));
312            result.AddRange(StructToBuffer(KernelAPI.GetCurrentThreadId()));
313            result.AddRange(StructToBuffer(KernelAPI.GetProcessHeap()));
314
315            //The caret and cursor positions
316            UserAPI.POINT point;
317            UserAPI.GetCaretPos(out point);
318            result.AddRange(StructToBuffer(point));
319            UserAPI.GetCursorPos(out point);
320            result.AddRange(StructToBuffer(point));
321
322            //Amount of free memory
323            KernelAPI.MEMORYSTATUSEX memoryStatus = new KernelAPI.MEMORYSTATUSEX();
324            memoryStatus.dwLength = (uint)Marshal.SizeOf(memoryStatus);
325            if (KernelAPI.GlobalMemoryStatusEx(ref memoryStatus))
326            {
327                result.AddRange(StructToBuffer(memoryStatus.ullAvailPhys));
328                result.AddRange(StructToBuffer(memoryStatus.ullAvailVirtual));
329                result.AddRange(StructToBuffer(memoryStatus));
330            }
331
332            //Thread execution times
333            long creationTime, exitTime, kernelTime, userTime;
334            if (KernelAPI.GetThreadTimes(KernelAPI.GetCurrentThread(), out creationTime,
335                out exitTime, out kernelTime, out userTime))
336            {
337                result.AddRange(StructToBuffer(creationTime));
338                result.AddRange(StructToBuffer(kernelTime));
339                result.AddRange(StructToBuffer(userTime));
340            }
341
342            //Process execution times
343            if (KernelAPI.GetProcessTimes(KernelAPI.GetCurrentProcess(), out creationTime,
344                out exitTime, out kernelTime, out userTime))
345            {
346                result.AddRange(StructToBuffer(creationTime));
347                result.AddRange(StructToBuffer(kernelTime));
348                result.AddRange(StructToBuffer(userTime));
349            }
350
351            //Current system time
352            result.AddRange(StructToBuffer(DateTime.Now.Ticks));
353
354            //The high resolution performance counter
355            long perfCount = 0;
356            if (KernelAPI.QueryPerformanceCounter(out perfCount))
357                result.AddRange(StructToBuffer(perfCount));
358
359            //Ticks since start up
360            uint tickCount = KernelAPI.GetTickCount();
361            if (tickCount != 0)
362                result.AddRange(StructToBuffer(tickCount));
363
364            //CryptGenRandom
365            byte[] cryptGenRandom = new byte[160];
366            if (CryptAPI.CryptGenRandom(cryptGenRandom))
367                result.AddRange(cryptGenRandom);
368
369            return result.ToArray();
370        }
371
372        /// <summary>
373        /// Retrieves entropy from sources which are relatively slower than those from
374        /// the FastAddEntropy function.
375        /// </summary>
376        public override byte[] GetSlowEntropy()
377        {
378            List<byte> result = new List<byte>();
379
380            //NetAPI statistics
381            unsafe
382            {
383                IntPtr netAPIStats = IntPtr.Zero;
384                if (NetAPI.NetStatisticsGet(null, NetAPI.SERVICE_WORKSTATION,
385                    0, 0, out netAPIStats) == 0)
386                {
387                    try
388                    {
389                        //Get the size of the buffer
390                        uint size = 0;
391                        NetAPI.NetApiBufferSize(netAPIStats, out size);
392                        byte[] entropy = new byte[size];
393
394                        //Copy the buffer
395                        Marshal.Copy(entropy, 0, netAPIStats, entropy.Length);
396
397                        //And add it to the pool
398                        result.AddRange(entropy);
399                    }
400                    finally
401                    {
402                        //Free the statistics buffer
403                        NetAPI.NetApiBufferFree(netAPIStats);
404                    }
405                }
406            }
407
408#if false
409            //Get disk I/O statistics for all the hard drives
410            for (int drive = 0; ; ++drive)
411            {
412                //Try to open the drive.
413                using (SafeFileHandle hDevice = File.CreateFile(
414                    string.Format("\\\\.\\PhysicalDrive%d", drive), 0,
415                    File.FILE_SHARE_READ | File.FILE_SHARE_WRITE, IntPtr.Zero,
416                    File.OPEN_EXISTING, 0, IntPtr.Zero))
417                {
418                    if (hDevice.IsInvalid)
419                        break;
420
421                    //This only works if the user has turned on the disk performance
422                    //counters with 'diskperf -y'. These counters are off by default
423                    if (File.DeviceIoControl(hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0,
424                        &diskPerformance, sizeof(DISK_PERFORMANCE), &uSize, NULL))
425                    {
426                        addEntropy(&diskPerformance, uSize);
427                    }
428                }
429            }
430#endif
431
432            /*
433             Query performance data. Because the Win32 version of this API (through
434             registry) may be buggy, use the NT Native API instead.
435             
436             Scan the first 64 possible information types (we don't bother
437             with increasing the buffer size as we do with the Win32
438             version of the performance data read, we may miss a few classes
439             but it's no big deal).  In addition the returned size value for
440             some classes is wrong (eg 23 and 24 return a size of 0) so we
441             miss a few more things, but again it's no big deal.  This scan
442             typically yields around 20 pieces of data, there's nothing in
443             the range 65...128 so chances are there won't be anything above
444             there either.
445            */
446            uint dataWritten = 0;
447            byte[] infoBuffer = new byte[65536];
448            uint totalEntropy = 0;
449            for (uint infoType = 0; infoType < 64; ++infoType)
450            {
451                uint sysInfo = NTAPI.NtQuerySystemInformation(infoType, infoBuffer,
452                    (uint)infoBuffer.Length, out dataWritten);
453
454                if (sysInfo == 0 /*ERROR_SUCCESS*/ && dataWritten > 0)
455                {
456                    byte[] entropy = new byte[dataWritten];
457                    Buffer.BlockCopy(infoBuffer, 0, entropy, 0, (int)dataWritten);
458                    result.AddRange(entropy);
459                    totalEntropy += dataWritten;
460                }
461            }
462
463            result.AddRange(StructToBuffer(totalEntropy));
464
465            //Finally, our good friend CryptGenRandom()
466            byte[] cryptGenRandom = new byte[1536];
467            if (CryptAPI.CryptGenRandom(cryptGenRandom))
468                result.AddRange(cryptGenRandom);
469
470            return result.ToArray();
471        }
472    }
473
474    /// <summary>
475    /// A class which uses EntropyPoll class to fetch system data as a source of
476    /// randomness at "regular" but "random" intervals
477    /// </summary>
478    public class EntropyPoller
479    {
480        /// <summary>
481        /// The algorithm used for mixing
482        /// </summary>
483        private enum PRFAlgorithms
484        {
485            Md5,
486            Sha1,
487            Ripemd160,
488            Sha256,
489            Sha384,
490            Sha512,
491        };
492
493        /// <summary>
494        /// Constructor.
495        /// </summary>
496        public EntropyPoller()
497        {
498            //Create the pool.
499            pool = new byte[sizeof(uint) << 7];
500
501            //Then start the thread which maintains the pool.
502            Thread = new Thread(Main);
503            Thread.Start();
504        }
505
506        /// <summary>
507        /// The PRNG entropy thread. This thread will run in the background, getting
508        /// random data to be used for entropy. This will maintain the integrity
509        /// of generated data from the PRNGs.
510        /// </summary>
511        private void Main()
512        {
513            //This entropy thread will utilize a polling loop.
514            DateTime lastAddedEntropy = DateTime.Now;
515            TimeSpan managerEntropySpan = new TimeSpan(0, 10, 0);
516            Stopwatch st = new Stopwatch();
517
518            while (Thread.ThreadState != System.Threading.ThreadState.AbortRequested)
519            {
520                st.Start();
521                lock (EntropySources)
522                    foreach (EntropySource src in EntropySources)
523                    {
524                        byte[] entropy = src.GetEntropy();
525                        AddEntropy(entropy);
526                    }
527
528                st.Stop();
529                // 2049 = bin '100000000001' ==> great avalanche
530                Thread.Sleep(2000 + (int)(st.ElapsedTicks % 2049L));
531                st.Reset();
532
533                // Send entropy to the PRNGs for new seeds.
534                if (DateTime.Now - lastAddedEntropy > managerEntropySpan)
535                    ManagerLibrary.Instance.PRNGManager.AddEntropy(GetPool());
536            }
537        }
538
539        /// <summary>
540        /// Stops the execution of the thread.
541        /// </summary>
542        public void Abort()
543        {
544            Thread.Abort();
545        }
546
547        /// <summary>
548        /// Adds a new Entropy Source to the Poller.
549        /// </summary>
550        /// <param name="source">The EntropySource object to add.</param>
551        public void AddEntropySource(EntropySource source)
552        {
553            lock (EntropySources)
554                EntropySources.Add(source);
555
556            AddEntropy(source.GetPrimer());
557            MixPool();
558
559            //Apply whitening effect
560            PRFAlgorithm = PRFAlgorithms.Ripemd160;
561            MixPool();
562            PRFAlgorithm = PRFAlgorithms.Sha512;
563        }
564
565        /// <summary>
566        /// Retrieves the current contents of the entropy pool.
567        /// </summary>
568        /// <returns>A byte array containing all the randomness currently found.</returns>
569        public byte[] GetPool()
570        {
571            //Mix and invert the pool
572            MixPool();
573            InvertPool();
574
575            //Return a safe copy
576            lock (poolLock)
577            {
578                byte[] result = new byte[pool.Length];
579                pool.CopyTo(result, 0);
580
581                return result;
582            }
583        }
584
585        /// <summary>
586        /// Inverts the contents of the pool
587        /// </summary>
588        private void InvertPool()
589        {
590            lock (poolLock)
591                unsafe
592                {
593                    fixed (byte* fPool = pool)
594                    {
595                        uint* pPool = (uint*)fPool;
596                        uint poolLength = (uint)(pool.Length / sizeof(uint));
597                        while (poolLength-- != 0)
598                            *pPool = (uint)(*pPool++ ^ uint.MaxValue);
599                    }
600                }
601        }
602
603        /// <summary>
604        /// Mixes the contents of the pool.
605        /// </summary>
606        private void MixPool()
607        {
608            lock (poolLock)
609            {
610                //Mix the last 128 bytes first.
611                const int mixBlockSize = 128;
612                int hashSize = PRF.HashSize / 8;
613                PRF.ComputeHash(pool, pool.Length - mixBlockSize, mixBlockSize).CopyTo(pool, 0);
614
615                //Then mix the following bytes until wraparound is required
616                int i = 0;
617                for (; i < pool.Length - hashSize; i += hashSize)
618                    Buffer.BlockCopy(PRF.ComputeHash(pool, i,
619                        i + mixBlockSize >= pool.Length ? pool.Length - i : mixBlockSize),
620                        0, pool, i, i + hashSize >= pool.Length ? pool.Length - i : hashSize);
621
622                //Mix the remaining blocks which require copying from the front
623                byte[] combinedBuffer = new byte[mixBlockSize];
624                for (; i < pool.Length; i += hashSize)
625                {
626                    Buffer.BlockCopy(pool, i, combinedBuffer, 0, pool.Length - i);
627
628                    Buffer.BlockCopy(pool, 0, combinedBuffer, pool.Length - i,
629                                mixBlockSize - (pool.Length - i));
630
631                    Buffer.BlockCopy(PRF.ComputeHash(combinedBuffer, 0, mixBlockSize), 0,
632                        pool, i, pool.Length - i > hashSize ? hashSize : pool.Length - i);
633                }
634            }
635        }
636
637        /// <summary>
638        /// Adds data which is random to the pool
639        /// </summary>
640        /// <param name="entropy">An array of data which will be XORed with pool
641        /// contents.</param>
642        public unsafe void AddEntropy(byte[] entropy)
643        {
644            lock (poolLock)
645                fixed (byte* pEntropy = entropy)
646                fixed (byte* pPool = pool)
647                {
648                    int size = entropy.Length;
649                    byte* mpEntropy = pEntropy;
650                    while (size > 0)
651                    {
652                        //Bring the pool position back to the front if we are at our end
653                        if (poolPosition >= pool.Length)
654                            poolPosition = 0;
655
656                        int amountToMix = Math.Min(size, pool.Length - poolPosition);
657                        MemoryXor(pPool + poolPosition, mpEntropy, amountToMix);
658                        mpEntropy = mpEntropy + amountToMix;
659                        size -= amountToMix;
660                    }
661                }
662        }
663
664        /// <summary>
665        /// XOR's memory a DWORD at a time.
666        /// </summary>
667        /// <param name="destination">The destination buffer to be XOR'ed</param>
668        /// <param name="source">The source buffer to XOR with</param>
669        /// <param name="size">The size of the source buffer</param>
670        private static unsafe void MemoryXor(byte* destination, byte* source, int size)
671        {
672            // XXX: Further optomisation
673            // check the memory bus frame
674            // use BYTE / WORD / DWORD as required         
675           
676            int wsize = size / sizeof(uint);
677            size -= wsize * sizeof(uint);
678            uint* d = (uint*)destination;
679            uint* s = (uint*)source;
680
681            while (wsize-- > 0)
682                *d++ ^= *s++;
683
684            if (size > 0)
685            {
686                byte* db = (byte*)d,
687                      ds = (byte*)s;
688                while (size-- > 0)
689                    *db++ ^= *ds++;
690            }
691        }
692
693        /// <summary>
694        /// PRF algorithm handle
695        /// </summary>
696        private HashAlgorithm PRF
697        {
698            get
699            {
700                Type type = null;
701                switch (PRFAlgorithm)
702                {
703                    case PRFAlgorithms.Md5:
704                        type = typeof(MD5CryptoServiceProvider);
705                        break;
706                    case PRFAlgorithms.Sha1:
707                        type = typeof(SHA1Managed);
708                        break;
709                    case PRFAlgorithms.Ripemd160:
710                        type = typeof(RIPEMD160Managed);
711                        break;
712                    case PRFAlgorithms.Sha256:
713                        type = typeof(SHA256Managed);
714                        break;
715                    case PRFAlgorithms.Sha384:
716                        type = typeof(SHA384Managed);
717                        break;
718                    default:
719                        type = typeof(SHA512Managed);
720                        break;
721                }
722
723                if (type.IsInstanceOfType(prfCache))
724                    return prfCache;
725                ConstructorInfo hashConstructor = type.GetConstructor(Type.EmptyTypes);
726                return prfCache = (HashAlgorithm)hashConstructor.Invoke(null);
727            }
728        }
729
730        /// <summary>
731        /// The last created PRF algorithm handle.
732        /// </summary>
733        private HashAlgorithm prfCache;
734
735        /// <summary>
736        /// PRF algorithm identifier
737        /// </summary>
738        private PRFAlgorithms PRFAlgorithm = PRFAlgorithms.Sha512;
739
740        /// <summary>
741        /// The pool of data which we currently maintain.
742        /// </summary>
743        private byte[] pool;
744
745        /// <summary>
746        /// The next position where entropy will be added to the pool.
747        /// </summary>
748        private int poolPosition;
749
750        /// <summary>
751        /// The lock guarding the pool array and the current entropy addition index.
752        /// </summary>
753        private object poolLock = new object();
754
755        /// <summary>
756        /// The thread object.
757        /// </summary>
758        private Thread Thread;
759
760        /// <summary>
761        /// The list of entropy sources registered with the Poller.
762        /// </summary>
763        private List<EntropySource> EntropySources = new List<EntropySource>();
764    }
765}
Note: See TracBrowser for help on using the repository browser.