IKVM11  11
Java SE 11 Virtual Machine for .NET
Loading...
Searching...
No Matches
StrongNameKeyPair.cs
Go to the documentation of this file.
1/*
2 Copyright (C) 2009-2012 Jeroen Frijters
3
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
7
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely, subject to the following restrictions:
11
12 1. The origin of this software must not be misrepresented; you must not
13 claim that you wrote the original software. If you use this software
14 in a product, an acknowledgment in the product documentation would be
15 appreciated but is not required.
16 2. Altered source versions must be plainly marked as such, and must not be
17 misrepresented as being the original software.
18 3. This notice may not be removed or altered from any source distribution.
19
20 Jeroen Frijters
21 jeroen@frijters.net
22
23*/
24using System;
25using System.IO;
26using System.Security.Cryptography;
27
28namespace IKVM.Reflection
29{
30
31 internal sealed class StrongNameKeyPair
32 {
33
34 readonly byte[] keyPairArray;
35 readonly string keyPairContainer;
36
43 public StrongNameKeyPair(string keyPairContainer)
44 {
45 if (keyPairContainer == null)
46 throw new ArgumentNullException("keyPairContainer");
47
48 if (Universe.MonoRuntime && Environment.OSVersion.Platform == PlatformID.Win32NT)
49 throw new NotSupportedException("IKVM.Reflection does not support key containers when running on Mono");
50
51 this.keyPairContainer = keyPairContainer;
52 }
53
59 public StrongNameKeyPair(byte[] keyPairArray)
60 {
61 if (keyPairArray == null)
62 throw new ArgumentNullException("keyPairArray");
63
64 this.keyPairArray = (byte[])keyPairArray.Clone();
65 }
66
71 public StrongNameKeyPair(FileStream keyPairFile) :
72 this(ReadAllBytes(keyPairFile))
73 {
74
75 }
76
77 static byte[] ReadAllBytes(FileStream keyPairFile)
78 {
79 if (keyPairFile == null)
80 throw new ArgumentNullException("keyPairFile");
81
82 var buf = new byte[keyPairFile.Length - keyPairFile.Position];
83 keyPairFile.Read(buf, 0, buf.Length);
84 return buf;
85 }
86
87 public byte[] PublicKey
88 {
89 get
90 {
91 // MONOBUG workaround for https://bugzilla.xamarin.com/show_bug.cgi?id=5299
92 if (Universe.MonoRuntime)
93 return MonoGetPublicKey();
94
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);
100 publicKey[1] = 36;
101 publicKey[4] = 4;
102 publicKey[5] = 128;
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);
107 return publicKey;
108 }
109 }
110
111 internal RSA CreateRSA()
112 {
113 try
114 {
115 if (keyPairArray != null)
116 {
117 var rsa = RSA.Create();
118 // we import from parameters, as using ImportCspBlob
119 // causes the exception "KeySet not found" when signing a hash later.
120 rsa.ImportParameters(RSAParametersFromByteArray(keyPairArray));
121 return rsa;
122 }
123 else
124 {
125#if NETFRAMEWORK
126 var parm = new CspParameters();
127 parm.KeyContainerName = keyPairContainer;
128
129 // MONOBUG Mono doesn't like it when Flags or KeyNumber are set
130 if (Universe.MonoRuntime == false)
131 {
132 parm.Flags = CspProviderFlags.UseMachineKeyStore | CspProviderFlags.UseExistingKey;
133 parm.KeyNumber = 2; // Signature
134 }
135
136 return new RSACryptoServiceProvider(parm);
137#else
138 throw new PlatformNotSupportedException("Strong name key container support is only available when targeting .NET Framework.");
139#endif
140 }
141 }
142 catch
143 {
144 throw new ArgumentException("Unable to obtain public key for StrongNameKeyPair.");
145 }
146 }
147
148 // helper functions ExportPublicKey, RSAParametersFromStream and RSAParametersFromByteArray
149 // based on code in the following article:-
150 // https://www.developerfusion.com/article/84422/the-key-to-strong-names/
151 static byte[] ExportPublicKey(RSAParameters rsaParameters)
152 {
153 if (rsaParameters.Modulus == null || rsaParameters.Exponent == null)
154 throw new ArgumentNullException(nameof(rsaParameters));
155
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);
169 bw.Write(modulus);
170
171 return ms.ToArray();
172 }
173
174 static RSAParameters RSAParametersFromByteArray(byte[] array)
175 {
176 using var ms = new MemoryStream(array);
177 return RSAParametersFromStream(ms);
178 }
179
180 static RSAParameters RSAParametersFromStream(Stream str)
181 {
182 var rsaParameters = new RSAParameters();
183 using var br = new BinaryReader(str);
184
185 // Read BLOBHEADER
186 var keyType = br.ReadByte();
187 if (keyType != 6 && keyType != 7)
188 throw new CryptographicException("SNK file not in correct format");
189
190 var blobVersion = br.ReadByte();
191 var reserverd = br.ReadUInt16();
192 var algorithmID = br.ReadUInt32();
193
194 // Read RSAPUBKEY
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");
198
199 var keyBitLength = br.ReadUInt32();
200 var publicExponent = br.ReadBytes(3);
201 br.ReadByte();
202 rsaParameters.Exponent = publicExponent;
203
204 // Read Modulus
205 var modulus = br.ReadBytes((int)keyBitLength / 8);
206 Array.Reverse(modulus);
207 rsaParameters.Modulus = modulus;
208
209 if (keyType == 7)
210 {
211 // Read Private Key Parameters
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);
218
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;
231 }
232
233 return rsaParameters;
234 }
235
236 [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
237 byte[] MonoGetPublicKey()
238 {
239 return keyPairArray != null ? new System.Reflection.StrongNameKeyPair(keyPairArray).PublicKey : new System.Reflection.StrongNameKeyPair(keyPairContainer).PublicKey;
240 }
241
242 }
243
244}