Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/cecil.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjbevain <jbevain@gmail.com>2010-04-12 11:19:07 +0400
committerjbevain <jbevain@gmail.com>2010-04-12 11:19:07 +0400
commit714ac9e6de3606a1f71966ff1684d964d8ae1334 (patch)
tree1a4d285f4603c8733b1f439acdf66fbc4d40eea5 /Mono.Security.Cryptography
initial commit
Diffstat (limited to 'Mono.Security.Cryptography')
-rw-r--r--Mono.Security.Cryptography/CryptoConvert.cs243
-rw-r--r--Mono.Security.Cryptography/CryptoService.cs208
2 files changed, 451 insertions, 0 deletions
diff --git a/Mono.Security.Cryptography/CryptoConvert.cs b/Mono.Security.Cryptography/CryptoConvert.cs
new file mode 100644
index 0000000..26a4ba2
--- /dev/null
+++ b/Mono.Security.Cryptography/CryptoConvert.cs
@@ -0,0 +1,243 @@
+//
+// CryptoConvert.cs - Crypto Convertion Routines
+//
+// Author:
+// Sebastien Pouliot <sebastien@ximian.com>
+//
+// (C) 2003 Motus Technologies Inc. (http://www.motus.com)
+// Copyright (C) 2004-2006 Novell Inc. (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Security.Cryptography;
+
+#if !(SILVERLIGHT || READ_ONLY)
+
+namespace Mono.Security.Cryptography {
+
+ static class CryptoConvert {
+
+ static private int ToInt32LE (byte [] bytes, int offset)
+ {
+ return (bytes [offset+3] << 24) | (bytes [offset+2] << 16) | (bytes [offset+1] << 8) | bytes [offset];
+ }
+
+ static private uint ToUInt32LE (byte [] bytes, int offset)
+ {
+ return (uint)((bytes [offset+3] << 24) | (bytes [offset+2] << 16) | (bytes [offset+1] << 8) | bytes [offset]);
+ }
+
+ static private byte[] Trim (byte[] array)
+ {
+ for (int i=0; i < array.Length; i++) {
+ if (array [i] != 0x00) {
+ byte[] result = new byte [array.Length - i];
+ Buffer.BlockCopy (array, i, result, 0, result.Length);
+ return result;
+ }
+ }
+ return null;
+ }
+
+ static RSA FromCapiPrivateKeyBlob (byte[] blob, int offset)
+ {
+ RSAParameters rsap = new RSAParameters ();
+ try {
+ if ((blob [offset] != 0x07) || // PRIVATEKEYBLOB (0x07)
+ (blob [offset+1] != 0x02) || // Version (0x02)
+ (blob [offset+2] != 0x00) || // Reserved (word)
+ (blob [offset+3] != 0x00) ||
+ (ToUInt32LE (blob, offset+8) != 0x32415352)) // DWORD magic = RSA2
+ throw new CryptographicException ("Invalid blob header");
+
+ // ALGID (CALG_RSA_SIGN, CALG_RSA_KEYX, ...)
+ // int algId = ToInt32LE (blob, offset+4);
+
+ // DWORD bitlen
+ int bitLen = ToInt32LE (blob, offset+12);
+
+ // DWORD public exponent
+ byte[] exp = new byte [4];
+ Buffer.BlockCopy (blob, offset+16, exp, 0, 4);
+ Array.Reverse (exp);
+ rsap.Exponent = Trim (exp);
+
+ int pos = offset+20;
+ // BYTE modulus[rsapubkey.bitlen/8];
+ int byteLen = (bitLen >> 3);
+ rsap.Modulus = new byte [byteLen];
+ Buffer.BlockCopy (blob, pos, rsap.Modulus, 0, byteLen);
+ Array.Reverse (rsap.Modulus);
+ pos += byteLen;
+
+ // BYTE prime1[rsapubkey.bitlen/16];
+ int byteHalfLen = (byteLen >> 1);
+ rsap.P = new byte [byteHalfLen];
+ Buffer.BlockCopy (blob, pos, rsap.P, 0, byteHalfLen);
+ Array.Reverse (rsap.P);
+ pos += byteHalfLen;
+
+ // BYTE prime2[rsapubkey.bitlen/16];
+ rsap.Q = new byte [byteHalfLen];
+ Buffer.BlockCopy (blob, pos, rsap.Q, 0, byteHalfLen);
+ Array.Reverse (rsap.Q);
+ pos += byteHalfLen;
+
+ // BYTE exponent1[rsapubkey.bitlen/16];
+ rsap.DP = new byte [byteHalfLen];
+ Buffer.BlockCopy (blob, pos, rsap.DP, 0, byteHalfLen);
+ Array.Reverse (rsap.DP);
+ pos += byteHalfLen;
+
+ // BYTE exponent2[rsapubkey.bitlen/16];
+ rsap.DQ = new byte [byteHalfLen];
+ Buffer.BlockCopy (blob, pos, rsap.DQ, 0, byteHalfLen);
+ Array.Reverse (rsap.DQ);
+ pos += byteHalfLen;
+
+ // BYTE coefficient[rsapubkey.bitlen/16];
+ rsap.InverseQ = new byte [byteHalfLen];
+ Buffer.BlockCopy (blob, pos, rsap.InverseQ, 0, byteHalfLen);
+ Array.Reverse (rsap.InverseQ);
+ pos += byteHalfLen;
+
+ // ok, this is hackish but CryptoAPI support it so...
+ // note: only works because CRT is used by default
+ // http://bugzilla.ximian.com/show_bug.cgi?id=57941
+ rsap.D = new byte [byteLen]; // must be allocated
+ if (pos + byteLen + offset <= blob.Length) {
+ // BYTE privateExponent[rsapubkey.bitlen/8];
+ Buffer.BlockCopy (blob, pos, rsap.D, 0, byteLen);
+ Array.Reverse (rsap.D);
+ }
+ }
+ catch (Exception e) {
+ throw new CryptographicException ("Invalid blob.", e);
+ }
+
+ RSA rsa = null;
+ try {
+ rsa = RSA.Create ();
+ rsa.ImportParameters (rsap);
+ }
+ catch (CryptographicException ce) {
+ // this may cause problem when this code is run under
+ // the SYSTEM identity on Windows (e.g. ASP.NET). See
+ // http://bugzilla.ximian.com/show_bug.cgi?id=77559
+ try {
+ CspParameters csp = new CspParameters ();
+ csp.Flags = CspProviderFlags.UseMachineKeyStore;
+ rsa = new RSACryptoServiceProvider (csp);
+ rsa.ImportParameters (rsap);
+ }
+ catch {
+ // rethrow original, not the later, exception if this fails
+ throw ce;
+ }
+ }
+ return rsa;
+ }
+
+ static RSA FromCapiPublicKeyBlob (byte[] blob, int offset)
+ {
+ try {
+ if ((blob [offset] != 0x06) || // PUBLICKEYBLOB (0x06)
+ (blob [offset+1] != 0x02) || // Version (0x02)
+ (blob [offset+2] != 0x00) || // Reserved (word)
+ (blob [offset+3] != 0x00) ||
+ (ToUInt32LE (blob, offset+8) != 0x31415352)) // DWORD magic = RSA1
+ throw new CryptographicException ("Invalid blob header");
+
+ // ALGID (CALG_RSA_SIGN, CALG_RSA_KEYX, ...)
+ // int algId = ToInt32LE (blob, offset+4);
+
+ // DWORD bitlen
+ int bitLen = ToInt32LE (blob, offset+12);
+
+ // DWORD public exponent
+ RSAParameters rsap = new RSAParameters ();
+ rsap.Exponent = new byte [3];
+ rsap.Exponent [0] = blob [offset+18];
+ rsap.Exponent [1] = blob [offset+17];
+ rsap.Exponent [2] = blob [offset+16];
+
+ int pos = offset+20;
+ // BYTE modulus[rsapubkey.bitlen/8];
+ int byteLen = (bitLen >> 3);
+ rsap.Modulus = new byte [byteLen];
+ Buffer.BlockCopy (blob, pos, rsap.Modulus, 0, byteLen);
+ Array.Reverse (rsap.Modulus);
+
+ RSA rsa = null;
+ try {
+ rsa = RSA.Create ();
+ rsa.ImportParameters (rsap);
+ }
+ catch (CryptographicException) {
+ // this may cause problem when this code is run under
+ // the SYSTEM identity on Windows (e.g. ASP.NET). See
+ // http://bugzilla.ximian.com/show_bug.cgi?id=77559
+ CspParameters csp = new CspParameters ();
+ csp.Flags = CspProviderFlags.UseMachineKeyStore;
+ rsa = new RSACryptoServiceProvider (csp);
+ rsa.ImportParameters (rsap);
+ }
+ return rsa;
+ }
+ catch (Exception e) {
+ throw new CryptographicException ("Invalid blob.", e);
+ }
+ }
+
+ // PRIVATEKEYBLOB
+ // PUBLICKEYBLOB
+ static public RSA FromCapiKeyBlob (byte[] blob)
+ {
+ return FromCapiKeyBlob (blob, 0);
+ }
+
+ static public RSA FromCapiKeyBlob (byte[] blob, int offset)
+ {
+ if (blob == null)
+ throw new ArgumentNullException ("blob");
+ if (offset >= blob.Length)
+ throw new ArgumentException ("blob is too small.");
+
+ switch (blob [offset]) {
+ case 0x00:
+ // this could be a public key inside an header
+ // like "sn -e" would produce
+ if (blob [offset + 12] == 0x06) {
+ return FromCapiPublicKeyBlob (blob, offset + 12);
+ }
+ break;
+ case 0x06:
+ return FromCapiPublicKeyBlob (blob, offset);
+ case 0x07:
+ return FromCapiPrivateKeyBlob (blob, offset);
+ }
+ throw new CryptographicException ("Unknown blob format.");
+ }
+ }
+}
+
+#endif
diff --git a/Mono.Security.Cryptography/CryptoService.cs b/Mono.Security.Cryptography/CryptoService.cs
new file mode 100644
index 0000000..12d0d94
--- /dev/null
+++ b/Mono.Security.Cryptography/CryptoService.cs
@@ -0,0 +1,208 @@
+//
+// CryptoService.cs
+//
+// Author:
+// Jb Evain (jbevain@gmail.com)
+//
+// Copyright (c) 2008 - 2010 Jb Evain
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.IO;
+using System.Reflection;
+using System.Runtime.Serialization;
+using System.Security.Cryptography;
+
+#if !READ_ONLY
+
+#if !SILVERLIGHT
+using Mono.Security.Cryptography;
+#endif
+
+using Mono.Cecil.PE;
+
+namespace Mono.Cecil {
+
+ // Most of this code has been adapted
+ // from Jeroen Frijters' fantastic work
+ // in IKVM.Reflection.Emit. Thanks!
+
+ static class CryptoService {
+
+#if !SILVERLIGHT
+ public static void StrongName (Stream stream, ImageWriter writer, StrongNameKeyPair key_pair)
+ {
+ int strong_name_pointer;
+
+ var strong_name = CreateStrongName (key_pair, HashStream (stream, writer, out strong_name_pointer));
+ PatchStrongName (stream, strong_name_pointer, strong_name);
+
+ PatchChecksum (stream, ComputeChecksum (stream));
+ }
+
+ static void PatchStrongName (Stream stream, int strong_name_pointer, byte [] strong_name)
+ {
+ stream.Seek (strong_name_pointer, SeekOrigin.Begin);
+ stream.Write (strong_name, 0, strong_name.Length);
+ }
+
+ static byte [] CreateStrongName (StrongNameKeyPair key_pair, byte [] hash)
+ {
+ const string hash_algo = "SHA1";
+
+ using (var rsa = key_pair.CreateRSA ()) {
+ var formatter = new RSAPKCS1SignatureFormatter (rsa);
+ formatter.SetHashAlgorithm (hash_algo);
+
+ byte [] signature = formatter.CreateSignature (hash);
+ Array.Reverse (signature);
+
+ return signature;
+ }
+ }
+
+ static byte [] HashStream (Stream stream, ImageWriter writer, out int strong_name_pointer)
+ {
+ const int buffer_size = 8192;
+
+ var text = writer.text;
+ var header_size = (int) writer.GetHeaderSize ();
+ var text_section_pointer = (int) text.PointerToRawData;
+ var strong_name_directory = writer.GetStrongNameSignatureDirectory ();
+
+ if (strong_name_directory.Size == 0)
+ throw new InvalidOperationException ();
+
+ strong_name_pointer = (int) (text_section_pointer
+ + (strong_name_directory.VirtualAddress - text.VirtualAddress));
+ var strong_name_length = (int) strong_name_directory.Size;
+
+ var sha1 = new SHA1Managed ();
+ var buffer = new byte [buffer_size];
+ using (var crypto_stream = new CryptoStream (Stream.Null, sha1, CryptoStreamMode.Write)) {
+
+ stream.Seek (0, SeekOrigin.Begin);
+ CopyStreamChunk (stream, crypto_stream, buffer, header_size);
+
+ stream.Seek (text_section_pointer, SeekOrigin.Begin);
+ CopyStreamChunk (stream, crypto_stream, buffer, (int) strong_name_pointer - text_section_pointer);
+
+ stream.Seek (strong_name_length, SeekOrigin.Current);
+ CopyStreamChunk (stream, crypto_stream, buffer, (int) (stream.Length - (strong_name_pointer + strong_name_length)));
+ }
+
+ return sha1.Hash;
+ }
+
+ static void PatchChecksum (Stream stream, int checksum)
+ {
+ stream.Seek (0xd8, SeekOrigin.Begin);
+ var buffer = new ByteBuffer (4);
+ buffer.WriteInt32 (checksum);
+
+ stream.Write (buffer.buffer, 0, 4);
+ }
+
+ static int ComputeChecksum (Stream stream)
+ {
+ stream.Seek (0, SeekOrigin.Begin);
+ int count = (int) stream.Length / 4;
+
+ var reader = new BinaryReader (stream);
+ long sum = 0;
+ for (int i = 0; i < count; i++) {
+ sum += reader.ReadUInt32 ();
+ int carry = (int) (sum >> 32);
+ sum &= 0xFFFFFFFFU;
+ sum += carry;
+ }
+
+ while ((sum >> 16) != 0)
+ sum = (sum & 0xFFFF) + (sum >> 16);
+
+ return (int) (sum + stream.Length);
+ }
+#endif
+ static void CopyStreamChunk (Stream stream, Stream dest_stream, byte [] buffer, int length)
+ {
+ while (length > 0) {
+ int read = stream.Read (buffer, 0, System.Math.Min (buffer.Length, length));
+ dest_stream.Write (buffer, 0, read);
+ length -= read;
+ }
+ }
+
+ public static byte [] ComputeHash (string file)
+ {
+ if (!File.Exists (file))
+ return Empty<byte>.Array;
+
+ const int buffer_size = 8192;
+
+ var sha1 = new SHA1Managed ();
+
+ using (var stream = new FileStream (file, FileMode.Open, FileAccess.Read, FileShare.Read)) {
+
+ var buffer = new byte [buffer_size];
+
+ using (var crypto_stream = new CryptoStream (Stream.Null, sha1, CryptoStreamMode.Write))
+ CopyStreamChunk (stream, crypto_stream, buffer, (int) stream.Length);
+ }
+
+ return sha1.Hash;
+ }
+ }
+
+#if !SILVERLIGHT
+ static partial class Mixin {
+
+ public static RSA CreateRSA (this StrongNameKeyPair key_pair)
+ {
+ byte [] key;
+ string key_container;
+
+ if (!TryGetKeyContainer (key_pair, out key, out key_container))
+ return CryptoConvert.FromCapiKeyBlob (key);
+
+ var parameters = new CspParameters {
+ Flags = CspProviderFlags.UseMachineKeyStore,
+ KeyContainerName = key_container,
+ KeyNumber = 2,
+ };
+
+ return new RSACryptoServiceProvider (parameters);
+ }
+
+ static bool TryGetKeyContainer (ISerializable key_pair, out byte [] key, out string key_container)
+ {
+ var info = new SerializationInfo (typeof (StrongNameKeyPair), new FormatterConverter ());
+ key_pair.GetObjectData (info, new StreamingContext ());
+
+ key = (byte []) info.GetValue ("_keyPairArray", typeof (byte []));
+ key_container = info.GetString ("_keyPairContainer");
+ return key_container != null;
+ }
+ }
+#endif
+}
+
+#endif