CryptoService.cs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. //
  2. // Author:
  3. // Jb Evain (jbevain@gmail.com)
  4. //
  5. // Copyright (c) 2008 - 2015 Jb Evain
  6. // Copyright (c) 2008 - 2011 Novell, Inc.
  7. //
  8. // Licensed under the MIT/X11 license.
  9. //
  10. #if !READ_ONLY
  11. #if !NET_CORE
  12. using System;
  13. using System.IO;
  14. using System.Reflection;
  15. using System.Security.Cryptography;
  16. using System.Runtime.Serialization;
  17. using Mono.Security.Cryptography;
  18. using Mono.Cecil.PE;
  19. namespace Mono.Cecil {
  20. // Most of this code has been adapted
  21. // from Jeroen Frijters' fantastic work
  22. // in IKVM.Reflection.Emit. Thanks!
  23. static class CryptoService {
  24. public static void StrongName (Stream stream, ImageWriter writer, StrongNameKeyPair key_pair)
  25. {
  26. int strong_name_pointer;
  27. var strong_name = CreateStrongName (key_pair, HashStream (stream, writer, out strong_name_pointer));
  28. PatchStrongName (stream, strong_name_pointer, strong_name);
  29. }
  30. static void PatchStrongName (Stream stream, int strong_name_pointer, byte [] strong_name)
  31. {
  32. stream.Seek (strong_name_pointer, SeekOrigin.Begin);
  33. stream.Write (strong_name, 0, strong_name.Length);
  34. }
  35. static byte [] CreateStrongName (StrongNameKeyPair key_pair, byte [] hash)
  36. {
  37. const string hash_algo = "SHA1";
  38. using (var rsa = key_pair.CreateRSA ()) {
  39. var formatter = new RSAPKCS1SignatureFormatter (rsa);
  40. formatter.SetHashAlgorithm (hash_algo);
  41. byte [] signature = formatter.CreateSignature (hash);
  42. Array.Reverse (signature);
  43. return signature;
  44. }
  45. }
  46. static byte [] HashStream (Stream stream, ImageWriter writer, out int strong_name_pointer)
  47. {
  48. const int buffer_size = 8192;
  49. var text = writer.text;
  50. var header_size = (int) writer.GetHeaderSize ();
  51. var text_section_pointer = (int) text.PointerToRawData;
  52. var strong_name_directory = writer.GetStrongNameSignatureDirectory ();
  53. if (strong_name_directory.Size == 0)
  54. throw new InvalidOperationException ();
  55. strong_name_pointer = (int) (text_section_pointer
  56. + (strong_name_directory.VirtualAddress - text.VirtualAddress));
  57. var strong_name_length = (int) strong_name_directory.Size;
  58. var sha1 = new SHA1Managed ();
  59. var buffer = new byte [buffer_size];
  60. using (var crypto_stream = new CryptoStream (Stream.Null, sha1, CryptoStreamMode.Write)) {
  61. stream.Seek (0, SeekOrigin.Begin);
  62. CopyStreamChunk (stream, crypto_stream, buffer, header_size);
  63. stream.Seek (text_section_pointer, SeekOrigin.Begin);
  64. CopyStreamChunk (stream, crypto_stream, buffer, (int) strong_name_pointer - text_section_pointer);
  65. stream.Seek (strong_name_length, SeekOrigin.Current);
  66. CopyStreamChunk (stream, crypto_stream, buffer, (int) (stream.Length - (strong_name_pointer + strong_name_length)));
  67. }
  68. return sha1.Hash;
  69. }
  70. static void CopyStreamChunk (Stream stream, Stream dest_stream, byte [] buffer, int length)
  71. {
  72. while (length > 0) {
  73. int read = stream.Read (buffer, 0, System.Math.Min (buffer.Length, length));
  74. dest_stream.Write (buffer, 0, read);
  75. length -= read;
  76. }
  77. }
  78. public static byte [] ComputeHash (string file)
  79. {
  80. if (!File.Exists (file))
  81. return Empty<byte>.Array;
  82. const int buffer_size = 8192;
  83. var sha1 = new SHA1Managed ();
  84. using (var stream = new FileStream (file, FileMode.Open, FileAccess.Read, FileShare.Read)) {
  85. var buffer = new byte [buffer_size];
  86. using (var crypto_stream = new CryptoStream (Stream.Null, sha1, CryptoStreamMode.Write))
  87. CopyStreamChunk (stream, crypto_stream, buffer, (int) stream.Length);
  88. }
  89. return sha1.Hash;
  90. }
  91. }
  92. static partial class Mixin {
  93. public static RSA CreateRSA (this StrongNameKeyPair key_pair)
  94. {
  95. byte [] key;
  96. string key_container;
  97. if (!TryGetKeyContainer (key_pair, out key, out key_container))
  98. return CryptoConvert.FromCapiKeyBlob (key);
  99. var parameters = new CspParameters {
  100. Flags = CspProviderFlags.UseMachineKeyStore,
  101. KeyContainerName = key_container,
  102. KeyNumber = 2,
  103. };
  104. return new RSACryptoServiceProvider (parameters);
  105. }
  106. static bool TryGetKeyContainer (ISerializable key_pair, out byte [] key, out string key_container)
  107. {
  108. var info = new SerializationInfo (typeof (StrongNameKeyPair), new FormatterConverter ());
  109. key_pair.GetObjectData (info, new StreamingContext ());
  110. key = (byte []) info.GetValue ("_keyPairArray", typeof (byte []));
  111. key_container = info.GetString ("_keyPairContainer");
  112. return key_container != null;
  113. }
  114. }
  115. }
  116. #endif
  117. #endif