using System; using System.Collections.Generic; using System.IO; using System.Security.Cryptography; using System.Text; namespace Lidgren.Network { /// /// Triple DES encryption /// public class NetTripleDESEncryption : INetEncryption { private readonly byte[] m_key; private readonly byte[] m_iv; private readonly int m_bitSize; private static readonly List m_keysizes; private static readonly List m_blocksizes; static NetTripleDESEncryption() { TripleDESCryptoServiceProvider tripleDES = new TripleDESCryptoServiceProvider(); List temp = new List(); foreach (KeySizes keysize in tripleDES.LegalKeySizes) { for (int i = keysize.MinSize; i <= keysize.MaxSize; i += keysize.SkipSize) { if (!temp.Contains(i)) temp.Add(i); if (i == keysize.MaxSize) break; } } m_keysizes = temp; temp = new List(); foreach (KeySizes keysize in tripleDES.LegalBlockSizes) { for (int i = keysize.MinSize; i <= keysize.MaxSize; i += keysize.SkipSize) { if (!temp.Contains(i)) temp.Add(i); if (i == keysize.MaxSize) break; } } m_blocksizes = temp; } /// /// NetTriplsDESEncryption constructor /// public NetTripleDESEncryption(byte[] key, byte[] iv) { if (!m_keysizes.Contains(key.Length * 8)) throw new NetException(string.Format("Not a valid key size. (Valid values are: {0})", NetUtility.MakeCommaDelimitedList(m_keysizes))); if (!m_blocksizes.Contains(iv.Length * 8)) throw new NetException(string.Format("Not a valid iv size. (Valid values are: {0})", NetUtility.MakeCommaDelimitedList(m_blocksizes))); m_key = key; m_iv = iv; m_bitSize = m_key.Length * 8; } /// /// NetTriplsDESEncryption constructor /// public NetTripleDESEncryption(string key, int bitsize) { if (!m_keysizes.Contains(bitsize)) throw new NetException(string.Format("Not a valid key size. (Valid values are: {0})", NetUtility.MakeCommaDelimitedList(m_keysizes))); byte[] entropy = Encoding.UTF32.GetBytes(key); // I know hardcoding salts is bad, but in this case I think it is acceptable. HMACSHA512 hmacsha512 = new HMACSHA512(Convert.FromBase64String("i88NEiez3c50bHqr3YGasDc4p8jRrxJAaiRiqixpvp4XNAStP5YNoC2fXnWkURtkha6M8yY901Gj07IRVIRyGL==")); hmacsha512.Initialize(); for (int i = 0; i < 1000; i++) { entropy = hmacsha512.ComputeHash(entropy); } int keylen = bitsize / 8; m_key = new byte[keylen]; Buffer.BlockCopy(entropy, 0, m_key, 0, keylen); m_iv = new byte[m_blocksizes[0] / 8]; Buffer.BlockCopy(entropy, entropy.Length - m_iv.Length - 1, m_iv, 0, m_iv.Length); m_bitSize = bitsize; } /// /// NetTriplsDESEncryption constructor /// public NetTripleDESEncryption(string key) : this(key, m_keysizes[0]) { } /// /// Encrypt outgoing message /// public bool Encrypt(NetOutgoingMessage msg) { try { // nested usings are fun! using (TripleDESCryptoServiceProvider tripleDESCryptoServiceProvider = new TripleDESCryptoServiceProvider { KeySize = m_bitSize, Mode = CipherMode.CBC }) { using (ICryptoTransform cryptoTransform = tripleDESCryptoServiceProvider.CreateEncryptor(m_key, m_iv)) { using (MemoryStream memoryStream = new MemoryStream()) { using (CryptoStream cryptoStream = new CryptoStream(memoryStream, cryptoTransform, CryptoStreamMode.Write)) { cryptoStream.Write(msg.m_data, 0, msg.m_data.Length); } msg.m_data = memoryStream.ToArray(); } } } } catch { return false; } return true; } /// /// Decrypt incoming message /// public bool Decrypt(NetIncomingMessage msg) { try { // nested usings are fun! using (TripleDESCryptoServiceProvider tripleDESCryptoServiceProvider = new TripleDESCryptoServiceProvider { KeySize = m_bitSize, Mode = CipherMode.CBC }) { using (ICryptoTransform cryptoTransform = tripleDESCryptoServiceProvider.CreateDecryptor(m_key, m_iv)) { using (MemoryStream memoryStream = new MemoryStream()) { using (CryptoStream cryptoStream = new CryptoStream(memoryStream, cryptoTransform, CryptoStreamMode.Write)) { cryptoStream.Write(msg.m_data, 0, msg.m_data.Length); } msg.m_data = memoryStream.ToArray(); } } } } catch { return false; } return true; } } }