Changeset 502


Ignore:
Timestamp:
11/11/08 00:04:36 (6 years ago)
Author:
cjax
Message:

Poller/Source? dilemma

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/eraser6/Manager/PRNG.cs

    r479 r502  
    221221 
    222222    /// <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> 
    223508    /// A class which uses EntropyPoll class to fetch system data as a source of 
    224509    /// randomness at "regular" but "random" intervals 
    225510    /// </summary> 
    226     class EntropyPoller 
     511    public class EntropyPoller : KernelEntropySource 
    227512    { 
    228513        /// <summary> 
     
    278563                    } 
    279564                 
    280                 st.Stop();  
     565                st.Stop(); 
     566                // 2049 = bin '100000000001', great avalanche 
    281567                Thread.Sleep(2000 + (int)(st.ElapsedTicks % 2049L)); 
    282568                st.Reset(); 
    283569 
    284                 //Send entropy to the PRNGs for new seeds. 
     570                // Send entropy to the PRNGs for new seeds. 
    285571                if (DateTime.Now - lastAddedEntropy > managerEntropySpan) 
    286572                    ManagerLibrary.Instance.PRNGManager.AddEntropy(GetPool()); 
     
    510796        private List<EntropySource> EntropySources = new List<EntropySource>(); 
    511797    } 
    512      
    513     /// <summary> 
    514     /// Provides an abstract interface to allow multiple sources of entropy into 
    515     /// the EntropyPoller class. 
    516     /// </summary> 
    517     public abstract class EntropySource 
    518     { 
    519         /// <summary> 
    520         /// Constructor. 
    521         /// </summary> 
    522         public EntropySource() 
    523         { 
    524         } 
    525  
    526         /// <summary> 
    527         /// Gets a primer to add to the pool when this source is first initialised, to 
    528         /// further add entropy to the pool. 
    529         /// </summary> 
    530         /// <returns>A byte array containing the entropy.</returns> 
    531         public abstract byte[] GetPrimer(); 
    532  
    533         /// <summary> 
    534         /// Gets entropy from the entropy source. This will be called repetitively. 
    535         /// </summary> 
    536         /// <returns>A byte array containing the entropy.</returns> 
    537         public abstract byte[] GetEntropy(); 
    538  
    539         /// <summary> 
    540         /// Converts value types into a byte array. This is a helper function to allow 
    541         /// inherited classes to convert value types into byte arrays which can be 
    542         /// returned to the EntropyPoller class. 
    543         /// </summary> 
    544         /// <typeparam name="T">Any value type</typeparam> 
    545         /// <param name="entropy">A value which will be XORed with pool contents.</param> 
    546         protected unsafe static byte[] StructToBuffer<T>(T entropy) where T: struct 
    547         { 
    548             int sizeofObject = Marshal.SizeOf(entropy); 
    549             IntPtr memory = Marshal.AllocHGlobal(sizeofObject); 
    550             try 
    551             { 
    552                 Marshal.StructureToPtr(entropy, memory, false); 
    553                 byte[] dest = new byte[sizeofObject]; 
    554  
    555                 //Copy the memory 
    556                 Marshal.Copy(memory, dest, 0, sizeofObject); 
    557                 return dest; 
    558             } 
    559             finally 
    560             { 
    561                 Marshal.FreeHGlobal(memory); 
    562             } 
    563         } 
    564     } 
    565  
    566     /// <summary> 
    567     /// Provides means of generating random entropy from the system or user space 
    568     /// randomness. 
    569     /// </summary> 
    570     internal class KernelEntropySource : EntropySource 
    571     { 
    572         public override byte[] GetPrimer() 
    573         { 
    574             List<byte> result = new List<byte>(); 
    575  
    576             //Process startup information 
    577             KernelAPI.STARTUPINFO startupInfo = new KernelAPI.STARTUPINFO(); 
    578             KernelAPI.GetStartupInfo(out startupInfo); 
    579             result.AddRange(StructToBuffer(startupInfo)); 
    580  
    581             //System information 
    582             KernelAPI.SYSTEM_INFO systemInfo = new KernelAPI.SYSTEM_INFO(); 
    583             KernelAPI.GetSystemInfo(out systemInfo); 
    584             result.AddRange(StructToBuffer(systemInfo)); 
    585  
    586             result.AddRange(GetFastEntropy()); 
    587             result.AddRange(GetSlowEntropy()); 
    588             return result.ToArray(); 
    589         } 
    590  
    591         public override byte[] GetEntropy() 
    592         { 
    593             List<byte> result = new List<byte>(); 
    594             result.AddRange(GetFastEntropy()); 
    595             result.AddRange(GetSlowEntropy()); 
    596              
    597             return result.ToArray(); 
    598         } 
    599  
    600         /// <summary> 
    601         /// Retrieves entropy from quick sources. 
    602         /// </summary> 
    603         private byte[] GetFastEntropy() 
    604         { 
    605             List<byte> result = new List<byte>(); 
    606  
    607             //Add the free disk space to the pool 
    608             result.AddRange(StructToBuffer(new DriveInfo(new DirectoryInfo(Environment.SystemDirectory). 
    609                 Root.FullName).TotalFreeSpace)); 
    610  
    611             //Miscellaneous window handles 
    612             result.AddRange(StructToBuffer(UserAPI.GetCapture())); 
    613             result.AddRange(StructToBuffer(UserAPI.GetClipboardOwner())); 
    614             result.AddRange(StructToBuffer(UserAPI.GetClipboardViewer())); 
    615             result.AddRange(StructToBuffer(UserAPI.GetDesktopWindow())); 
    616             result.AddRange(StructToBuffer(UserAPI.GetForegroundWindow())); 
    617             result.AddRange(StructToBuffer(UserAPI.GetMessagePos())); 
    618             result.AddRange(StructToBuffer(UserAPI.GetMessageTime())); 
    619             result.AddRange(StructToBuffer(UserAPI.GetOpenClipboardWindow())); 
    620             result.AddRange(StructToBuffer(UserAPI.GetProcessWindowStation())); 
    621             result.AddRange(StructToBuffer(KernelAPI.GetCurrentProcessId())); 
    622             result.AddRange(StructToBuffer(KernelAPI.GetCurrentThreadId())); 
    623             result.AddRange(StructToBuffer(KernelAPI.GetProcessHeap())); 
    624  
    625             //The caret and cursor positions 
    626             UserAPI.POINT point; 
    627             UserAPI.GetCaretPos(out point); 
    628             result.AddRange(StructToBuffer(point)); 
    629             UserAPI.GetCursorPos(out point); 
    630             result.AddRange(StructToBuffer(point)); 
    631  
    632             //Amount of free memory 
    633             KernelAPI.MEMORYSTATUSEX memoryStatus = new KernelAPI.MEMORYSTATUSEX(); 
    634             memoryStatus.dwLength = (uint)Marshal.SizeOf(memoryStatus); 
    635             if (KernelAPI.GlobalMemoryStatusEx(ref memoryStatus)) 
    636             { 
    637                 result.AddRange(StructToBuffer(memoryStatus.ullAvailPhys)); 
    638                 result.AddRange(StructToBuffer(memoryStatus.ullAvailVirtual)); 
    639                 result.AddRange(StructToBuffer(memoryStatus)); 
    640             } 
    641  
    642             //Thread execution times 
    643             long creationTime, exitTime, kernelTime, userTime; 
    644             if (KernelAPI.GetThreadTimes(KernelAPI.GetCurrentThread(), out creationTime, 
    645                 out exitTime, out kernelTime, out userTime)) 
    646             { 
    647                 result.AddRange(StructToBuffer(creationTime)); 
    648                 result.AddRange(StructToBuffer(kernelTime)); 
    649                 result.AddRange(StructToBuffer(userTime)); 
    650             } 
    651  
    652             //Process execution times 
    653             if (KernelAPI.GetProcessTimes(KernelAPI.GetCurrentProcess(), out creationTime, 
    654                 out exitTime, out kernelTime, out userTime)) 
    655             { 
    656                 result.AddRange(StructToBuffer(creationTime)); 
    657                 result.AddRange(StructToBuffer(kernelTime)); 
    658                 result.AddRange(StructToBuffer(userTime)); 
    659             } 
    660  
    661             //Current system time 
    662             result.AddRange(StructToBuffer(DateTime.Now.Ticks)); 
    663  
    664             //The high resolution performance counter 
    665             long perfCount = 0; 
    666             if (KernelAPI.QueryPerformanceCounter(out perfCount)) 
    667                 result.AddRange(StructToBuffer(perfCount)); 
    668  
    669             //Ticks since start up 
    670             uint tickCount = KernelAPI.GetTickCount(); 
    671             if (tickCount != 0) 
    672                 result.AddRange(StructToBuffer(tickCount)); 
    673  
    674             //CryptGenRandom 
    675             byte[] cryptGenRandom = new byte[160]; 
    676             if (CryptAPI.CryptGenRandom(cryptGenRandom)) 
    677                 result.AddRange(cryptGenRandom); 
    678  
    679             return result.ToArray(); 
    680         } 
    681  
    682         /// <summary> 
    683         /// Retrieves entropy from sources which are relatively slower than those from 
    684         /// the FastAddEntropy function. 
    685         /// </summary> 
    686         private byte[] GetSlowEntropy() 
    687         { 
    688             List<byte> result = new List<byte>(); 
    689  
    690             //NetAPI statistics 
    691             unsafe 
    692             { 
    693                 IntPtr netAPIStats = IntPtr.Zero; 
    694                 if (NetAPI.NetStatisticsGet(null, NetAPI.SERVICE_WORKSTATION, 
    695                     0, 0, out netAPIStats) == 0) 
    696                 { 
    697                     try 
    698                     { 
    699                         //Get the size of the buffer 
    700                         uint size = 0; 
    701                         NetAPI.NetApiBufferSize(netAPIStats, out size); 
    702                         byte[] entropy = new byte[size]; 
    703  
    704                         //Copy the buffer 
    705                         Marshal.Copy(entropy, 0, netAPIStats, entropy.Length); 
    706  
    707                         //And add it to the pool 
    708                         result.AddRange(entropy); 
    709                     } 
    710                     finally 
    711                     { 
    712                         //Free the statistics buffer 
    713                         NetAPI.NetApiBufferFree(netAPIStats); 
    714                     } 
    715                 } 
    716             } 
    717  
    718 #if false 
    719             //Get disk I/O statistics for all the hard drives 
    720             for (int drive = 0; ; ++drive) 
    721             { 
    722                 //Try to open the drive. 
    723                 using (SafeFileHandle hDevice = File.CreateFile( 
    724                     string.Format("\\\\.\\PhysicalDrive%d", drive), 0, 
    725                     File.FILE_SHARE_READ | File.FILE_SHARE_WRITE, IntPtr.Zero, 
    726                     File.OPEN_EXISTING, 0, IntPtr.Zero)) 
    727                 { 
    728                     if (hDevice.IsInvalid) 
    729                         break; 
    730  
    731                     //This only works if the user has turned on the disk performance 
    732                     //counters with 'diskperf -y'. These counters are off by default 
    733                     if (File.DeviceIoControl(hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0, 
    734                         &diskPerformance, sizeof(DISK_PERFORMANCE), &uSize, NULL)) 
    735                     { 
    736                         addEntropy(&diskPerformance, uSize); 
    737                     } 
    738                 } 
    739             } 
    740 #endif 
    741  
    742             /* 
    743              Query performance data. Because the Win32 version of this API (through 
    744              registry) may be buggy, use the NT Native API instead. 
    745               
    746              Scan the first 64 possible information types (we don't bother 
    747              with increasing the buffer size as we do with the Win32 
    748              version of the performance data read, we may miss a few classes 
    749              but it's no big deal).  In addition the returned size value for 
    750              some classes is wrong (eg 23 and 24 return a size of 0) so we 
    751              miss a few more things, but again it's no big deal.  This scan 
    752              typically yields around 20 pieces of data, there's nothing in 
    753              the range 65...128 so chances are there won't be anything above 
    754              there either. 
    755             */ 
    756             uint dataWritten = 0; 
    757             byte[] infoBuffer = new byte[65536]; 
    758             uint totalEntropy = 0; 
    759             for (uint infoType = 0; infoType < 64; ++infoType) 
    760             { 
    761                 uint sysInfo = NTAPI.NtQuerySystemInformation(infoType, infoBuffer, 
    762                     (uint)infoBuffer.Length, out dataWritten); 
    763  
    764                 if (sysInfo == 0 /*ERROR_SUCCESS*/ && dataWritten > 0) 
    765                 { 
    766                     byte[] entropy = new byte[dataWritten]; 
    767                     Buffer.BlockCopy(infoBuffer, 0, entropy, 0, (int)dataWritten); 
    768                     result.AddRange(entropy); 
    769                     totalEntropy += dataWritten; 
    770                 } 
    771             } 
    772  
    773             result.AddRange(StructToBuffer(totalEntropy)); 
    774  
    775             //Finally, our good friend CryptGenRandom() 
    776             byte[] cryptGenRandom = new byte[1536]; 
    777             if (CryptAPI.CryptGenRandom(cryptGenRandom)) 
    778                 result.AddRange(cryptGenRandom); 
    779  
    780             return result.ToArray(); 
    781         } 
    782     } 
    783798} 
Note: See TracChangeset for help on using the changeset viewer.