2008-05-19 George Giolfan <georgegiolfan@yahoo.com>
[mono.git] / mcs / class / System.Web / System.Web.Configuration / MachineKeyRegistryStorage.cs
1 //
2 // System.Web.Configuration.MachineKeyRegistryStorage
3 //
4 // Authors:
5 //      Marek Habersack <mhabersack@novell.com>
6 //
7 // (C) 2007 Novell, Inc
8 //
9
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 using System;
32 using System.Security.Cryptography;
33 using Microsoft.Win32;
34
35 namespace System.Web.Configuration
36 {
37         internal class MachineKeyRegistryStorage
38         {
39                 public enum KeyType
40                 {
41                         Validation,
42                         Encryption
43                 };
44
45                 const int encryptionKeyLength = 64;
46                 const int validationKeyLength = 64;
47                 
48                 static string keyEncryption;
49                 static string keyValidation;
50                 static bool noStore;
51                 
52                 static MachineKeyRegistryStorage ()
53                 {
54                         string appName = AppDomain.CurrentDomain.SetupInformation.ApplicationName;
55                         if (appName == null) {
56                                 noStore = true;
57                                 return;
58                         }
59                         
60                         string hash = appName.GetHashCode ().ToString ("x");
61                         keyEncryption = "software\\mono\\asp.net\\" + Environment.Version.ToString () +
62                                 "\\autogenkeys\\" + hash + "-" + ((int)KeyType.Encryption).ToString ();
63                         keyValidation = "software\\mono\\asp.net\\" + Environment.Version.ToString () +
64                                 "\\autogenkeys\\" + hash + "-" + ((int)KeyType.Validation).ToString ();
65                 }
66                 
67                 public static byte[] Retrieve (KeyType kt)
68                 {
69                         byte[] ret = GetKey (kt);
70                         if (ret == null) {
71                                 ret = Generate (kt);
72                                 if (ret != null)
73                                         Store (ret, kt);
74                         }
75                         
76                         return ret;
77                 }
78
79                 static byte[] GetKey (KeyType kt)
80                 {
81                         string key = null;
82                         int len;
83                         
84                         switch (kt) {
85                                 case KeyType.Validation:
86                                         key = keyValidation;
87                                         len = validationKeyLength;
88                                         break;
89
90                                 case KeyType.Encryption:
91                                         key = keyEncryption;
92                                         len = validationKeyLength;
93                                         break;
94
95                                 default:
96                                         throw new ArgumentException ("Unknown key type.");
97                         }
98
99                         if (key == null)
100                                 return null;
101                         
102                         object o = null;
103
104                         try {
105                                 RegistryKey v = OpenRegistryKey (key, false);
106                                 o = v.GetValue ("AutoGenKey", null);
107                         } catch (Exception) {
108                                 return null;
109                         }
110
111                         if (o == null || o.GetType () != typeof (byte[]))
112                                 return null;
113                         byte[] ret = (byte[])o;
114                         if (ret.Length != len)
115                                 return null;
116
117                         return ret;
118                 }
119
120                 static RegistryKey OpenRegistryKey (string path, bool write)
121                 {
122                         RegistryKey ret, tmp;
123                         string[] keys = path.Split ('\\');
124                         int klen = keys.Length;
125
126                         ret = Registry.CurrentUser;
127                         for (int i = 0; i < klen; i++) {
128                                 tmp = ret.OpenSubKey (keys [i], true);
129                                 if (tmp == null) {
130                                         if (!write)
131                                                 return null;
132                                         tmp = ret.CreateSubKey (keys [i]);
133                                 }
134                                 ret = tmp;
135                         }
136
137                         return ret;
138                 }
139                 
140                 static void Store (byte[] buf, KeyType kt)
141                 {
142                         if (buf == null)
143                                 return;
144                         
145                         string key = null;
146                         int len;
147                         
148                         switch (kt) {
149                                 case KeyType.Validation:
150                                         key = keyValidation;
151                                         len = validationKeyLength;
152                                         break;
153
154                                 case KeyType.Encryption:
155                                         key = keyEncryption;
156                                         len = validationKeyLength;
157                                         break;
158
159                                 default:
160                                         throw new ArgumentException ("Unknown key type.");
161                         }
162
163                         if (key == null)
164                                 return;
165
166                         if (buf.Length != len)
167                                 throw new ArgumentException ("Key has invalid length");
168
169                         try {
170                                 using (RegistryKey rk = OpenRegistryKey (key, true)) {
171 #if NET_2_0
172                                         rk.SetValue ("AutoGenKey", buf, RegistryValueKind.Binary);
173                                         rk.SetValue ("AutoGenKeyCreationTime", DateTime.Now.Ticks, RegistryValueKind.QWord);
174                                         rk.SetValue ("AutoGenKeyFormat", 2, RegistryValueKind.DWord);
175 #else
176                                         rk.SetValue ("AutoGenKey", buf);
177                                         rk.SetValue ("AutoGenKeyCreationTime", DateTime.Now.Ticks);
178                                         rk.SetValue ("AutoGenKeyFormat", 2);
179 #endif
180                                         rk.Flush (); // we want it synchronous
181                                 }
182                         } catch (Exception ex) {
183                                 throw new ApplicationException ("Failed to store encryption key in the registry.", ex);
184                         }
185                 }
186
187                 static byte[] Generate (KeyType kt)
188                 {
189                         RandomNumberGenerator rng = RandomNumberGenerator.Create ();
190                         byte[] ret = null;
191                         
192                         switch (kt) {
193                                 case KeyType.Validation:
194                                         ret = new byte [validationKeyLength];
195                                         break;
196
197                                 case KeyType.Encryption:
198                                         ret = new byte [encryptionKeyLength];
199                                         break;
200
201                                 default:
202                                         throw new ArgumentException ("Unknown key type.");
203                         }
204                         
205                         rng.GetBytes (ret);
206                         return ret;
207                 }
208         }
209 }