From 7f721ae20c9d948a67a09c72eb76b3fbede69220 Mon Sep 17 00:00:00 2001
From: Sean Dague
Date: Thu, 16 Oct 2008 15:58:07 +0000
Subject: fix line endings, as apparently the bot didn't do this yet
---
.../Communications/Cache/CryptoGridAssetClient.cs | 1054 ++++++++++----------
1 file changed, 527 insertions(+), 527 deletions(-)
(limited to 'OpenSim/Framework/Communications/Cache/CryptoGridAssetClient.cs')
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 @@
-/*
- * Copyright (c) Contributors, http://www.openmetaverse.org/
- * See CONTRIBUTORS.TXT for a full list of copyright holders.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of the OpenSim Project nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-/*
- * This file includes content derived from Obviex.
- * Copyright (C) 2002 Obviex(TM). All rights reserved.
- * http://www.obviex.com/samples/Encryption.aspx
- */
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Reflection;
-using System.Text;
-using System.Xml.Serialization;
-using log4net;
-using OpenSim.Framework.Servers;
-using System.Security.Cryptography;
-
-namespace OpenSim.Framework.Communications.Cache
-{
- public class CryptoGridAssetClient : AssetServerBase
- {
- #region Keyfile Classes
- [Serializable]
- private class RjinKeyfile
- {
- public string Secret;
- public string AlsoKnownAs;
- public int Keysize;
- public string IVBytes;
- public string Description = "OpenSim Key";
-
- private static string SHA1Hash(byte[] bytes)
- {
- SHA1 sha1 = SHA1CryptoServiceProvider.Create();
- byte[] dataMd5 = sha1.ComputeHash(bytes);
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < dataMd5.Length; i++)
- sb.AppendFormat("{0:x2}", dataMd5[i]);
- return sb.ToString();
- }
-
- public void GenerateRandom()
- {
- RNGCryptoServiceProvider Gen = new RNGCryptoServiceProvider();
-
- byte[] genSec = new byte[32];
- byte[] genAKA = new byte[32];
- byte[] genIV = new byte[32];
-
- Gen.GetBytes(genSec);
- Gen.GetBytes(genAKA);
- Gen.GetBytes(genIV);
-
- Secret = SHA1Hash(genSec);
- AlsoKnownAs = SHA1Hash(genAKA);
- IVBytes = SHA1Hash(genIV).Substring(0, 16);
- Keysize = 256;
- }
- }
- #endregion
-
- #region Rjindael
- ///
- /// This class uses a symmetric key algorithm (Rijndael/AES) to encrypt and
- /// decrypt data. As long as encryption and decryption routines use the same
- /// parameters to generate the keys, the keys are guaranteed to be the same.
- /// The class uses static functions with duplicate code to make it easier to
- /// demonstrate encryption and decryption logic. In a real-life application,
- /// this may not be the most efficient way of handling encryption, so - as
- /// soon as you feel comfortable with it - you may want to redesign this class.
- ///
- private class UtilRijndael
- {
- ///
- /// Encrypts specified plaintext using Rijndael symmetric key algorithm
- /// and returns a base64-encoded result.
- ///
- ///
- /// Plaintext value to be encrypted.
- ///
- ///
- /// Passphrase from which a pseudo-random password will be derived. The
- /// derived password will be used to generate the encryption key.
- /// Passphrase can be any string. In this example we assume that this
- /// passphrase is an ASCII string.
- ///
- ///
- /// Salt value used along with passphrase to generate password. Salt can
- /// be any string. In this example we assume that salt is an ASCII string.
- ///
- ///
- /// Hash algorithm used to generate password. Allowed values are: "MD5" and
- /// "SHA1". SHA1 hashes are a bit slower, but more secure than MD5 hashes.
- ///
- ///
- /// Number of iterations used to generate password. One or two iterations
- /// should be enough.
- ///
- ///
- /// Initialization vector (or IV). This value is required to encrypt the
- /// first block of plaintext data. For RijndaelManaged class IV must be
- /// exactly 16 ASCII characters long.
- ///
- ///
- /// Size of encryption key in bits. Allowed values are: 128, 192, and 256.
- /// Longer keys are more secure than shorter keys.
- ///
- ///
- /// Encrypted value formatted as a base64-encoded string.
- ///
- public static byte[] Encrypt(byte[] plainText,
- string passPhrase,
- string saltValue,
- string hashAlgorithm,
- int passwordIterations,
- string initVector,
- int keySize)
- {
- // Convert strings into byte arrays.
- // Let us assume that strings only contain ASCII codes.
- // If strings include Unicode characters, use Unicode, UTF7, or UTF8
- // encoding.
- byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
- byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue);
-
- // Convert our plaintext into a byte array.
- // Let us assume that plaintext contains UTF8-encoded characters.
- byte[] plainTextBytes = plainText;
-
- // First, we must create a password, from which the key will be derived.
- // This password will be generated from the specified passphrase and
- // salt value. The password will be created using the specified hash
- // algorithm. Password creation can be done in several iterations.
- PasswordDeriveBytes password = new PasswordDeriveBytes(
- passPhrase,
- saltValueBytes,
- hashAlgorithm,
- passwordIterations);
-
- // Use the password to generate pseudo-random bytes for the encryption
- // key. Specify the size of the key in bytes (instead of bits).
- byte[] keyBytes = password.GetBytes(keySize / 8);
-
- // Create uninitialized Rijndael encryption object.
- RijndaelManaged symmetricKey = new RijndaelManaged();
-
- // It is reasonable to set encryption mode to Cipher Block Chaining
- // (CBC). Use default options for other symmetric key parameters.
- symmetricKey.Mode = CipherMode.CBC;
-
- // Generate encryptor from the existing key bytes and initialization
- // vector. Key size will be defined based on the number of the key
- // bytes.
- ICryptoTransform encryptor = symmetricKey.CreateEncryptor(
- keyBytes,
- initVectorBytes);
-
- // Define memory stream which will be used to hold encrypted data.
- MemoryStream memoryStream = new MemoryStream();
-
- // Define cryptographic stream (always use Write mode for encryption).
- CryptoStream cryptoStream = new CryptoStream(memoryStream,
- encryptor,
- CryptoStreamMode.Write);
- // Start encrypting.
- cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
-
- // Finish encrypting.
- cryptoStream.FlushFinalBlock();
-
- // Convert our encrypted data from a memory stream into a byte array.
- byte[] cipherTextBytes = memoryStream.ToArray();
-
- // Close both streams.
- memoryStream.Close();
- cryptoStream.Close();
-
- // Return encrypted string.
- return cipherTextBytes;
- }
-
- ///
- /// Decrypts specified ciphertext using Rijndael symmetric key algorithm.
- ///
- ///
- /// Base64-formatted ciphertext value.
- ///
- ///
- /// Passphrase from which a pseudo-random password will be derived. The
- /// derived password will be used to generate the encryption key.
- /// Passphrase can be any string. In this example we assume that this
- /// passphrase is an ASCII string.
- ///
- ///
- /// Salt value used along with passphrase to generate password. Salt can
- /// be any string. In this example we assume that salt is an ASCII string.
- ///
- ///
- /// Hash algorithm used to generate password. Allowed values are: "MD5" and
- /// "SHA1". SHA1 hashes are a bit slower, but more secure than MD5 hashes.
- ///
- ///
- /// Number of iterations used to generate password. One or two iterations
- /// should be enough.
- ///
- ///
- /// Initialization vector (or IV). This value is required to encrypt the
- /// first block of plaintext data. For RijndaelManaged class IV must be
- /// exactly 16 ASCII characters long.
- ///
- ///
- /// Size of encryption key in bits. Allowed values are: 128, 192, and 256.
- /// Longer keys are more secure than shorter keys.
- ///
- ///
- /// Decrypted string value.
- ///
- ///
- /// Most of the logic in this function is similar to the Encrypt
- /// logic. In order for decryption to work, all parameters of this function
- /// - except cipherText value - must match the corresponding parameters of
- /// the Encrypt function which was called to generate the
- /// ciphertext.
- ///
- public static byte[] Decrypt(byte[] cipherText,
- string passPhrase,
- string saltValue,
- string hashAlgorithm,
- int passwordIterations,
- string initVector,
- int keySize)
- {
- // Convert strings defining encryption key characteristics into byte
- // arrays. Let us assume that strings only contain ASCII codes.
- // If strings include Unicode characters, use Unicode, UTF7, or UTF8
- // encoding.
- byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
- byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue);
-
- // Convert our ciphertext into a byte array.
- byte[] cipherTextBytes = cipherText;
-
- // First, we must create a password, from which the key will be
- // derived. This password will be generated from the specified
- // passphrase and salt value. The password will be created using
- // the specified hash algorithm. Password creation can be done in
- // several iterations.
- PasswordDeriveBytes password = new PasswordDeriveBytes(
- passPhrase,
- saltValueBytes,
- hashAlgorithm,
- passwordIterations);
-
- // Use the password to generate pseudo-random bytes for the encryption
- // key. Specify the size of the key in bytes (instead of bits).
- byte[] keyBytes = password.GetBytes(keySize / 8);
-
- // Create uninitialized Rijndael encryption object.
- RijndaelManaged symmetricKey = new RijndaelManaged();
-
- // It is reasonable to set encryption mode to Cipher Block Chaining
- // (CBC). Use default options for other symmetric key parameters.
- symmetricKey.Mode = CipherMode.CBC;
-
- // Generate decryptor from the existing key bytes and initialization
- // vector. Key size will be defined based on the number of the key
- // bytes.
- ICryptoTransform decryptor = symmetricKey.CreateDecryptor(
- keyBytes,
- initVectorBytes);
-
- // Define memory stream which will be used to hold encrypted data.
- MemoryStream memoryStream = new MemoryStream(cipherTextBytes);
-
- // Define cryptographic stream (always use Read mode for encryption).
- CryptoStream cryptoStream = new CryptoStream(memoryStream,
- decryptor,
- CryptoStreamMode.Read);
-
- // Since at this point we don't know what the size of decrypted data
- // will be, allocate the buffer long enough to hold ciphertext;
- // plaintext is never longer than ciphertext.
- byte[] plainTextBytes = new byte[cipherTextBytes.Length];
-
- // Start decrypting.
- int decryptedByteCount = cryptoStream.Read(plainTextBytes,
- 0,
- plainTextBytes.Length);
-
- // Close both streams.
- memoryStream.Close();
- cryptoStream.Close();
-
- byte[] plainText = new byte[decryptedByteCount];
- int i;
- for (i = 0; i < decryptedByteCount; i++)
- plainText[i] = plainTextBytes[i];
-
- // Return decrypted string.
- return plainText;
- }
- }
- #endregion
-
- private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
-
- private readonly string _assetServerUrl;
- private readonly bool m_encryptOnUpload;
- private readonly RjinKeyfile m_encryptKey;
- private readonly Dictionary m_keyfiles = new Dictionary();
-
- public CryptoGridAssetClient(string serverUrl, string keydir, bool decOnly)
- {
- _assetServerUrl = serverUrl;
-
- string[] keys = Directory.GetFiles(keydir, "*.deckey");
- foreach (string key in keys)
- {
- XmlSerializer xs = new XmlSerializer(typeof (RjinKeyfile));
- FileStream file = new FileStream(key, FileMode.Open, FileAccess.Read);
-
- RjinKeyfile rjkey = (RjinKeyfile) xs.Deserialize(file);
-
- file.Close();
-
- m_keyfiles.Add(rjkey.AlsoKnownAs, rjkey);
- }
-
-
- keys = Directory.GetFiles(keydir, "*.enckey");
- if (keys.Length == 1)
- {
- string Ekey = keys[0];
- XmlSerializer Exs = new XmlSerializer(typeof (RjinKeyfile));
- FileStream Efile = new FileStream(Ekey, FileMode.Open, FileAccess.Read);
-
- RjinKeyfile Erjkey = (RjinKeyfile) Exs.Deserialize(Efile);
-
- Efile.Close();
-
- m_keyfiles.Add(Erjkey.AlsoKnownAs, Erjkey);
-
- m_encryptKey = Erjkey;
- } else
- {
- if (keys.Length > 1)
- throw new Exception(
- "You have more than one asset *encryption* key. (You should never have more than one)," +
- "If you downloaded this key from someone, rename it to .deckey to convert it to" +
- "a decryption-only key.");
-
- m_log.Warn("No encryption key found, generating a new one for you...");
- RjinKeyfile encKey = new RjinKeyfile();
- encKey.GenerateRandom();
-
- m_encryptKey = encKey;
-
- FileStream encExportFile = new FileStream("mysecretkey_rename_me.enckey",FileMode.CreateNew);
- XmlSerializer xs = new XmlSerializer(typeof(RjinKeyfile));
- xs.Serialize(encExportFile, encKey);
- encExportFile.Flush();
- encExportFile.Close();
-
- m_log.Info(
- "Encryption file generated, please rename 'mysecretkey_rename_me.enckey' to something more appropriate (however preserve the file extension).");
- }
-
- // If Decrypt-Only, dont encrypt on upload
- m_encryptOnUpload = !decOnly;
- }
-
- private static void EncryptAssetBase(AssetBase x, RjinKeyfile file)
- {
- // Make a salt
- RNGCryptoServiceProvider RandomGen = new RNGCryptoServiceProvider();
- byte[] rand = new byte[32];
- RandomGen.GetBytes(rand);
-
- string salt = Convert.ToBase64String(rand);
-
- x.Data = UtilRijndael.Encrypt(x.Data, file.Secret, salt, "SHA1", 2, file.IVBytes, file.Keysize);
- x.Description = String.Format("ENCASS#:~:#{0}#:~:#{1}#:~:#{2}#:~:#{3}",
- "OPENSIM_AES_AF1",
- file.AlsoKnownAs,
- salt,
- x.Description);
- }
-
- private bool DecryptAssetBase(AssetBase x)
- {
- // Check it's encrypted first.
- if (!x.Description.Contains("ENCASS"))
- return true;
-
- // ENCASS:ALG:AKA:SALT:Description
- // 0 1 2 3 4
- string[] splitchars = new string[1];
- splitchars[0] = "#:~:#";
-
- string[] meta = x.Description.Split(splitchars, StringSplitOptions.None);
- if (meta.Length < 5)
- {
- m_log.Warn("[ENCASSETS] Recieved Encrypted Asset, but header is corrupt");
- return false;
- }
-
- // Check if we have a matching key
- if (m_keyfiles.ContainsKey(meta[2]))
- {
- RjinKeyfile deckey = m_keyfiles[meta[2]];
- x.Description = meta[4];
- switch (meta[1])
- {
- case "OPENSIM_AES_AF1":
- x.Data = UtilRijndael.Decrypt(x.Data,
- deckey.Secret,
- meta[3],
- "SHA1",
- 2,
- deckey.IVBytes,
- deckey.Keysize);
- // Decrypted Successfully
- return true;
- default:
- m_log.Warn(
- "[ENCASSETS] Recieved Encrypted Asset, but we dont know how to decrypt '" + meta[1] + "'.");
- // We dont understand this encryption scheme
- return false;
- }
- }
-
- m_log.Warn("[ENCASSETS] Recieved Encrypted Asset, but we do not have the decryption key.");
- return false;
- }
-
- #region IAssetServer Members
-
- protected override AssetBase GetAsset(AssetRequest req)
- {
-#if DEBUG
- //m_log.DebugFormat("[GRID ASSET CLIENT]: Querying for {0}", req.AssetID.ToString());
-#endif
-
- RestClient rc = new RestClient(_assetServerUrl);
- rc.AddResourcePath("assets");
- rc.AddResourcePath(req.AssetID.ToString());
- if (req.IsTexture)
- rc.AddQueryParameter("texture");
-
- rc.RequestMethod = "GET";
-
- Stream s = rc.Request();
-
- if (s == null)
- return null;
-
- if (s.Length > 0)
- {
- XmlSerializer xs = new XmlSerializer(typeof(AssetBase));
-
- AssetBase encAsset = (AssetBase)xs.Deserialize(s);
-
- // Try decrypt it
- if (DecryptAssetBase(encAsset))
- return encAsset;
- }
-
- return null;
- }
-
- public override void UpdateAsset(AssetBase asset)
- {
- throw new Exception("The method or operation is not implemented.");
- }
-
- public override void StoreAsset(AssetBase asset)
- {
- if (m_encryptOnUpload)
- EncryptAssetBase(asset, m_encryptKey);
-
- try
- {
- string assetUrl = _assetServerUrl + "/assets/";
-
- m_log.InfoFormat("[CRYPTO GRID ASSET CLIENT]: Sending store request for asset {0}", asset.FullID);
-
- RestObjectPoster.BeginPostObject(assetUrl, asset);
- }
- catch (Exception e)
- {
- m_log.ErrorFormat("[CRYPTO GRID ASSET CLIENT]: {0}", e);
- }
- }
-
- public override void Close()
- {
- throw new Exception("The method or operation is not implemented.");
- }
-
- #endregion
- }
-}
+/*
+ * Copyright (c) Contributors, http://www.openmetaverse.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSim Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * This file includes content derived from Obviex.
+ * Copyright (C) 2002 Obviex(TM). All rights reserved.
+ * http://www.obviex.com/samples/Encryption.aspx
+ */
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Text;
+using System.Xml.Serialization;
+using log4net;
+using OpenSim.Framework.Servers;
+using System.Security.Cryptography;
+
+namespace OpenSim.Framework.Communications.Cache
+{
+ public class CryptoGridAssetClient : AssetServerBase
+ {
+ #region Keyfile Classes
+ [Serializable]
+ private class RjinKeyfile
+ {
+ public string Secret;
+ public string AlsoKnownAs;
+ public int Keysize;
+ public string IVBytes;
+ public string Description = "OpenSim Key";
+
+ private static string SHA1Hash(byte[] bytes)
+ {
+ SHA1 sha1 = SHA1CryptoServiceProvider.Create();
+ byte[] dataMd5 = sha1.ComputeHash(bytes);
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < dataMd5.Length; i++)
+ sb.AppendFormat("{0:x2}", dataMd5[i]);
+ return sb.ToString();
+ }
+
+ public void GenerateRandom()
+ {
+ RNGCryptoServiceProvider Gen = new RNGCryptoServiceProvider();
+
+ byte[] genSec = new byte[32];
+ byte[] genAKA = new byte[32];
+ byte[] genIV = new byte[32];
+
+ Gen.GetBytes(genSec);
+ Gen.GetBytes(genAKA);
+ Gen.GetBytes(genIV);
+
+ Secret = SHA1Hash(genSec);
+ AlsoKnownAs = SHA1Hash(genAKA);
+ IVBytes = SHA1Hash(genIV).Substring(0, 16);
+ Keysize = 256;
+ }
+ }
+ #endregion
+
+ #region Rjindael
+ ///
+ /// This class uses a symmetric key algorithm (Rijndael/AES) to encrypt and
+ /// decrypt data. As long as encryption and decryption routines use the same
+ /// parameters to generate the keys, the keys are guaranteed to be the same.
+ /// The class uses static functions with duplicate code to make it easier to
+ /// demonstrate encryption and decryption logic. In a real-life application,
+ /// this may not be the most efficient way of handling encryption, so - as
+ /// soon as you feel comfortable with it - you may want to redesign this class.
+ ///
+ private class UtilRijndael
+ {
+ ///
+ /// Encrypts specified plaintext using Rijndael symmetric key algorithm
+ /// and returns a base64-encoded result.
+ ///
+ ///
+ /// Plaintext value to be encrypted.
+ ///
+ ///
+ /// Passphrase from which a pseudo-random password will be derived. The
+ /// derived password will be used to generate the encryption key.
+ /// Passphrase can be any string. In this example we assume that this
+ /// passphrase is an ASCII string.
+ ///
+ ///
+ /// Salt value used along with passphrase to generate password. Salt can
+ /// be any string. In this example we assume that salt is an ASCII string.
+ ///
+ ///
+ /// Hash algorithm used to generate password. Allowed values are: "MD5" and
+ /// "SHA1". SHA1 hashes are a bit slower, but more secure than MD5 hashes.
+ ///
+ ///
+ /// Number of iterations used to generate password. One or two iterations
+ /// should be enough.
+ ///
+ ///
+ /// Initialization vector (or IV). This value is required to encrypt the
+ /// first block of plaintext data. For RijndaelManaged class IV must be
+ /// exactly 16 ASCII characters long.
+ ///
+ ///
+ /// Size of encryption key in bits. Allowed values are: 128, 192, and 256.
+ /// Longer keys are more secure than shorter keys.
+ ///
+ ///
+ /// Encrypted value formatted as a base64-encoded string.
+ ///
+ public static byte[] Encrypt(byte[] plainText,
+ string passPhrase,
+ string saltValue,
+ string hashAlgorithm,
+ int passwordIterations,
+ string initVector,
+ int keySize)
+ {
+ // Convert strings into byte arrays.
+ // Let us assume that strings only contain ASCII codes.
+ // If strings include Unicode characters, use Unicode, UTF7, or UTF8
+ // encoding.
+ byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
+ byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue);
+
+ // Convert our plaintext into a byte array.
+ // Let us assume that plaintext contains UTF8-encoded characters.
+ byte[] plainTextBytes = plainText;
+
+ // First, we must create a password, from which the key will be derived.
+ // This password will be generated from the specified passphrase and
+ // salt value. The password will be created using the specified hash
+ // algorithm. Password creation can be done in several iterations.
+ PasswordDeriveBytes password = new PasswordDeriveBytes(
+ passPhrase,
+ saltValueBytes,
+ hashAlgorithm,
+ passwordIterations);
+
+ // Use the password to generate pseudo-random bytes for the encryption
+ // key. Specify the size of the key in bytes (instead of bits).
+ byte[] keyBytes = password.GetBytes(keySize / 8);
+
+ // Create uninitialized Rijndael encryption object.
+ RijndaelManaged symmetricKey = new RijndaelManaged();
+
+ // It is reasonable to set encryption mode to Cipher Block Chaining
+ // (CBC). Use default options for other symmetric key parameters.
+ symmetricKey.Mode = CipherMode.CBC;
+
+ // Generate encryptor from the existing key bytes and initialization
+ // vector. Key size will be defined based on the number of the key
+ // bytes.
+ ICryptoTransform encryptor = symmetricKey.CreateEncryptor(
+ keyBytes,
+ initVectorBytes);
+
+ // Define memory stream which will be used to hold encrypted data.
+ MemoryStream memoryStream = new MemoryStream();
+
+ // Define cryptographic stream (always use Write mode for encryption).
+ CryptoStream cryptoStream = new CryptoStream(memoryStream,
+ encryptor,
+ CryptoStreamMode.Write);
+ // Start encrypting.
+ cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
+
+ // Finish encrypting.
+ cryptoStream.FlushFinalBlock();
+
+ // Convert our encrypted data from a memory stream into a byte array.
+ byte[] cipherTextBytes = memoryStream.ToArray();
+
+ // Close both streams.
+ memoryStream.Close();
+ cryptoStream.Close();
+
+ // Return encrypted string.
+ return cipherTextBytes;
+ }
+
+ ///
+ /// Decrypts specified ciphertext using Rijndael symmetric key algorithm.
+ ///
+ ///
+ /// Base64-formatted ciphertext value.
+ ///
+ ///
+ /// Passphrase from which a pseudo-random password will be derived. The
+ /// derived password will be used to generate the encryption key.
+ /// Passphrase can be any string. In this example we assume that this
+ /// passphrase is an ASCII string.
+ ///
+ ///
+ /// Salt value used along with passphrase to generate password. Salt can
+ /// be any string. In this example we assume that salt is an ASCII string.
+ ///
+ ///
+ /// Hash algorithm used to generate password. Allowed values are: "MD5" and
+ /// "SHA1". SHA1 hashes are a bit slower, but more secure than MD5 hashes.
+ ///
+ ///
+ /// Number of iterations used to generate password. One or two iterations
+ /// should be enough.
+ ///
+ ///
+ /// Initialization vector (or IV). This value is required to encrypt the
+ /// first block of plaintext data. For RijndaelManaged class IV must be
+ /// exactly 16 ASCII characters long.
+ ///
+ ///
+ /// Size of encryption key in bits. Allowed values are: 128, 192, and 256.
+ /// Longer keys are more secure than shorter keys.
+ ///
+ ///
+ /// Decrypted string value.
+ ///
+ ///
+ /// Most of the logic in this function is similar to the Encrypt
+ /// logic. In order for decryption to work, all parameters of this function
+ /// - except cipherText value - must match the corresponding parameters of
+ /// the Encrypt function which was called to generate the
+ /// ciphertext.
+ ///
+ public static byte[] Decrypt(byte[] cipherText,
+ string passPhrase,
+ string saltValue,
+ string hashAlgorithm,
+ int passwordIterations,
+ string initVector,
+ int keySize)
+ {
+ // Convert strings defining encryption key characteristics into byte
+ // arrays. Let us assume that strings only contain ASCII codes.
+ // If strings include Unicode characters, use Unicode, UTF7, or UTF8
+ // encoding.
+ byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
+ byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue);
+
+ // Convert our ciphertext into a byte array.
+ byte[] cipherTextBytes = cipherText;
+
+ // First, we must create a password, from which the key will be
+ // derived. This password will be generated from the specified
+ // passphrase and salt value. The password will be created using
+ // the specified hash algorithm. Password creation can be done in
+ // several iterations.
+ PasswordDeriveBytes password = new PasswordDeriveBytes(
+ passPhrase,
+ saltValueBytes,
+ hashAlgorithm,
+ passwordIterations);
+
+ // Use the password to generate pseudo-random bytes for the encryption
+ // key. Specify the size of the key in bytes (instead of bits).
+ byte[] keyBytes = password.GetBytes(keySize / 8);
+
+ // Create uninitialized Rijndael encryption object.
+ RijndaelManaged symmetricKey = new RijndaelManaged();
+
+ // It is reasonable to set encryption mode to Cipher Block Chaining
+ // (CBC). Use default options for other symmetric key parameters.
+ symmetricKey.Mode = CipherMode.CBC;
+
+ // Generate decryptor from the existing key bytes and initialization
+ // vector. Key size will be defined based on the number of the key
+ // bytes.
+ ICryptoTransform decryptor = symmetricKey.CreateDecryptor(
+ keyBytes,
+ initVectorBytes);
+
+ // Define memory stream which will be used to hold encrypted data.
+ MemoryStream memoryStream = new MemoryStream(cipherTextBytes);
+
+ // Define cryptographic stream (always use Read mode for encryption).
+ CryptoStream cryptoStream = new CryptoStream(memoryStream,
+ decryptor,
+ CryptoStreamMode.Read);
+
+ // Since at this point we don't know what the size of decrypted data
+ // will be, allocate the buffer long enough to hold ciphertext;
+ // plaintext is never longer than ciphertext.
+ byte[] plainTextBytes = new byte[cipherTextBytes.Length];
+
+ // Start decrypting.
+ int decryptedByteCount = cryptoStream.Read(plainTextBytes,
+ 0,
+ plainTextBytes.Length);
+
+ // Close both streams.
+ memoryStream.Close();
+ cryptoStream.Close();
+
+ byte[] plainText = new byte[decryptedByteCount];
+ int i;
+ for (i = 0; i < decryptedByteCount; i++)
+ plainText[i] = plainTextBytes[i];
+
+ // Return decrypted string.
+ return plainText;
+ }
+ }
+ #endregion
+
+ private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
+ private readonly string _assetServerUrl;
+ private readonly bool m_encryptOnUpload;
+ private readonly RjinKeyfile m_encryptKey;
+ private readonly Dictionary m_keyfiles = new Dictionary();
+
+ public CryptoGridAssetClient(string serverUrl, string keydir, bool decOnly)
+ {
+ _assetServerUrl = serverUrl;
+
+ string[] keys = Directory.GetFiles(keydir, "*.deckey");
+ foreach (string key in keys)
+ {
+ XmlSerializer xs = new XmlSerializer(typeof (RjinKeyfile));
+ FileStream file = new FileStream(key, FileMode.Open, FileAccess.Read);
+
+ RjinKeyfile rjkey = (RjinKeyfile) xs.Deserialize(file);
+
+ file.Close();
+
+ m_keyfiles.Add(rjkey.AlsoKnownAs, rjkey);
+ }
+
+
+ keys = Directory.GetFiles(keydir, "*.enckey");
+ if (keys.Length == 1)
+ {
+ string Ekey = keys[0];
+ XmlSerializer Exs = new XmlSerializer(typeof (RjinKeyfile));
+ FileStream Efile = new FileStream(Ekey, FileMode.Open, FileAccess.Read);
+
+ RjinKeyfile Erjkey = (RjinKeyfile) Exs.Deserialize(Efile);
+
+ Efile.Close();
+
+ m_keyfiles.Add(Erjkey.AlsoKnownAs, Erjkey);
+
+ m_encryptKey = Erjkey;
+ } else
+ {
+ if (keys.Length > 1)
+ throw new Exception(
+ "You have more than one asset *encryption* key. (You should never have more than one)," +
+ "If you downloaded this key from someone, rename it to .deckey to convert it to" +
+ "a decryption-only key.");
+
+ m_log.Warn("No encryption key found, generating a new one for you...");
+ RjinKeyfile encKey = new RjinKeyfile();
+ encKey.GenerateRandom();
+
+ m_encryptKey = encKey;
+
+ FileStream encExportFile = new FileStream("mysecretkey_rename_me.enckey",FileMode.CreateNew);
+ XmlSerializer xs = new XmlSerializer(typeof(RjinKeyfile));
+ xs.Serialize(encExportFile, encKey);
+ encExportFile.Flush();
+ encExportFile.Close();
+
+ m_log.Info(
+ "Encryption file generated, please rename 'mysecretkey_rename_me.enckey' to something more appropriate (however preserve the file extension).");
+ }
+
+ // If Decrypt-Only, dont encrypt on upload
+ m_encryptOnUpload = !decOnly;
+ }
+
+ private static void EncryptAssetBase(AssetBase x, RjinKeyfile file)
+ {
+ // Make a salt
+ RNGCryptoServiceProvider RandomGen = new RNGCryptoServiceProvider();
+ byte[] rand = new byte[32];
+ RandomGen.GetBytes(rand);
+
+ string salt = Convert.ToBase64String(rand);
+
+ x.Data = UtilRijndael.Encrypt(x.Data, file.Secret, salt, "SHA1", 2, file.IVBytes, file.Keysize);
+ x.Description = String.Format("ENCASS#:~:#{0}#:~:#{1}#:~:#{2}#:~:#{3}",
+ "OPENSIM_AES_AF1",
+ file.AlsoKnownAs,
+ salt,
+ x.Description);
+ }
+
+ private bool DecryptAssetBase(AssetBase x)
+ {
+ // Check it's encrypted first.
+ if (!x.Description.Contains("ENCASS"))
+ return true;
+
+ // ENCASS:ALG:AKA:SALT:Description
+ // 0 1 2 3 4
+ string[] splitchars = new string[1];
+ splitchars[0] = "#:~:#";
+
+ string[] meta = x.Description.Split(splitchars, StringSplitOptions.None);
+ if (meta.Length < 5)
+ {
+ m_log.Warn("[ENCASSETS] Recieved Encrypted Asset, but header is corrupt");
+ return false;
+ }
+
+ // Check if we have a matching key
+ if (m_keyfiles.ContainsKey(meta[2]))
+ {
+ RjinKeyfile deckey = m_keyfiles[meta[2]];
+ x.Description = meta[4];
+ switch (meta[1])
+ {
+ case "OPENSIM_AES_AF1":
+ x.Data = UtilRijndael.Decrypt(x.Data,
+ deckey.Secret,
+ meta[3],
+ "SHA1",
+ 2,
+ deckey.IVBytes,
+ deckey.Keysize);
+ // Decrypted Successfully
+ return true;
+ default:
+ m_log.Warn(
+ "[ENCASSETS] Recieved Encrypted Asset, but we dont know how to decrypt '" + meta[1] + "'.");
+ // We dont understand this encryption scheme
+ return false;
+ }
+ }
+
+ m_log.Warn("[ENCASSETS] Recieved Encrypted Asset, but we do not have the decryption key.");
+ return false;
+ }
+
+ #region IAssetServer Members
+
+ protected override AssetBase GetAsset(AssetRequest req)
+ {
+#if DEBUG
+ //m_log.DebugFormat("[GRID ASSET CLIENT]: Querying for {0}", req.AssetID.ToString());
+#endif
+
+ RestClient rc = new RestClient(_assetServerUrl);
+ rc.AddResourcePath("assets");
+ rc.AddResourcePath(req.AssetID.ToString());
+ if (req.IsTexture)
+ rc.AddQueryParameter("texture");
+
+ rc.RequestMethod = "GET";
+
+ Stream s = rc.Request();
+
+ if (s == null)
+ return null;
+
+ if (s.Length > 0)
+ {
+ XmlSerializer xs = new XmlSerializer(typeof(AssetBase));
+
+ AssetBase encAsset = (AssetBase)xs.Deserialize(s);
+
+ // Try decrypt it
+ if (DecryptAssetBase(encAsset))
+ return encAsset;
+ }
+
+ return null;
+ }
+
+ public override void UpdateAsset(AssetBase asset)
+ {
+ throw new Exception("The method or operation is not implemented.");
+ }
+
+ public override void StoreAsset(AssetBase asset)
+ {
+ if (m_encryptOnUpload)
+ EncryptAssetBase(asset, m_encryptKey);
+
+ try
+ {
+ string assetUrl = _assetServerUrl + "/assets/";
+
+ m_log.InfoFormat("[CRYPTO GRID ASSET CLIENT]: Sending store request for asset {0}", asset.FullID);
+
+ RestObjectPoster.BeginPostObject(assetUrl, asset);
+ }
+ catch (Exception e)
+ {
+ m_log.ErrorFormat("[CRYPTO GRID ASSET CLIENT]: {0}", e);
+ }
+ }
+
+ public override void Close()
+ {
+ throw new Exception("The method or operation is not implemented.");
+ }
+
+ #endregion
+ }
+}
--
cgit v1.1