2004-01-25 Martin Baulig <martin@ximian.com>
[mono.git] / mcs / class / corlib / System.Reflection / StrongNameKeyPair.cs
1 //
2 // System.Reflection.StrongNameKeyPair.cs
3 //
4 // Authors:
5 //      Kevin Winchester (kwin@ns.sympatico.ca)
6 //      Sebastien Pouliot (spouliot@motus.com)
7 //
8 // (C) 2002 Kevin Winchester
9 // Portions (C) 2002 Motus Technologies Inc. (http://www.motus.com)
10 //
11
12 using System.IO;
13
14 namespace System.Reflection {
15
16 [Serializable]
17 public class StrongNameKeyPair 
18 {               
19         private byte[] keyPair;
20         private byte[] publicKey;
21         private int bitLen;
22         private bool keypairValid;
23
24         public StrongNameKeyPair (byte[] keyPairArray) 
25         {
26                 if (keyPairArray == null)
27                         throw new ArgumentNullException ("keyPairArray");
28                 keypairValid = Validate (keyPairArray);
29         }
30         
31         public StrongNameKeyPair (FileStream keyPairFile) 
32         {
33                 if (keyPairFile == null)
34                         throw new ArgumentNullException ("keyPairFile");
35                 byte[] input = new byte [keyPairFile.Length];
36                 keyPairFile.Read (input, 0, input.Length);
37                 keypairValid = Validate (input);
38         }
39         
40         [MonoTODO("We do not, yet, support keypair persistance")]
41         public StrongNameKeyPair (string keyPairContainer) 
42         {
43                 // named key container
44                 if (keyPairContainer == null)
45                         throw new ArgumentNullException ("keyPairContainer");
46                 // only RSA ? or both RSA and DSA ?
47                 throw new NotImplementedException ();
48         }
49
50         private bool Validate (byte[] keypair) {
51                 // Type - PRIVATEKEYBLOB (0x07)
52                 if (keypair[0] != 0x07)
53                         return false;
54                 // Version - Always CUR_BLOB_VERSION (0x02)
55                 if (keypair[1] != 0x02)
56                         return false;
57                 // RESERVED - Always 0
58                 if ((keypair[2] != 0x00) || (keypair[3] != 0x00))
59                         return false;
60                 // ALGID - Always 00 24 00 00 (for CALG_RSA_SIGN)
61                 if ((keypair[4] != 0x00) || (keypair[5] != 0x24) || (keypair[6] != 0x00) || (keypair[7] != 0x00))
62                         return false;
63                 // Magic - RSA2 (ASCII in hex)
64                 if ((keypair[8] != 0x52) || (keypair[9] != 0x53) || (keypair[10] != 0x41) || (keypair[11] != 0x32))
65                         return false;
66                 // bitlen - ex: 1024 - must be a multiple of 8
67                 bitLen = (keypair[15] << 24) + (keypair[14] << 16) + (keypair[13] << 8) + keypair[12];
68                 if (bitLen % 8 != 0)
69                         return false;
70                 // public exponent (DWORD)
71                 // modulus
72                 // private key
73                 keyPair = keypair;
74                 return true;
75         }
76
77         public byte[] PublicKey {
78                 get { 
79                         if (!keypairValid)
80                                 throw new ArgumentException ("invalid keypair");
81                         // first call (will be cached for all subsequent calls)
82                         if (publicKey == null) {
83                                 publicKey = new byte [(bitLen >> 3) + 32];
84                                 // The first 12 bytes are documented at:
85                                 // http://msdn.microsoft.com/library/en-us/cprefadd/html/grfungethashfromfile.asp
86                                 // ALG_ID - Signature
87                                 publicKey[0] = keyPair[4];
88                                 publicKey[1] = keyPair[5];      
89                                 publicKey[2] = keyPair[6];      
90                                 publicKey[3] = keyPair[7];      
91                                 // ALG_ID - Hash
92                                 publicKey[4] = 0x04;
93                                 publicKey[5] = 0x80;
94                                 publicKey[6] = 0x00;
95                                 publicKey[7] = 0x00;
96                                 // Length of Public Key (in bytes)
97                                 int lastPart = publicKey.Length - 12;
98                                 publicKey[8] = (byte)(lastPart % 256);
99                                 publicKey[9] = (byte)(lastPart / 256); // just in case
100                                 publicKey[10] = 0x00;
101                                 publicKey[11] = 0x00;
102                                 // Ok from here - Same structure as keypair - expect for public key
103                                 publicKey[12] = 0x06;           // PUBLICKEYBLOB
104                                 // we can copy this part
105                                 Array.Copy (keyPair, 1, publicKey, 13, publicKey.Length - 13);
106                                 // and make a small adjustment 
107                                 publicKey[23] = 0x31;           // (RSA1 not RSA2)
108                         }
109                         return publicKey; 
110                 }
111         }
112 }
113
114 }