aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Framework/Communications
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Framework/Communications')
-rw-r--r--OpenSim/Framework/Communications/Cache/CryptoGridAssetClient.cs1054
1 files changed, 527 insertions, 527 deletions
diff --git a/OpenSim/Framework/Communications/Cache/CryptoGridAssetClient.cs b/OpenSim/Framework/Communications/Cache/CryptoGridAssetClient.cs
index a8e6efb..8e88844 100644
--- a/OpenSim/Framework/Communications/Cache/CryptoGridAssetClient.cs
+++ b/OpenSim/Framework/Communications/Cache/CryptoGridAssetClient.cs
@@ -1,527 +1,527 @@
1/* 1/*
2 * Copyright (c) Contributors, http://www.openmetaverse.org/ 2 * Copyright (c) Contributors, http://www.openmetaverse.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met: 6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright 7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright 9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution. 11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the 12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products 13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission. 14 * derived from this software without specific prior written permission.
15 * 15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY 16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY 19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27/* 27/*
28 * This file includes content derived from Obviex. 28 * This file includes content derived from Obviex.
29 * Copyright (C) 2002 Obviex(TM). All rights reserved. 29 * Copyright (C) 2002 Obviex(TM). All rights reserved.
30 * http://www.obviex.com/samples/Encryption.aspx 30 * http://www.obviex.com/samples/Encryption.aspx
31 */ 31 */
32 32
33using System; 33using System;
34using System.Collections.Generic; 34using System.Collections.Generic;
35using System.IO; 35using System.IO;
36using System.Reflection; 36using System.Reflection;
37using System.Text; 37using System.Text;
38using System.Xml.Serialization; 38using System.Xml.Serialization;
39using log4net; 39using log4net;
40using OpenSim.Framework.Servers; 40using OpenSim.Framework.Servers;
41using System.Security.Cryptography; 41using System.Security.Cryptography;
42 42
43namespace OpenSim.Framework.Communications.Cache 43namespace OpenSim.Framework.Communications.Cache
44{ 44{
45 public class CryptoGridAssetClient : AssetServerBase 45 public class CryptoGridAssetClient : AssetServerBase
46 { 46 {
47 #region Keyfile Classes 47 #region Keyfile Classes
48 [Serializable] 48 [Serializable]
49 private class RjinKeyfile 49 private class RjinKeyfile
50 { 50 {
51 public string Secret; 51 public string Secret;
52 public string AlsoKnownAs; 52 public string AlsoKnownAs;
53 public int Keysize; 53 public int Keysize;
54 public string IVBytes; 54 public string IVBytes;
55 public string Description = "OpenSim Key"; 55 public string Description = "OpenSim Key";
56 56
57 private static string SHA1Hash(byte[] bytes) 57 private static string SHA1Hash(byte[] bytes)
58 { 58 {
59 SHA1 sha1 = SHA1CryptoServiceProvider.Create(); 59 SHA1 sha1 = SHA1CryptoServiceProvider.Create();
60 byte[] dataMd5 = sha1.ComputeHash(bytes); 60 byte[] dataMd5 = sha1.ComputeHash(bytes);
61 StringBuilder sb = new StringBuilder(); 61 StringBuilder sb = new StringBuilder();
62 for (int i = 0; i < dataMd5.Length; i++) 62 for (int i = 0; i < dataMd5.Length; i++)
63 sb.AppendFormat("{0:x2}", dataMd5[i]); 63 sb.AppendFormat("{0:x2}", dataMd5[i]);
64 return sb.ToString(); 64 return sb.ToString();
65 } 65 }
66 66
67 public void GenerateRandom() 67 public void GenerateRandom()
68 { 68 {
69 RNGCryptoServiceProvider Gen = new RNGCryptoServiceProvider(); 69 RNGCryptoServiceProvider Gen = new RNGCryptoServiceProvider();
70 70
71 byte[] genSec = new byte[32]; 71 byte[] genSec = new byte[32];
72 byte[] genAKA = new byte[32]; 72 byte[] genAKA = new byte[32];
73 byte[] genIV = new byte[32]; 73 byte[] genIV = new byte[32];
74 74
75 Gen.GetBytes(genSec); 75 Gen.GetBytes(genSec);
76 Gen.GetBytes(genAKA); 76 Gen.GetBytes(genAKA);
77 Gen.GetBytes(genIV); 77 Gen.GetBytes(genIV);
78 78
79 Secret = SHA1Hash(genSec); 79 Secret = SHA1Hash(genSec);
80 AlsoKnownAs = SHA1Hash(genAKA); 80 AlsoKnownAs = SHA1Hash(genAKA);
81 IVBytes = SHA1Hash(genIV).Substring(0, 16); 81 IVBytes = SHA1Hash(genIV).Substring(0, 16);
82 Keysize = 256; 82 Keysize = 256;
83 } 83 }
84 } 84 }
85 #endregion 85 #endregion
86 86
87 #region Rjindael 87 #region Rjindael
88 /// <summary> 88 /// <summary>
89 /// This class uses a symmetric key algorithm (Rijndael/AES) to encrypt and 89 /// This class uses a symmetric key algorithm (Rijndael/AES) to encrypt and
90 /// decrypt data. As long as encryption and decryption routines use the same 90 /// decrypt data. As long as encryption and decryption routines use the same
91 /// parameters to generate the keys, the keys are guaranteed to be the same. 91 /// parameters to generate the keys, the keys are guaranteed to be the same.
92 /// The class uses static functions with duplicate code to make it easier to 92 /// The class uses static functions with duplicate code to make it easier to
93 /// demonstrate encryption and decryption logic. In a real-life application, 93 /// demonstrate encryption and decryption logic. In a real-life application,
94 /// this may not be the most efficient way of handling encryption, so - as 94 /// this may not be the most efficient way of handling encryption, so - as
95 /// soon as you feel comfortable with it - you may want to redesign this class. 95 /// soon as you feel comfortable with it - you may want to redesign this class.
96 /// </summary> 96 /// </summary>
97 private class UtilRijndael 97 private class UtilRijndael
98 { 98 {
99 /// <summary> 99 /// <summary>
100 /// Encrypts specified plaintext using Rijndael symmetric key algorithm 100 /// Encrypts specified plaintext using Rijndael symmetric key algorithm
101 /// and returns a base64-encoded result. 101 /// and returns a base64-encoded result.
102 /// </summary> 102 /// </summary>
103 /// <param name="plainText"> 103 /// <param name="plainText">
104 /// Plaintext value to be encrypted. 104 /// Plaintext value to be encrypted.
105 /// </param> 105 /// </param>
106 /// <param name="passPhrase"> 106 /// <param name="passPhrase">
107 /// Passphrase from which a pseudo-random password will be derived. The 107 /// Passphrase from which a pseudo-random password will be derived. The
108 /// derived password will be used to generate the encryption key. 108 /// derived password will be used to generate the encryption key.
109 /// Passphrase can be any string. In this example we assume that this 109 /// Passphrase can be any string. In this example we assume that this
110 /// passphrase is an ASCII string. 110 /// passphrase is an ASCII string.
111 /// </param> 111 /// </param>
112 /// <param name="saltValue"> 112 /// <param name="saltValue">
113 /// Salt value used along with passphrase to generate password. Salt can 113 /// Salt value used along with passphrase to generate password. Salt can
114 /// be any string. In this example we assume that salt is an ASCII string. 114 /// be any string. In this example we assume that salt is an ASCII string.
115 /// </param> 115 /// </param>
116 /// <param name="hashAlgorithm"> 116 /// <param name="hashAlgorithm">
117 /// Hash algorithm used to generate password. Allowed values are: "MD5" and 117 /// Hash algorithm used to generate password. Allowed values are: "MD5" and
118 /// "SHA1". SHA1 hashes are a bit slower, but more secure than MD5 hashes. 118 /// "SHA1". SHA1 hashes are a bit slower, but more secure than MD5 hashes.
119 /// </param> 119 /// </param>
120 /// <param name="passwordIterations"> 120 /// <param name="passwordIterations">
121 /// Number of iterations used to generate password. One or two iterations 121 /// Number of iterations used to generate password. One or two iterations
122 /// should be enough. 122 /// should be enough.
123 /// </param> 123 /// </param>
124 /// <param name="initVector"> 124 /// <param name="initVector">
125 /// Initialization vector (or IV). This value is required to encrypt the 125 /// Initialization vector (or IV). This value is required to encrypt the
126 /// first block of plaintext data. For RijndaelManaged class IV must be 126 /// first block of plaintext data. For RijndaelManaged class IV must be
127 /// exactly 16 ASCII characters long. 127 /// exactly 16 ASCII characters long.
128 /// </param> 128 /// </param>
129 /// <param name="keySize"> 129 /// <param name="keySize">
130 /// Size of encryption key in bits. Allowed values are: 128, 192, and 256. 130 /// Size of encryption key in bits. Allowed values are: 128, 192, and 256.
131 /// Longer keys are more secure than shorter keys. 131 /// Longer keys are more secure than shorter keys.
132 /// </param> 132 /// </param>
133 /// <returns> 133 /// <returns>
134 /// Encrypted value formatted as a base64-encoded string. 134 /// Encrypted value formatted as a base64-encoded string.
135 /// </returns> 135 /// </returns>
136 public static byte[] Encrypt(byte[] plainText, 136 public static byte[] Encrypt(byte[] plainText,
137 string passPhrase, 137 string passPhrase,
138 string saltValue, 138 string saltValue,
139 string hashAlgorithm, 139 string hashAlgorithm,
140 int passwordIterations, 140 int passwordIterations,
141 string initVector, 141 string initVector,
142 int keySize) 142 int keySize)
143 { 143 {
144 // Convert strings into byte arrays. 144 // Convert strings into byte arrays.
145 // Let us assume that strings only contain ASCII codes. 145 // Let us assume that strings only contain ASCII codes.
146 // If strings include Unicode characters, use Unicode, UTF7, or UTF8 146 // If strings include Unicode characters, use Unicode, UTF7, or UTF8
147 // encoding. 147 // encoding.
148 byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector); 148 byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
149 byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue); 149 byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue);
150 150
151 // Convert our plaintext into a byte array. 151 // Convert our plaintext into a byte array.
152 // Let us assume that plaintext contains UTF8-encoded characters. 152 // Let us assume that plaintext contains UTF8-encoded characters.
153 byte[] plainTextBytes = plainText; 153 byte[] plainTextBytes = plainText;
154 154
155 // First, we must create a password, from which the key will be derived. 155 // First, we must create a password, from which the key will be derived.
156 // This password will be generated from the specified passphrase and 156 // This password will be generated from the specified passphrase and
157 // salt value. The password will be created using the specified hash 157 // salt value. The password will be created using the specified hash
158 // algorithm. Password creation can be done in several iterations. 158 // algorithm. Password creation can be done in several iterations.
159 PasswordDeriveBytes password = new PasswordDeriveBytes( 159 PasswordDeriveBytes password = new PasswordDeriveBytes(
160 passPhrase, 160 passPhrase,
161 saltValueBytes, 161 saltValueBytes,
162 hashAlgorithm, 162 hashAlgorithm,
163 passwordIterations); 163 passwordIterations);
164 164
165 // Use the password to generate pseudo-random bytes for the encryption 165 // Use the password to generate pseudo-random bytes for the encryption
166 // key. Specify the size of the key in bytes (instead of bits). 166 // key. Specify the size of the key in bytes (instead of bits).
167 byte[] keyBytes = password.GetBytes(keySize / 8); 167 byte[] keyBytes = password.GetBytes(keySize / 8);
168 168
169 // Create uninitialized Rijndael encryption object. 169 // Create uninitialized Rijndael encryption object.
170 RijndaelManaged symmetricKey = new RijndaelManaged(); 170 RijndaelManaged symmetricKey = new RijndaelManaged();
171 171
172 // It is reasonable to set encryption mode to Cipher Block Chaining 172 // It is reasonable to set encryption mode to Cipher Block Chaining
173 // (CBC). Use default options for other symmetric key parameters. 173 // (CBC). Use default options for other symmetric key parameters.
174 symmetricKey.Mode = CipherMode.CBC; 174 symmetricKey.Mode = CipherMode.CBC;
175 175
176 // Generate encryptor from the existing key bytes and initialization 176 // Generate encryptor from the existing key bytes and initialization
177 // vector. Key size will be defined based on the number of the key 177 // vector. Key size will be defined based on the number of the key
178 // bytes. 178 // bytes.
179 ICryptoTransform encryptor = symmetricKey.CreateEncryptor( 179 ICryptoTransform encryptor = symmetricKey.CreateEncryptor(
180 keyBytes, 180 keyBytes,
181 initVectorBytes); 181 initVectorBytes);
182 182
183 // Define memory stream which will be used to hold encrypted data. 183 // Define memory stream which will be used to hold encrypted data.
184 MemoryStream memoryStream = new MemoryStream(); 184 MemoryStream memoryStream = new MemoryStream();
185 185
186 // Define cryptographic stream (always use Write mode for encryption). 186 // Define cryptographic stream (always use Write mode for encryption).
187 CryptoStream cryptoStream = new CryptoStream(memoryStream, 187 CryptoStream cryptoStream = new CryptoStream(memoryStream,
188 encryptor, 188 encryptor,
189 CryptoStreamMode.Write); 189 CryptoStreamMode.Write);
190 // Start encrypting. 190 // Start encrypting.
191 cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length); 191 cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
192 192
193 // Finish encrypting. 193 // Finish encrypting.
194 cryptoStream.FlushFinalBlock(); 194 cryptoStream.FlushFinalBlock();
195 195
196 // Convert our encrypted data from a memory stream into a byte array. 196 // Convert our encrypted data from a memory stream into a byte array.
197 byte[] cipherTextBytes = memoryStream.ToArray(); 197 byte[] cipherTextBytes = memoryStream.ToArray();
198 198
199 // Close both streams. 199 // Close both streams.
200 memoryStream.Close(); 200 memoryStream.Close();
201 cryptoStream.Close(); 201 cryptoStream.Close();
202 202
203 // Return encrypted string. 203 // Return encrypted string.
204 return cipherTextBytes; 204 return cipherTextBytes;
205 } 205 }
206 206
207 /// <summary> 207 /// <summary>
208 /// Decrypts specified ciphertext using Rijndael symmetric key algorithm. 208 /// Decrypts specified ciphertext using Rijndael symmetric key algorithm.
209 /// </summary> 209 /// </summary>
210 /// <param name="cipherText"> 210 /// <param name="cipherText">
211 /// Base64-formatted ciphertext value. 211 /// Base64-formatted ciphertext value.
212 /// </param> 212 /// </param>
213 /// <param name="passPhrase"> 213 /// <param name="passPhrase">
214 /// Passphrase from which a pseudo-random password will be derived. The 214 /// Passphrase from which a pseudo-random password will be derived. The
215 /// derived password will be used to generate the encryption key. 215 /// derived password will be used to generate the encryption key.
216 /// Passphrase can be any string. In this example we assume that this 216 /// Passphrase can be any string. In this example we assume that this
217 /// passphrase is an ASCII string. 217 /// passphrase is an ASCII string.
218 /// </param> 218 /// </param>
219 /// <param name="saltValue"> 219 /// <param name="saltValue">
220 /// Salt value used along with passphrase to generate password. Salt can 220 /// Salt value used along with passphrase to generate password. Salt can
221 /// be any string. In this example we assume that salt is an ASCII string. 221 /// be any string. In this example we assume that salt is an ASCII string.
222 /// </param> 222 /// </param>
223 /// <param name="hashAlgorithm"> 223 /// <param name="hashAlgorithm">
224 /// Hash algorithm used to generate password. Allowed values are: "MD5" and 224 /// Hash algorithm used to generate password. Allowed values are: "MD5" and
225 /// "SHA1". SHA1 hashes are a bit slower, but more secure than MD5 hashes. 225 /// "SHA1". SHA1 hashes are a bit slower, but more secure than MD5 hashes.
226 /// </param> 226 /// </param>
227 /// <param name="passwordIterations"> 227 /// <param name="passwordIterations">
228 /// Number of iterations used to generate password. One or two iterations 228 /// Number of iterations used to generate password. One or two iterations
229 /// should be enough. 229 /// should be enough.
230 /// </param> 230 /// </param>
231 /// <param name="initVector"> 231 /// <param name="initVector">
232 /// Initialization vector (or IV). This value is required to encrypt the 232 /// Initialization vector (or IV). This value is required to encrypt the
233 /// first block of plaintext data. For RijndaelManaged class IV must be 233 /// first block of plaintext data. For RijndaelManaged class IV must be
234 /// exactly 16 ASCII characters long. 234 /// exactly 16 ASCII characters long.
235 /// </param> 235 /// </param>
236 /// <param name="keySize"> 236 /// <param name="keySize">
237 /// Size of encryption key in bits. Allowed values are: 128, 192, and 256. 237 /// Size of encryption key in bits. Allowed values are: 128, 192, and 256.
238 /// Longer keys are more secure than shorter keys. 238 /// Longer keys are more secure than shorter keys.
239 /// </param> 239 /// </param>
240 /// <returns> 240 /// <returns>
241 /// Decrypted string value. 241 /// Decrypted string value.
242 /// </returns> 242 /// </returns>
243 /// <remarks> 243 /// <remarks>
244 /// Most of the logic in this function is similar to the Encrypt 244 /// Most of the logic in this function is similar to the Encrypt
245 /// logic. In order for decryption to work, all parameters of this function 245 /// logic. In order for decryption to work, all parameters of this function
246 /// - except cipherText value - must match the corresponding parameters of 246 /// - except cipherText value - must match the corresponding parameters of
247 /// the Encrypt function which was called to generate the 247 /// the Encrypt function which was called to generate the
248 /// ciphertext. 248 /// ciphertext.
249 /// </remarks> 249 /// </remarks>
250 public static byte[] Decrypt(byte[] cipherText, 250 public static byte[] Decrypt(byte[] cipherText,
251 string passPhrase, 251 string passPhrase,
252 string saltValue, 252 string saltValue,
253 string hashAlgorithm, 253 string hashAlgorithm,
254 int passwordIterations, 254 int passwordIterations,
255 string initVector, 255 string initVector,
256 int keySize) 256 int keySize)
257 { 257 {
258 // Convert strings defining encryption key characteristics into byte 258 // Convert strings defining encryption key characteristics into byte
259 // arrays. Let us assume that strings only contain ASCII codes. 259 // arrays. Let us assume that strings only contain ASCII codes.
260 // If strings include Unicode characters, use Unicode, UTF7, or UTF8 260 // If strings include Unicode characters, use Unicode, UTF7, or UTF8
261 // encoding. 261 // encoding.
262 byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector); 262 byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
263 byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue); 263 byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue);
264 264
265 // Convert our ciphertext into a byte array. 265 // Convert our ciphertext into a byte array.
266 byte[] cipherTextBytes = cipherText; 266 byte[] cipherTextBytes = cipherText;
267 267
268 // First, we must create a password, from which the key will be 268 // First, we must create a password, from which the key will be
269 // derived. This password will be generated from the specified 269 // derived. This password will be generated from the specified
270 // passphrase and salt value. The password will be created using 270 // passphrase and salt value. The password will be created using
271 // the specified hash algorithm. Password creation can be done in 271 // the specified hash algorithm. Password creation can be done in
272 // several iterations. 272 // several iterations.
273 PasswordDeriveBytes password = new PasswordDeriveBytes( 273 PasswordDeriveBytes password = new PasswordDeriveBytes(
274 passPhrase, 274 passPhrase,
275 saltValueBytes, 275 saltValueBytes,
276 hashAlgorithm, 276 hashAlgorithm,
277 passwordIterations); 277 passwordIterations);
278 278
279 // Use the password to generate pseudo-random bytes for the encryption 279 // Use the password to generate pseudo-random bytes for the encryption
280 // key. Specify the size of the key in bytes (instead of bits). 280 // key. Specify the size of the key in bytes (instead of bits).
281 byte[] keyBytes = password.GetBytes(keySize / 8); 281 byte[] keyBytes = password.GetBytes(keySize / 8);
282 282
283 // Create uninitialized Rijndael encryption object. 283 // Create uninitialized Rijndael encryption object.
284 RijndaelManaged symmetricKey = new RijndaelManaged(); 284 RijndaelManaged symmetricKey = new RijndaelManaged();
285 285
286 // It is reasonable to set encryption mode to Cipher Block Chaining 286 // It is reasonable to set encryption mode to Cipher Block Chaining
287 // (CBC). Use default options for other symmetric key parameters. 287 // (CBC). Use default options for other symmetric key parameters.
288 symmetricKey.Mode = CipherMode.CBC; 288 symmetricKey.Mode = CipherMode.CBC;
289 289
290 // Generate decryptor from the existing key bytes and initialization 290 // Generate decryptor from the existing key bytes and initialization
291 // vector. Key size will be defined based on the number of the key 291 // vector. Key size will be defined based on the number of the key
292 // bytes. 292 // bytes.
293 ICryptoTransform decryptor = symmetricKey.CreateDecryptor( 293 ICryptoTransform decryptor = symmetricKey.CreateDecryptor(
294 keyBytes, 294 keyBytes,
295 initVectorBytes); 295 initVectorBytes);
296 296
297 // Define memory stream which will be used to hold encrypted data. 297 // Define memory stream which will be used to hold encrypted data.
298 MemoryStream memoryStream = new MemoryStream(cipherTextBytes); 298 MemoryStream memoryStream = new MemoryStream(cipherTextBytes);
299 299
300 // Define cryptographic stream (always use Read mode for encryption). 300 // Define cryptographic stream (always use Read mode for encryption).
301 CryptoStream cryptoStream = new CryptoStream(memoryStream, 301 CryptoStream cryptoStream = new CryptoStream(memoryStream,
302 decryptor, 302 decryptor,
303 CryptoStreamMode.Read); 303 CryptoStreamMode.Read);
304 304
305 // Since at this point we don't know what the size of decrypted data 305 // Since at this point we don't know what the size of decrypted data
306 // will be, allocate the buffer long enough to hold ciphertext; 306 // will be, allocate the buffer long enough to hold ciphertext;
307 // plaintext is never longer than ciphertext. 307 // plaintext is never longer than ciphertext.
308 byte[] plainTextBytes = new byte[cipherTextBytes.Length]; 308 byte[] plainTextBytes = new byte[cipherTextBytes.Length];
309 309
310 // Start decrypting. 310 // Start decrypting.
311 int decryptedByteCount = cryptoStream.Read(plainTextBytes, 311 int decryptedByteCount = cryptoStream.Read(plainTextBytes,
312 0, 312 0,
313 plainTextBytes.Length); 313 plainTextBytes.Length);
314 314
315 // Close both streams. 315 // Close both streams.
316 memoryStream.Close(); 316 memoryStream.Close();
317 cryptoStream.Close(); 317 cryptoStream.Close();
318 318
319 byte[] plainText = new byte[decryptedByteCount]; 319 byte[] plainText = new byte[decryptedByteCount];
320 int i; 320 int i;
321 for (i = 0; i < decryptedByteCount; i++) 321 for (i = 0; i < decryptedByteCount; i++)
322 plainText[i] = plainTextBytes[i]; 322 plainText[i] = plainTextBytes[i];
323 323
324 // Return decrypted string. 324 // Return decrypted string.
325 return plainText; 325 return plainText;
326 } 326 }
327 } 327 }
328 #endregion 328 #endregion
329 329
330 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 330 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
331 331
332 private readonly string _assetServerUrl; 332 private readonly string _assetServerUrl;
333 private readonly bool m_encryptOnUpload; 333 private readonly bool m_encryptOnUpload;
334 private readonly RjinKeyfile m_encryptKey; 334 private readonly RjinKeyfile m_encryptKey;
335 private readonly Dictionary<string,RjinKeyfile> m_keyfiles = new Dictionary<string, RjinKeyfile>(); 335 private readonly Dictionary<string,RjinKeyfile> m_keyfiles = new Dictionary<string, RjinKeyfile>();
336 336
337 public CryptoGridAssetClient(string serverUrl, string keydir, bool decOnly) 337 public CryptoGridAssetClient(string serverUrl, string keydir, bool decOnly)
338 { 338 {
339 _assetServerUrl = serverUrl; 339 _assetServerUrl = serverUrl;
340 340
341 string[] keys = Directory.GetFiles(keydir, "*.deckey"); 341 string[] keys = Directory.GetFiles(keydir, "*.deckey");
342 foreach (string key in keys) 342 foreach (string key in keys)
343 { 343 {
344 XmlSerializer xs = new XmlSerializer(typeof (RjinKeyfile)); 344 XmlSerializer xs = new XmlSerializer(typeof (RjinKeyfile));
345 FileStream file = new FileStream(key, FileMode.Open, FileAccess.Read); 345 FileStream file = new FileStream(key, FileMode.Open, FileAccess.Read);
346 346
347 RjinKeyfile rjkey = (RjinKeyfile) xs.Deserialize(file); 347 RjinKeyfile rjkey = (RjinKeyfile) xs.Deserialize(file);
348 348
349 file.Close(); 349 file.Close();
350 350
351 m_keyfiles.Add(rjkey.AlsoKnownAs, rjkey); 351 m_keyfiles.Add(rjkey.AlsoKnownAs, rjkey);
352 } 352 }
353 353
354 354
355 keys = Directory.GetFiles(keydir, "*.enckey"); 355 keys = Directory.GetFiles(keydir, "*.enckey");
356 if (keys.Length == 1) 356 if (keys.Length == 1)
357 { 357 {
358 string Ekey = keys[0]; 358 string Ekey = keys[0];
359 XmlSerializer Exs = new XmlSerializer(typeof (RjinKeyfile)); 359 XmlSerializer Exs = new XmlSerializer(typeof (RjinKeyfile));
360 FileStream Efile = new FileStream(Ekey, FileMode.Open, FileAccess.Read); 360 FileStream Efile = new FileStream(Ekey, FileMode.Open, FileAccess.Read);
361 361
362 RjinKeyfile Erjkey = (RjinKeyfile) Exs.Deserialize(Efile); 362 RjinKeyfile Erjkey = (RjinKeyfile) Exs.Deserialize(Efile);
363 363
364 Efile.Close(); 364 Efile.Close();
365 365
366 m_keyfiles.Add(Erjkey.AlsoKnownAs, Erjkey); 366 m_keyfiles.Add(Erjkey.AlsoKnownAs, Erjkey);
367 367
368 m_encryptKey = Erjkey; 368 m_encryptKey = Erjkey;
369 } else 369 } else
370 { 370 {
371 if (keys.Length > 1) 371 if (keys.Length > 1)
372 throw new Exception( 372 throw new Exception(
373 "You have more than one asset *encryption* key. (You should never have more than one)," + 373 "You have more than one asset *encryption* key. (You should never have more than one)," +
374 "If you downloaded this key from someone, rename it to <filename>.deckey to convert it to" + 374 "If you downloaded this key from someone, rename it to <filename>.deckey to convert it to" +
375 "a decryption-only key."); 375 "a decryption-only key.");
376 376
377 m_log.Warn("No encryption key found, generating a new one for you..."); 377 m_log.Warn("No encryption key found, generating a new one for you...");
378 RjinKeyfile encKey = new RjinKeyfile(); 378 RjinKeyfile encKey = new RjinKeyfile();
379 encKey.GenerateRandom(); 379 encKey.GenerateRandom();
380 380
381 m_encryptKey = encKey; 381 m_encryptKey = encKey;
382 382
383 FileStream encExportFile = new FileStream("mysecretkey_rename_me.enckey",FileMode.CreateNew); 383 FileStream encExportFile = new FileStream("mysecretkey_rename_me.enckey",FileMode.CreateNew);
384 XmlSerializer xs = new XmlSerializer(typeof(RjinKeyfile)); 384 XmlSerializer xs = new XmlSerializer(typeof(RjinKeyfile));
385 xs.Serialize(encExportFile, encKey); 385 xs.Serialize(encExportFile, encKey);
386 encExportFile.Flush(); 386 encExportFile.Flush();
387 encExportFile.Close(); 387 encExportFile.Close();
388 388
389 m_log.Info( 389 m_log.Info(
390 "Encryption file generated, please rename 'mysecretkey_rename_me.enckey' to something more appropriate (however preserve the file extension)."); 390 "Encryption file generated, please rename 'mysecretkey_rename_me.enckey' to something more appropriate (however preserve the file extension).");
391 } 391 }
392 392
393 // If Decrypt-Only, dont encrypt on upload 393 // If Decrypt-Only, dont encrypt on upload
394 m_encryptOnUpload = !decOnly; 394 m_encryptOnUpload = !decOnly;
395 } 395 }
396 396
397 private static void EncryptAssetBase(AssetBase x, RjinKeyfile file) 397 private static void EncryptAssetBase(AssetBase x, RjinKeyfile file)
398 { 398 {
399 // Make a salt 399 // Make a salt
400 RNGCryptoServiceProvider RandomGen = new RNGCryptoServiceProvider(); 400 RNGCryptoServiceProvider RandomGen = new RNGCryptoServiceProvider();
401 byte[] rand = new byte[32]; 401 byte[] rand = new byte[32];
402 RandomGen.GetBytes(rand); 402 RandomGen.GetBytes(rand);
403 403
404 string salt = Convert.ToBase64String(rand); 404 string salt = Convert.ToBase64String(rand);
405 405
406 x.Data = UtilRijndael.Encrypt(x.Data, file.Secret, salt, "SHA1", 2, file.IVBytes, file.Keysize); 406 x.Data = UtilRijndael.Encrypt(x.Data, file.Secret, salt, "SHA1", 2, file.IVBytes, file.Keysize);
407 x.Description = String.Format("ENCASS#:~:#{0}#:~:#{1}#:~:#{2}#:~:#{3}", 407 x.Description = String.Format("ENCASS#:~:#{0}#:~:#{1}#:~:#{2}#:~:#{3}",
408 "OPENSIM_AES_AF1", 408 "OPENSIM_AES_AF1",
409 file.AlsoKnownAs, 409 file.AlsoKnownAs,
410 salt, 410 salt,
411 x.Description); 411 x.Description);
412 } 412 }
413 413
414 private bool DecryptAssetBase(AssetBase x) 414 private bool DecryptAssetBase(AssetBase x)
415 { 415 {
416 // Check it's encrypted first. 416 // Check it's encrypted first.
417 if (!x.Description.Contains("ENCASS")) 417 if (!x.Description.Contains("ENCASS"))
418 return true; 418 return true;
419 419
420 // ENCASS:ALG:AKA:SALT:Description 420 // ENCASS:ALG:AKA:SALT:Description
421 // 0 1 2 3 4 421 // 0 1 2 3 4
422 string[] splitchars = new string[1]; 422 string[] splitchars = new string[1];
423 splitchars[0] = "#:~:#"; 423 splitchars[0] = "#:~:#";
424 424
425 string[] meta = x.Description.Split(splitchars, StringSplitOptions.None); 425 string[] meta = x.Description.Split(splitchars, StringSplitOptions.None);
426 if (meta.Length < 5) 426 if (meta.Length < 5)
427 { 427 {
428 m_log.Warn("[ENCASSETS] Recieved Encrypted Asset, but header is corrupt"); 428 m_log.Warn("[ENCASSETS] Recieved Encrypted Asset, but header is corrupt");
429 return false; 429 return false;
430 } 430 }
431 431
432 // Check if we have a matching key 432 // Check if we have a matching key
433 if (m_keyfiles.ContainsKey(meta[2])) 433 if (m_keyfiles.ContainsKey(meta[2]))
434 { 434 {
435 RjinKeyfile deckey = m_keyfiles[meta[2]]; 435 RjinKeyfile deckey = m_keyfiles[meta[2]];
436 x.Description = meta[4]; 436 x.Description = meta[4];
437 switch (meta[1]) 437 switch (meta[1])
438 { 438 {
439 case "OPENSIM_AES_AF1": 439 case "OPENSIM_AES_AF1":
440 x.Data = UtilRijndael.Decrypt(x.Data, 440 x.Data = UtilRijndael.Decrypt(x.Data,
441 deckey.Secret, 441 deckey.Secret,
442 meta[3], 442 meta[3],
443 "SHA1", 443 "SHA1",
444 2, 444 2,
445 deckey.IVBytes, 445 deckey.IVBytes,
446 deckey.Keysize); 446 deckey.Keysize);
447 // Decrypted Successfully 447 // Decrypted Successfully
448 return true; 448 return true;
449 default: 449 default:
450 m_log.Warn( 450 m_log.Warn(
451 "[ENCASSETS] Recieved Encrypted Asset, but we dont know how to decrypt '" + meta[1] + "'."); 451 "[ENCASSETS] Recieved Encrypted Asset, but we dont know how to decrypt '" + meta[1] + "'.");
452 // We dont understand this encryption scheme 452 // We dont understand this encryption scheme
453 return false; 453 return false;
454 } 454 }
455 } 455 }
456 456
457 m_log.Warn("[ENCASSETS] Recieved Encrypted Asset, but we do not have the decryption key."); 457 m_log.Warn("[ENCASSETS] Recieved Encrypted Asset, but we do not have the decryption key.");
458 return false; 458 return false;
459 } 459 }
460 460
461 #region IAssetServer Members 461 #region IAssetServer Members
462 462
463 protected override AssetBase GetAsset(AssetRequest req) 463 protected override AssetBase GetAsset(AssetRequest req)
464 { 464 {
465#if DEBUG 465#if DEBUG
466 //m_log.DebugFormat("[GRID ASSET CLIENT]: Querying for {0}", req.AssetID.ToString()); 466 //m_log.DebugFormat("[GRID ASSET CLIENT]: Querying for {0}", req.AssetID.ToString());
467#endif 467#endif
468 468
469 RestClient rc = new RestClient(_assetServerUrl); 469 RestClient rc = new RestClient(_assetServerUrl);
470 rc.AddResourcePath("assets"); 470 rc.AddResourcePath("assets");
471 rc.AddResourcePath(req.AssetID.ToString()); 471 rc.AddResourcePath(req.AssetID.ToString());
472 if (req.IsTexture) 472 if (req.IsTexture)
473 rc.AddQueryParameter("texture"); 473 rc.AddQueryParameter("texture");
474 474
475 rc.RequestMethod = "GET"; 475 rc.RequestMethod = "GET";
476 476
477 Stream s = rc.Request(); 477 Stream s = rc.Request();
478 478
479 if (s == null) 479 if (s == null)
480 return null; 480 return null;
481 481
482 if (s.Length > 0) 482 if (s.Length > 0)
483 { 483 {
484 XmlSerializer xs = new XmlSerializer(typeof(AssetBase)); 484 XmlSerializer xs = new XmlSerializer(typeof(AssetBase));
485 485
486 AssetBase encAsset = (AssetBase)xs.Deserialize(s); 486 AssetBase encAsset = (AssetBase)xs.Deserialize(s);
487 487
488 // Try decrypt it 488 // Try decrypt it
489 if (DecryptAssetBase(encAsset)) 489 if (DecryptAssetBase(encAsset))
490 return encAsset; 490 return encAsset;
491 } 491 }
492 492
493 return null; 493 return null;
494 } 494 }
495 495
496 public override void UpdateAsset(AssetBase asset) 496 public override void UpdateAsset(AssetBase asset)
497 { 497 {
498 throw new Exception("The method or operation is not implemented."); 498 throw new Exception("The method or operation is not implemented.");
499 } 499 }
500 500
501 public override void StoreAsset(AssetBase asset) 501 public override void StoreAsset(AssetBase asset)
502 { 502 {
503 if (m_encryptOnUpload) 503 if (m_encryptOnUpload)
504 EncryptAssetBase(asset, m_encryptKey); 504 EncryptAssetBase(asset, m_encryptKey);
505 505
506 try 506 try
507 { 507 {
508 string assetUrl = _assetServerUrl + "/assets/"; 508 string assetUrl = _assetServerUrl + "/assets/";
509 509
510 m_log.InfoFormat("[CRYPTO GRID ASSET CLIENT]: Sending store request for asset {0}", asset.FullID); 510 m_log.InfoFormat("[CRYPTO GRID ASSET CLIENT]: Sending store request for asset {0}", asset.FullID);
511 511
512 RestObjectPoster.BeginPostObject<AssetBase>(assetUrl, asset); 512 RestObjectPoster.BeginPostObject<AssetBase>(assetUrl, asset);
513 } 513 }
514 catch (Exception e) 514 catch (Exception e)
515 { 515 {
516 m_log.ErrorFormat("[CRYPTO GRID ASSET CLIENT]: {0}", e); 516 m_log.ErrorFormat("[CRYPTO GRID ASSET CLIENT]: {0}", e);
517 } 517 }
518 } 518 }
519 519
520 public override void Close() 520 public override void Close()
521 { 521 {
522 throw new Exception("The method or operation is not implemented."); 522 throw new Exception("The method or operation is not implemented.");
523 } 523 }
524 524
525 #endregion 525 #endregion
526 } 526 }
527} 527}