Merge pull request #2716 from BrzVlad/fix-tramp-jinfo
[mono.git] / mcs / class / System.Web / System.Web.Security / MachineKey.cs
1 //
2 // Authors:
3 //   Marek Habersack <grendel@twistedcode.net>
4 //
5 // (C) 2011 Novell, Inc (http://novell.com/)
6 //
7
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 using System;
30 using System.Web;
31 using System.Web.Configuration;
32 using System.Web.Util;
33 using System.IO;
34 using System.Security.Cryptography;
35 using System.Text;
36
37 namespace System.Web.Security 
38 {
39         public static class MachineKey
40         {
41                 public static byte[] Decode (string encodedData, MachineKeyProtection protectionOption)
42                 {
43                         if (encodedData == null)
44                                 throw new ArgumentNullException ("encodedData");
45
46                         int dlen = encodedData.Length;
47                         if (dlen == 0 || dlen % 2 == 1)
48                                 throw new ArgumentException ("encodedData");
49
50                         byte[] data = MachineKeySectionUtils.GetBytes (encodedData, dlen);
51                         if (data == null || data.Length == 0)
52                                 throw new ArgumentException ("encodedData");
53                         
54                         var config = WebConfigurationManager.GetWebApplicationSection ("system.web/machineKey") as MachineKeySection;
55                         byte[] result = null;
56                         Exception ex = null;
57                         try {
58                                 switch (protectionOption) {
59                                         case MachineKeyProtection.All:
60                                                 result = MachineKeySectionUtils.VerifyDecrypt (config, data);
61                                                 break;
62
63                                         case MachineKeyProtection.Encryption:
64                                                 result = MachineKeySectionUtils.Decrypt (config, data);
65                                                 break;
66
67                                         case MachineKeyProtection.Validation:
68                                                 result = MachineKeySectionUtils.Verify (config, data);
69                                                 break;
70
71                                         default:
72                                                 return MachineKeySectionUtils.GetBytes (encodedData, dlen);
73                                 }
74                         } catch (Exception e) {
75                                 ex = e;
76                         }
77                         
78                         if (result == null || ex != null)
79                                 throw new HttpException ("Unable to verify passed data.", ex);
80                         
81                         return result;
82                 }
83
84                 public static string Encode (byte[] data, MachineKeyProtection protectionOption)
85                 {
86                         if (data == null)
87                                 throw new ArgumentNullException ("data");
88
89                         var config = WebConfigurationManager.GetWebApplicationSection ("system.web/machineKey") as MachineKeySection;
90                         byte[] result;
91                         switch (protectionOption) {
92                                 case MachineKeyProtection.All:
93                                         result = MachineKeySectionUtils.EncryptSign (config, data);
94                                         break;
95
96                                 case MachineKeyProtection.Encryption:
97                                         result = MachineKeySectionUtils.Encrypt (config, data);
98                                         break;
99
100                                 case MachineKeyProtection.Validation:
101                                         result = MachineKeySectionUtils.Sign (config, data);
102                                         break;
103
104                                 default:
105                                         return String.Empty;
106                         }
107                         
108                         return MachineKeySectionUtils.GetHexString (result);
109                 }
110
111                 public static byte[] Protect (byte[] userData, params string[] purposes)
112                 {
113                         if (userData == null)
114                                 throw new ArgumentNullException ("userData");
115
116                         foreach (var purpose in purposes)
117                         {
118                                 if (string.IsNullOrWhiteSpace (purpose))
119                                         throw new ArgumentException ("all purpose parameters must contain text");
120                         }
121
122                         var config = WebConfigurationManager.GetWebApplicationSection ("system.web/machineKey") as MachineKeySection;
123                         var purposeJoined = string.Join (";", purposes);
124                         var purposeBytes = GetHashed (purposeJoined);
125                         var bytes = new byte [userData.Length + purposeBytes.Length];
126                         purposeBytes.CopyTo (bytes, 0);
127                         userData.CopyTo (bytes, purposeBytes.Length);
128                         return MachineKeySectionUtils.Encrypt (config, bytes);
129                 }
130
131                 public static byte[] Unprotect (byte[] protectedData, params string[] purposes)
132                 {
133                         if (protectedData == null)
134                                 throw new ArgumentNullException ("protectedData");
135
136                         foreach (var purpose in purposes) {
137                                 if (string.IsNullOrWhiteSpace (purpose))
138                                         throw new ArgumentException ("all purpose parameters must contain text");
139                         }
140
141                         var config = WebConfigurationManager.GetWebApplicationSection ("system.web/machineKey") as MachineKeySection;
142                         var purposeJoined = string.Join (";", purposes);
143                         var purposeBytes = GetHashed (purposeJoined);
144                         var unprotected = MachineKeySectionUtils.Decrypt (config, protectedData);
145
146                         for (int i = 0; i < purposeBytes.Length; i++) {
147                                 if (purposeBytes [i] != unprotected [i])
148                                         throw new CryptographicException ();
149                         }
150
151                         var dataLength = unprotected.Length - purposeBytes.Length;
152                         var result = new byte [dataLength];
153                         Array.Copy (unprotected, purposeBytes.Length, result, 0, dataLength);
154                         return result;
155                 }
156
157                 static byte[] GetHashed (string purposes)
158                 {
159                         using (var hash = SHA512.Create ()) {
160                                 var bytes = Encoding.UTF8.GetBytes (purposes);
161                                 return hash.ComputeHash (bytes, 0, bytes.Length);
162                         }
163                 }
164         }
165 }