PageRenderTime 21ms CodeModel.GetById 8ms app.highlight 9ms RepoModel.GetById 1ms app.codeStats 0ms

/Mono.Security.Cryptography/CryptoConvert.cs

http://github.com/jbevain/cecil
C# | 290 lines | 196 code | 33 blank | 61 comment | 24 complexity | cc49d0fd09b40f12bd4b84d2ffe28de4 MD5 | raw file
  1//
  2// CryptoConvert.cs - Crypto Convertion Routines
  3//
  4// Author:
  5//	Sebastien Pouliot  <sebastien@ximian.com>
  6//
  7// (C) 2003 Motus Technologies Inc. (http://www.motus.com)
  8// Copyright (C) 2004-2006 Novell Inc. (http://www.novell.com)
  9//
 10// Permission is hereby granted, free of charge, to any person obtaining
 11// a copy of this software and associated documentation files (the
 12// "Software"), to deal in the Software without restriction, including
 13// without limitation the rights to use, copy, modify, merge, publish,
 14// distribute, sublicense, and/or sell copies of the Software, and to
 15// permit persons to whom the Software is furnished to do so, subject to
 16// the following conditions:
 17//
 18// The above copyright notice and this permission notice shall be
 19// included in all copies or substantial portions of the Software.
 20//
 21// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 22// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 23// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 24// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 25// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 26// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 27// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 28//
 29
 30using System;
 31using System.Security.Cryptography;
 32
 33namespace Mono.Security.Cryptography {
 34
 35	static class CryptoConvert {
 36
 37		static private int ToInt32LE (byte [] bytes, int offset)
 38		{
 39			return (bytes [offset+3] << 24) | (bytes [offset+2] << 16) | (bytes [offset+1] << 8) | bytes [offset];
 40		}
 41
 42		static private uint ToUInt32LE (byte [] bytes, int offset)
 43		{
 44			return (uint)((bytes [offset+3] << 24) | (bytes [offset+2] << 16) | (bytes [offset+1] << 8) | bytes [offset]);
 45		}
 46
 47		static private byte [] GetBytesLE (int val)
 48		{
 49			return new byte [] { 
 50				(byte) (val & 0xff), 
 51				(byte) ((val >> 8) & 0xff), 
 52				(byte) ((val >> 16) & 0xff), 
 53				(byte) ((val >> 24) & 0xff)
 54			};
 55                }
 56
 57		static private byte[] Trim (byte[] array)
 58		{
 59			for (int i=0; i < array.Length; i++) {
 60				if (array [i] != 0x00) {
 61					byte[] result = new byte [array.Length - i];
 62					Buffer.BlockCopy (array, i, result, 0, result.Length);
 63					return result;
 64				}
 65			}
 66			return null;
 67		}
 68
 69		static RSA FromCapiPrivateKeyBlob (byte[] blob, int offset)
 70		{
 71			RSAParameters rsap = new RSAParameters ();
 72			try {
 73				if ((blob [offset]   != 0x07) ||				// PRIVATEKEYBLOB (0x07)
 74				    (blob [offset+1] != 0x02) ||				// Version (0x02)
 75				    (blob [offset+2] != 0x00) ||				// Reserved (word)
 76				    (blob [offset+3] != 0x00) ||
 77				    (ToUInt32LE (blob, offset+8) != 0x32415352))	// DWORD magic = RSA2
 78					throw new CryptographicException ("Invalid blob header");
 79
 80				// ALGID (CALG_RSA_SIGN, CALG_RSA_KEYX, ...)
 81				// int algId = ToInt32LE (blob, offset+4);
 82
 83				// DWORD bitlen
 84				int bitLen = ToInt32LE (blob, offset+12);
 85
 86				// DWORD public exponent
 87				byte[] exp = new byte [4];
 88				Buffer.BlockCopy (blob, offset+16, exp, 0, 4);
 89				Array.Reverse (exp);
 90				rsap.Exponent = Trim (exp);
 91
 92				int pos = offset+20;
 93				// BYTE modulus[rsapubkey.bitlen/8];
 94				int byteLen = (bitLen >> 3);
 95				rsap.Modulus = new byte [byteLen];
 96				Buffer.BlockCopy (blob, pos, rsap.Modulus, 0, byteLen);
 97				Array.Reverse (rsap.Modulus);
 98				pos += byteLen;
 99
100				// BYTE prime1[rsapubkey.bitlen/16];
101				int byteHalfLen = (byteLen >> 1);
102				rsap.P = new byte [byteHalfLen];
103				Buffer.BlockCopy (blob, pos, rsap.P, 0, byteHalfLen);
104				Array.Reverse (rsap.P);
105				pos += byteHalfLen;
106
107				// BYTE prime2[rsapubkey.bitlen/16];
108				rsap.Q = new byte [byteHalfLen];
109				Buffer.BlockCopy (blob, pos, rsap.Q, 0, byteHalfLen);
110				Array.Reverse (rsap.Q);
111				pos += byteHalfLen;
112
113				// BYTE exponent1[rsapubkey.bitlen/16];
114				rsap.DP = new byte [byteHalfLen];
115				Buffer.BlockCopy (blob, pos, rsap.DP, 0, byteHalfLen);
116				Array.Reverse (rsap.DP);
117				pos += byteHalfLen;
118
119				// BYTE exponent2[rsapubkey.bitlen/16];
120				rsap.DQ = new byte [byteHalfLen];
121				Buffer.BlockCopy (blob, pos, rsap.DQ, 0, byteHalfLen);
122				Array.Reverse (rsap.DQ);
123				pos += byteHalfLen;
124
125				// BYTE coefficient[rsapubkey.bitlen/16];
126				rsap.InverseQ = new byte [byteHalfLen];
127				Buffer.BlockCopy (blob, pos, rsap.InverseQ, 0, byteHalfLen);
128				Array.Reverse (rsap.InverseQ);
129				pos += byteHalfLen;
130
131				// ok, this is hackish but CryptoAPI support it so...
132				// note: only works because CRT is used by default
133				// http://bugzilla.ximian.com/show_bug.cgi?id=57941
134				rsap.D = new byte [byteLen]; // must be allocated
135				if (pos + byteLen + offset <= blob.Length) {
136					// BYTE privateExponent[rsapubkey.bitlen/8];
137					Buffer.BlockCopy (blob, pos, rsap.D, 0, byteLen);
138					Array.Reverse (rsap.D);
139				}
140			}
141			catch (Exception e) {
142				throw new CryptographicException ("Invalid blob.", e);
143			}
144
145			RSA rsa = null;
146			try {
147				rsa = RSA.Create ();
148				rsa.ImportParameters (rsap);
149			}
150			catch (CryptographicException) {
151				// this may cause problem when this code is run under
152				// the SYSTEM identity on Windows (e.g. ASP.NET). See
153				// http://bugzilla.ximian.com/show_bug.cgi?id=77559
154				bool throws = false;
155				try {
156					CspParameters csp = new CspParameters ();
157					csp.Flags = CspProviderFlags.UseMachineKeyStore;
158					rsa = new RSACryptoServiceProvider (csp);
159					rsa.ImportParameters (rsap);
160				}
161				catch {
162					throws = true;
163				}
164
165				if (throws) {
166					// rethrow original, not the latter, exception if this fails
167					throw;
168				}
169			}
170			return rsa;
171		}
172
173		static RSA FromCapiPublicKeyBlob (byte[] blob, int offset)
174		{
175			try {
176				if ((blob [offset]   != 0x06) ||				// PUBLICKEYBLOB (0x06)
177				    (blob [offset+1] != 0x02) ||				// Version (0x02)
178				    (blob [offset+2] != 0x00) ||				// Reserved (word)
179				    (blob [offset+3] != 0x00) ||
180				    (ToUInt32LE (blob, offset+8) != 0x31415352))	// DWORD magic = RSA1
181					throw new CryptographicException ("Invalid blob header");
182
183				// ALGID (CALG_RSA_SIGN, CALG_RSA_KEYX, ...)
184				// int algId = ToInt32LE (blob, offset+4);
185
186				// DWORD bitlen
187				int bitLen = ToInt32LE (blob, offset+12);
188
189				// DWORD public exponent
190				RSAParameters rsap = new RSAParameters ();
191				rsap.Exponent = new byte [3];
192				rsap.Exponent [0] = blob [offset+18];
193				rsap.Exponent [1] = blob [offset+17];
194				rsap.Exponent [2] = blob [offset+16];
195
196				int pos = offset+20;
197				// BYTE modulus[rsapubkey.bitlen/8];
198				int byteLen = (bitLen >> 3);
199				rsap.Modulus = new byte [byteLen];
200				Buffer.BlockCopy (blob, pos, rsap.Modulus, 0, byteLen);
201				Array.Reverse (rsap.Modulus);
202
203				RSA rsa = null;
204				try {
205					rsa = RSA.Create ();
206					rsa.ImportParameters (rsap);
207				}
208				catch (CryptographicException) {
209					// this may cause problem when this code is run under
210					// the SYSTEM identity on Windows (e.g. ASP.NET). See
211					// http://bugzilla.ximian.com/show_bug.cgi?id=77559
212					CspParameters csp = new CspParameters ();
213					csp.Flags = CspProviderFlags.UseMachineKeyStore;
214					rsa = new RSACryptoServiceProvider (csp);
215					rsa.ImportParameters (rsap);
216				}
217				return rsa;
218			}
219			catch (Exception e) {
220				throw new CryptographicException ("Invalid blob.", e);
221			}
222		}
223
224		// PRIVATEKEYBLOB
225		// PUBLICKEYBLOB
226		static public RSA FromCapiKeyBlob (byte[] blob)
227		{
228			return FromCapiKeyBlob (blob, 0);
229		}
230
231		static public RSA FromCapiKeyBlob (byte[] blob, int offset)
232		{
233			if (blob == null)
234				throw new ArgumentNullException ("blob");
235			if (offset >= blob.Length)
236				throw new ArgumentException ("blob is too small.");
237
238			switch (blob [offset]) {
239				case 0x00:
240					// this could be a public key inside an header
241					// like "sn -e" would produce
242					if (blob [offset + 12] == 0x06) {
243						return FromCapiPublicKeyBlob (blob, offset + 12);
244					}
245					break;
246				case 0x06:
247					return FromCapiPublicKeyBlob (blob, offset);
248				case 0x07:
249					return FromCapiPrivateKeyBlob (blob, offset);
250			}
251			throw new CryptographicException ("Unknown blob format.");
252		}
253
254		static public byte[] ToCapiPublicKeyBlob (RSA rsa) 
255		{
256			RSAParameters p = rsa.ExportParameters (false);
257			int keyLength = p.Modulus.Length; // in bytes
258			byte[] blob = new byte [20 + keyLength];
259
260			blob [0] = 0x06;	// Type - PUBLICKEYBLOB (0x06)
261			blob [1] = 0x02;	// Version - Always CUR_BLOB_VERSION (0x02)
262			// [2], [3]		// RESERVED - Always 0
263			blob [5] = 0x24;	// ALGID - Always 00 24 00 00 (for CALG_RSA_SIGN)
264			blob [8] = 0x52;	// Magic - RSA1 (ASCII in hex)
265			blob [9] = 0x53;
266			blob [10] = 0x41;
267			blob [11] = 0x31;
268
269			byte[] bitlen = GetBytesLE (keyLength << 3);
270			blob [12] = bitlen [0];	// bitlen
271			blob [13] = bitlen [1];	
272			blob [14] = bitlen [2];	
273			blob [15] = bitlen [3];
274
275			// public exponent (DWORD)
276			int pos = 16;
277			int n = p.Exponent.Length;
278			while (n > 0)
279				blob [pos++] = p.Exponent [--n];
280			// modulus
281			pos = 20;
282			byte[] part = p.Modulus;
283			int len = part.Length;
284			Array.Reverse (part, 0, len);
285			Buffer.BlockCopy (part, 0, blob, pos, len);
286			pos += len;
287			return blob;
288		}
289	}
290}