From e541e2bf5e6ea0004576c645849a8aa967ba6458 Mon Sep 17 00:00:00 2001 From: simoncropp Date: Mon, 18 Mar 2019 23:36:15 +1100 Subject: [PATCH] add custom StrongNameKeyPair --- Mono.Cecil/ModuleDefinition.cs | 9 +- Mono.Cecil/StrongNameKeyPair.cs | 132 ++++++++++++++++++++ Mono.Security.Cryptography/CryptoService.cs | 23 +++- 3 files changed, 161 insertions(+), 3 deletions(-) create mode 100644 Mono.Cecil/StrongNameKeyPair.cs diff --git a/Mono.Cecil/ModuleDefinition.cs b/Mono.Cecil/ModuleDefinition.cs index 707a1358f..7db2a2ddd 100644 --- a/Mono.Cecil/ModuleDefinition.cs +++ b/Mono.Cecil/ModuleDefinition.cs @@ -13,6 +13,11 @@ using System.IO; using System.Threading; using SR = System.Reflection; +#if (NETSTANDARD) +using StrongNameKeyPair=Mono.Cecil.StrongNameKeyPair; +#else +using StrongNameKeyPair=System.Reflection.StrongNameKeyPair; +#endif using Mono.Cecil.Cil; using Mono.Cecil.Metadata; @@ -185,7 +190,7 @@ public sealed class WriterParameters { bool write_symbols; byte [] key_blob; string key_container; - SR.StrongNameKeyPair key_pair; + StrongNameKeyPair key_pair; public uint? Timestamp { get { return timestamp; } @@ -221,7 +226,7 @@ public string StrongNameKeyContainer { set { key_container = value; } } - public SR.StrongNameKeyPair StrongNameKeyPair { + public StrongNameKeyPair StrongNameKeyPair { get { return key_pair; } set { key_pair = value; } } diff --git a/Mono.Cecil/StrongNameKeyPair.cs b/Mono.Cecil/StrongNameKeyPair.cs new file mode 100644 index 000000000..9c3f94c9f --- /dev/null +++ b/Mono.Cecil/StrongNameKeyPair.cs @@ -0,0 +1,132 @@ +#if (NETSTANDARD) +using System; +using System.IO; +using System.Runtime.Serialization; +using System.Security; +using System.Security.Cryptography; + +namespace Mono.Cecil { + [Serializable] + public class StrongNameKeyPair : ISerializable { + bool _keyPairExported; + byte [] _keyPairArray; + string _keyPairContainer; + byte [] _publicKey; + + public byte [] PublicKey { + [SecuritySafeCritical] + get { + if (_publicKey == null) { + _publicKey = ComputePublicKey (); + } + + byte [] array = new byte[_publicKey.Length]; + Array.Copy (_publicKey, array, _publicKey.Length); + return array; + } + } + + public StrongNameKeyPair (FileStream keyPairFile) + { + if (keyPairFile == null) { + throw new ArgumentNullException ("keyPairFile"); + } + + var num = (int) keyPairFile.Length; + _keyPairArray = new byte[num]; + keyPairFile.Read (_keyPairArray, 0, num); + _keyPairExported = true; + } + + public StrongNameKeyPair (byte [] keyPairArray) + { + if (keyPairArray == null) { + throw new ArgumentNullException ("keyPairArray"); + } + + _keyPairArray = new byte[keyPairArray.Length]; + Array.Copy (keyPairArray, _keyPairArray, keyPairArray.Length); + _keyPairExported = true; + } + + public StrongNameKeyPair (string keyPairContainer) + { + if (keyPairContainer == null) { + throw new ArgumentNullException ("keyPairContainer"); + } + + _keyPairContainer = keyPairContainer; + _keyPairExported = false; + } + + protected StrongNameKeyPair (SerializationInfo info, StreamingContext context) + { + _keyPairExported = (bool) info.GetValue ("_keyPairExported", typeof(bool)); + _keyPairArray = (byte []) info.GetValue ("_keyPairArray", typeof(byte [])); + _keyPairContainer = (string) info.GetValue ("_keyPairContainer", typeof(string)); + _publicKey = (byte []) info.GetValue ("_publicKey", typeof(byte [])); + } + + byte [] ComputePublicKey () + { + using (var rsa = Mixin.CreateRSA (this)) { + var cspBlob = ToCapiPublicKeyBlob (rsa); + var publicKey = new byte[12 + cspBlob.Length]; + Buffer.BlockCopy (cspBlob, 0, publicKey, 12, cspBlob.Length); + // The first 12 bytes are documented at: + // http://msdn.microsoft.com/library/en-us/cprefadd/html/grfungethashfromfile.asp + // ALG_ID - Signature + publicKey [1] = 36; + // ALG_ID - Hash + publicKey [4] = 4; + publicKey [5] = 128; + // Length of Public Key (in bytes) + publicKey [8] = (byte) (cspBlob.Length >> 0); + publicKey [9] = (byte) (cspBlob.Length >> 8); + publicKey [10] = (byte) (cspBlob.Length >> 16); + publicKey [11] = (byte) (cspBlob.Length >> 24); + return publicKey; + } + } + + void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context) + { + info.AddValue ("_keyPairExported", _keyPairExported); + info.AddValue ("_keyPairArray", _keyPairArray); + info.AddValue ("_keyPairContainer", _keyPairContainer); + info.AddValue ("_publicKey", _publicKey); + } + + static byte [] ToCapiPublicKeyBlob (RSA rsa) + { + var rsap = rsa.ExportParameters (false); + var blob = new byte[rsap.Modulus.Length + 20]; + blob [0] = 0x06; // PUBLICKEYBLOB (0x06) + blob [1] = 0x02; // Version (0x02) + blob [2] = 0x00; // Reserved (word) + blob [3] = 0x00; + blob [5] = 0x24; // ALGID + WriteUInt32LE (blob, 8, 0x31415352); // DWORD magic = RSA1 + WriteUInt32LE (blob, 12, (uint) rsap.Modulus.Length << 3); // DWORD bitlen + + // DWORD public exponent + blob [18] = rsap.Exponent [0]; + blob [17] = rsap.Exponent [1]; + blob [16] = rsap.Exponent [2]; + + // BYTE modulus[rsapubkey.bitlen/8]; + Array.Reverse (rsap.Modulus); + Buffer.BlockCopy (rsap.Modulus, 0, blob, 20, rsap.Modulus.Length); + return blob; + } + + static void WriteUInt32LE (byte [] bytes, int offset, uint value) + { + bytes [offset + 3] = (byte) (value >> 24); + bytes [offset + 2] = (byte) (value >> 16); + bytes [offset + 1] = (byte) (value >> 8); + bytes [offset] = (byte) value; + } + } +} +#endif \ No newline at end of file diff --git a/Mono.Security.Cryptography/CryptoService.cs b/Mono.Security.Cryptography/CryptoService.cs index 013e0019d..dd0277f30 100644 --- a/Mono.Security.Cryptography/CryptoService.cs +++ b/Mono.Security.Cryptography/CryptoService.cs @@ -10,7 +10,11 @@ using System; using System.IO; -using System.Reflection; +#if (NETSTANDARD) +using StrongNameKeyPair=Mono.Cecil.StrongNameKeyPair; +#else +using StrongNameKeyPair=System.Reflection.StrongNameKeyPair; +#endif using System.Security.Cryptography; using System.Runtime.Serialization; @@ -191,6 +195,23 @@ public static RSA CreateRSA (this WriterParameters writer_parameters) return new RSACryptoServiceProvider (parameters); } + 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 ());