Changeset 502 for branches/eraser6/Manager/PRNG.cs
- Timestamp:
- 11/11/2008 12:04:36 AM (5 years ago)
- File:
-
- 1 edited
-
branches/eraser6/Manager/PRNG.cs (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branches/eraser6/Manager/PRNG.cs
r479 r502 221 221 222 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> 223 508 /// A class which uses EntropyPoll class to fetch system data as a source of 224 509 /// randomness at "regular" but "random" intervals 225 510 /// </summary> 226 class EntropyPoller511 public class EntropyPoller : KernelEntropySource 227 512 { 228 513 /// <summary> … … 278 563 } 279 564 280 st.Stop(); 565 st.Stop(); 566 // 2049 = bin '100000000001', great avalanche 281 567 Thread.Sleep(2000 + (int)(st.ElapsedTicks % 2049L)); 282 568 st.Reset(); 283 569 284 // Send entropy to the PRNGs for new seeds.570 // Send entropy to the PRNGs for new seeds. 285 571 if (DateTime.Now - lastAddedEntropy > managerEntropySpan) 286 572 ManagerLibrary.Instance.PRNGManager.AddEntropy(GetPool()); … … 510 796 private List<EntropySource> EntropySources = new List<EntropySource>(); 511 797 } 512 513 /// <summary>514 /// Provides an abstract interface to allow multiple sources of entropy into515 /// the EntropyPoller class.516 /// </summary>517 public abstract class EntropySource518 {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, to528 /// 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 allow541 /// inherited classes to convert value types into byte arrays which can be542 /// 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: struct547 {548 int sizeofObject = Marshal.SizeOf(entropy);549 IntPtr memory = Marshal.AllocHGlobal(sizeofObject);550 try551 {552 Marshal.StructureToPtr(entropy, memory, false);553 byte[] dest = new byte[sizeofObject];554 555 //Copy the memory556 Marshal.Copy(memory, dest, 0, sizeofObject);557 return dest;558 }559 finally560 {561 Marshal.FreeHGlobal(memory);562 }563 }564 }565 566 /// <summary>567 /// Provides means of generating random entropy from the system or user space568 /// randomness.569 /// </summary>570 internal class KernelEntropySource : EntropySource571 {572 public override byte[] GetPrimer()573 {574 List<byte> result = new List<byte>();575 576 //Process startup information577 KernelAPI.STARTUPINFO startupInfo = new KernelAPI.STARTUPINFO();578 KernelAPI.GetStartupInfo(out startupInfo);579 result.AddRange(StructToBuffer(startupInfo));580 581 //System information582 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 pool608 result.AddRange(StructToBuffer(new DriveInfo(new DirectoryInfo(Environment.SystemDirectory).609 Root.FullName).TotalFreeSpace));610 611 //Miscellaneous window handles612 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 positions626 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 memory633 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 times643 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 times653 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 time662 result.AddRange(StructToBuffer(DateTime.Now.Ticks));663 664 //The high resolution performance counter665 long perfCount = 0;666 if (KernelAPI.QueryPerformanceCounter(out perfCount))667 result.AddRange(StructToBuffer(perfCount));668 669 //Ticks since start up670 uint tickCount = KernelAPI.GetTickCount();671 if (tickCount != 0)672 result.AddRange(StructToBuffer(tickCount));673 674 //CryptGenRandom675 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 from684 /// the FastAddEntropy function.685 /// </summary>686 private byte[] GetSlowEntropy()687 {688 List<byte> result = new List<byte>();689 690 //NetAPI statistics691 unsafe692 {693 IntPtr netAPIStats = IntPtr.Zero;694 if (NetAPI.NetStatisticsGet(null, NetAPI.SERVICE_WORKSTATION,695 0, 0, out netAPIStats) == 0)696 {697 try698 {699 //Get the size of the buffer700 uint size = 0;701 NetAPI.NetApiBufferSize(netAPIStats, out size);702 byte[] entropy = new byte[size];703 704 //Copy the buffer705 Marshal.Copy(entropy, 0, netAPIStats, entropy.Length);706 707 //And add it to the pool708 result.AddRange(entropy);709 }710 finally711 {712 //Free the statistics buffer713 NetAPI.NetApiBufferFree(netAPIStats);714 }715 }716 }717 718 #if false719 //Get disk I/O statistics for all the hard drives720 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 performance732 //counters with 'diskperf -y'. These counters are off by default733 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 #endif741 742 /*743 Query performance data. Because the Win32 version of this API (through744 registry) may be buggy, use the NT Native API instead.745 746 Scan the first 64 possible information types (we don't bother747 with increasing the buffer size as we do with the Win32748 version of the performance data read, we may miss a few classes749 but it's no big deal). In addition the returned size value for750 some classes is wrong (eg 23 and 24 return a size of 0) so we751 miss a few more things, but again it's no big deal. This scan752 typically yields around 20 pieces of data, there's nothing in753 the range 65...128 so chances are there won't be anything above754 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 }783 798 }
Note: See TracChangeset
for help on using the changeset viewer.
