26using System.Security.Cryptography;
31 internal sealed class StrongNameKeyPair
34 readonly
byte[] keyPairArray;
35 readonly
string keyPairContainer;
43 public StrongNameKeyPair(
string keyPairContainer)
45 if (keyPairContainer ==
null)
46 throw new ArgumentNullException(
"keyPairContainer");
48 if (Universe.MonoRuntime && Environment.OSVersion.Platform == PlatformID.Win32NT)
49 throw new NotSupportedException(
"IKVM.Reflection does not support key containers when running on Mono");
51 this.keyPairContainer = keyPairContainer;
59 public StrongNameKeyPair(
byte[] keyPairArray)
61 if (keyPairArray ==
null)
62 throw new ArgumentNullException(
"keyPairArray");
64 this.keyPairArray = (
byte[])keyPairArray.Clone();
71 public StrongNameKeyPair(FileStream keyPairFile) :
72 this(ReadAllBytes(keyPairFile))
77 static byte[] ReadAllBytes(FileStream keyPairFile)
79 if (keyPairFile ==
null)
80 throw new ArgumentNullException(
"keyPairFile");
82 var buf =
new byte[keyPairFile.Length - keyPairFile.Position];
83 keyPairFile.Read(buf, 0, buf.Length);
87 public byte[] PublicKey
92 if (Universe.MonoRuntime)
93 return MonoGetPublicKey();
95 using var rsa = CreateRSA();
96 var rsaParameters = rsa.ExportParameters(
false);
97 var cspBlob = ExportPublicKey(rsaParameters);
98 var publicKey =
new byte[12 + cspBlob.Length];
99 Buffer.BlockCopy(cspBlob, 0, publicKey, 12, cspBlob.Length);
103 publicKey[8] = (byte)(cspBlob.Length >> 0);
104 publicKey[9] = (byte)(cspBlob.Length >> 8);
105 publicKey[10] = (byte)(cspBlob.Length >> 16);
106 publicKey[11] = (byte)(cspBlob.Length >> 24);
111 internal RSA CreateRSA()
115 if (keyPairArray !=
null)
117 var rsa = RSA.Create();
120 rsa.ImportParameters(RSAParametersFromByteArray(keyPairArray));
126 var parm =
new CspParameters();
127 parm.KeyContainerName = keyPairContainer;
130 if (Universe.MonoRuntime ==
false)
132 parm.Flags = CspProviderFlags.UseMachineKeyStore | CspProviderFlags.UseExistingKey;
136 return new RSACryptoServiceProvider(parm);
138 throw new PlatformNotSupportedException(
"Strong name key container support is only available when targeting .NET Framework.");
144 throw new ArgumentException(
"Unable to obtain public key for StrongNameKeyPair.");
151 static byte[] ExportPublicKey(RSAParameters rsaParameters)
153 if (rsaParameters.Modulus ==
null || rsaParameters.Exponent ==
null)
154 throw new ArgumentNullException(nameof(rsaParameters));
156 using var ms =
new MemoryStream();
157 using var bw =
new BinaryWriter(ms);
158 var keyBitLength = rsaParameters.Modulus.Length * 8;
159 bw.Write((
byte)0x06);
160 bw.Write((
byte)0x02);
161 bw.Write((ushort)0x0000);
162 bw.Write((uint)0x2400);
163 bw.Write(
"RSA1".ToCharArray());
164 bw.Write((uint)keyBitLength);
165 bw.Write(rsaParameters.Exponent);
166 bw.Write((
byte)0x00);
167 var modulus = (
byte[])rsaParameters.Modulus.Clone();
168 Array.Reverse(modulus);
174 static RSAParameters RSAParametersFromByteArray(
byte[] array)
176 using var ms =
new MemoryStream(array);
177 return RSAParametersFromStream(ms);
180 static RSAParameters RSAParametersFromStream(Stream str)
182 var rsaParameters =
new RSAParameters();
183 using var br =
new BinaryReader(str);
186 var keyType = br.ReadByte();
187 if (keyType != 6 && keyType != 7)
188 throw new CryptographicException(
"SNK file not in correct format");
190 var blobVersion = br.ReadByte();
191 var reserverd = br.ReadUInt16();
192 var algorithmID = br.ReadUInt32();
195 var magic =
new string(br.ReadChars(4));
196 if (!magic.Equals(
"RSA1") && !magic.Equals(
"RSA2"))
197 throw new CryptographicException(
"SNK file not in correct format");
199 var keyBitLength = br.ReadUInt32();
200 var publicExponent = br.ReadBytes(3);
202 rsaParameters.Exponent = publicExponent;
205 var modulus = br.ReadBytes((
int)keyBitLength / 8);
206 Array.Reverse(modulus);
207 rsaParameters.Modulus = modulus;
212 var prime1 = br.ReadBytes((
int)keyBitLength / 16);
213 var prime2 = br.ReadBytes((
int)keyBitLength / 16);
214 var exponent1 = br.ReadBytes((
int)keyBitLength / 16);
215 var exponent2 = br.ReadBytes((
int)keyBitLength / 16);
216 var coefficient = br.ReadBytes((
int)keyBitLength / 16);
217 var privateExponent = br.ReadBytes((
int)keyBitLength / 8);
219 Array.Reverse(prime1);
220 Array.Reverse(prime2);
221 Array.Reverse(exponent1);
222 Array.Reverse(exponent2);
223 Array.Reverse(coefficient);
224 Array.Reverse(privateExponent);
225 rsaParameters.P = prime1;
226 rsaParameters.Q = prime2;
227 rsaParameters.DP = exponent1;
228 rsaParameters.DQ = exponent2;
229 rsaParameters.InverseQ = coefficient;
230 rsaParameters.D = privateExponent;
233 return rsaParameters;
237 byte[] MonoGetPublicKey()
239 return keyPairArray !=
null ?
new System.Reflection.StrongNameKeyPair(keyPairArray).PublicKey :
new System.Reflection.StrongNameKeyPair(keyPairContainer).PublicKey;