source: branches/eraser6/Manager/PRNG.cs @ 502

Revision 502, 22.6 KB checked in by cjax, 6 years ago (diff)

Poller/Source? dilemma

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