actually I gave wrong file name.
[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 = String.Format ("software\\mono\\asp.net\\{0}\\autogenkeys\\{1}-{2}",
62                                                        Environment.Version,
63                                                        hash,
64                                                        (int)KeyType.Encryption);
65                         keyValidation = String.Format ("software\\mono\\asp.net\\{0}\\autogenkeys\\{1}-{2}",
66                                                        Environment.Version,
67                                                        hash,
68                                                        (int)KeyType.Validation);
69                 }
70                 
71                 public static byte[] Retrieve (KeyType kt)
72                 {
73                         byte[] ret = GetKey (kt);
74                         if (ret == null) {
75                                 ret = Generate (kt);
76                                 if (ret != null)
77                                         Store (ret, kt);
78                         }
79                         
80                         return ret;
81                 }
82
83                 static byte[] GetKey (KeyType kt)
84                 {
85                         string key = null;
86                         int len;
87                         
88                         switch (kt) {
89                                 case KeyType.Validation:
90                                         key = keyValidation;
91                                         len = validationKeyLength;
92                                         break;
93
94                                 case KeyType.Encryption:
95                                         key = keyEncryption;
96                                         len = validationKeyLength;
97                                         break;
98
99                                 default:
100                                         throw new ArgumentException ("Unknown key type.");
101                         }
102
103                         if (key == null)
104                                 return null;
105                         
106                         object o = null;
107
108                         try {
109                                 RegistryKey v = OpenRegistryKey (key, false);
110                                 o = v.GetValue ("AutoGenKey", null);
111                         } catch (Exception) {
112                                 return null;
113                         }
114
115                         if (o == null || o.GetType () != typeof (byte[]))
116                                 return null;
117                         byte[] ret = (byte[])o;
118                         if (ret.Length != len)
119                                 return null;
120
121                         return ret;
122                 }
123
124                 static RegistryKey OpenRegistryKey (string path, bool write)
125                 {
126                         RegistryKey ret, tmp;
127                         string[] keys = path.Split ('\\');
128                         int klen = keys.Length;
129
130                         ret = Registry.CurrentUser;
131                         for (int i = 0; i < klen; i++) {
132                                 tmp = ret.OpenSubKey (keys [i], true);
133                                 if (tmp == null) {
134                                         if (!write)
135                                                 return null;
136                                         tmp = ret.CreateSubKey (keys [i]);
137                                 }
138                                 ret = tmp;
139                         }
140
141                         return ret;
142                 }
143                 
144                 static void Store (byte[] buf, KeyType kt)
145                 {
146                         if (buf == null)
147                                 return;
148                         
149                         string key = null;
150                         int len;
151                         
152                         switch (kt) {
153                                 case KeyType.Validation:
154                                         key = keyValidation;
155                                         len = validationKeyLength;
156                                         break;
157
158                                 case KeyType.Encryption:
159                                         key = keyEncryption;
160                                         len = validationKeyLength;
161                                         break;
162
163                                 default:
164                                         throw new ArgumentException ("Unknown key type.");
165                         }
166
167                         if (key == null)
168                                 return;
169
170                         if (buf.Length != len)
171                                 throw new ArgumentException ("Key has invalid length");
172
173                         try {
174                                 using (RegistryKey rk = OpenRegistryKey (key, true)) {
175 #if NET_2_0
176                                         rk.SetValue ("AutoGenKey", buf, RegistryValueKind.Binary);
177                                         rk.SetValue ("AutoGenKeyCreationTime", DateTime.Now.Ticks, RegistryValueKind.QWord);
178                                         rk.SetValue ("AutoGenKeyFormat", 2, RegistryValueKind.DWord);
179 #else
180                                         rk.SetValue ("AutoGenKey", buf);
181                                         rk.SetValue ("AutoGenKeyCreationTime", DateTime.Now.Ticks);
182                                         rk.SetValue ("AutoGenKeyFormat", 2);
183 #endif
184                                         rk.Flush (); // we want it synchronous
185                                 }
186                         } catch (Exception ex) {
187                                 throw new ApplicationException ("Failed to store encryption key in the registry.", ex);
188                         }
189                 }
190
191                 static byte[] Generate (KeyType kt)
192                 {
193                         RandomNumberGenerator rng = RandomNumberGenerator.Create ();
194                         byte[] ret = null;
195                         
196                         switch (kt) {
197                                 case KeyType.Validation:
198                                         ret = new byte [validationKeyLength];
199                                         break;
200
201                                 case KeyType.Encryption:
202                                         ret = new byte [encryptionKeyLength];
203                                         break;
204
205                                 default:
206                                         throw new ArgumentException ("Unknown key type.");
207                         }
208                         
209                         rng.GetBytes (ret);
210                         return ret;
211                 }
212         }
213 }