From 814cd1507df3e3185cc2bceca70ffbe722fa4fd3 Mon Sep 17 00:00:00 2001 From: lidgren Date: Mon, 25 Apr 2011 15:25:35 +0000 Subject: [PATCH] Various encryption algorithms added; thanks shawn andrew rose --- .../Encryption/NetAESEncryption.cs | 175 +++++++++++++++++ .../Encryption/NetDESEncryption.cs | 175 +++++++++++++++++ .../Encryption/NetRC2Encryption.cs | 176 ++++++++++++++++++ .../Encryption/NetTripleDESEncryption.cs | 175 +++++++++++++++++ Lidgren.Network/Lidgren.Network.csproj | 4 + UnitTests/EncryptionTests.cs | 6 +- 6 files changed, 710 insertions(+), 1 deletion(-) create mode 100644 Lidgren.Network/Encryption/NetAESEncryption.cs create mode 100644 Lidgren.Network/Encryption/NetDESEncryption.cs create mode 100644 Lidgren.Network/Encryption/NetRC2Encryption.cs create mode 100644 Lidgren.Network/Encryption/NetTripleDESEncryption.cs diff --git a/Lidgren.Network/Encryption/NetAESEncryption.cs b/Lidgren.Network/Encryption/NetAESEncryption.cs new file mode 100644 index 0000000..ffb9bdf --- /dev/null +++ b/Lidgren.Network/Encryption/NetAESEncryption.cs @@ -0,0 +1,175 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Text; + +namespace Lidgren.Network +{ + /// + /// AES encryption + /// + public class NetAESEncryption : 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 NetAESEncryption() + { + + AesCryptoServiceProvider aes = new AesCryptoServiceProvider(); + List temp = new List(); + foreach (KeySizes keysize in aes.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 aes.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; + } + + /// + /// NetAESEncryption constructor + /// + public NetAESEncryption(byte[] key, byte[] iv) + { + if (!m_keysizes.Contains(key.Length * 8)) + { + string lengths = m_keysizes.Aggregate("", (current, i) => current + string.Format("{0}, ", i)); + lengths = lengths.Remove(lengths.Length - 3); + throw new NetException(string.Format("Not a valid key size. (Valid values are: {0})", lengths)); + } + + if (!m_blocksizes.Contains(iv.Length * 8)) + { + string lengths = m_blocksizes.Aggregate("", (current, i) => current + string.Format("{0}, ", i)); + lengths = lengths.Remove(lengths.Length - 3); + throw new NetException(string.Format("Not a valid iv size. (Valid values are: {0})", lengths)); + } + m_key = key; + m_iv = iv; + m_bitSize = m_key.Length * 8; + } + + /// + /// NetAESEncryption constructor + /// + public NetAESEncryption(string key, int bitsize) + { + if (!m_keysizes.Contains(bitsize)) + { + string lengths = m_keysizes.Aggregate("", (current, i) => current + string.Format("{0}, ", i)); + lengths = lengths.Remove(lengths.Length - 3); + throw new NetException(string.Format("Not a valid key size. (Valid values are: {0})", lengths)); + } + 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; + } + + /// + /// NetAESEncryption constructor + /// + public NetAESEncryption(string key) + : this(key, m_keysizes.Max()) + { + } + + /// + /// Encrypt outgoing message + /// + public bool Encrypt(NetOutgoingMessage msg) + { + try + { + // nested usings are fun! + using (AesCryptoServiceProvider aesCryptoServiceProvider = new AesCryptoServiceProvider { KeySize = m_bitSize, Mode = CipherMode.CBC }) + { + using (ICryptoTransform cryptoTransform = aesCryptoServiceProvider.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 (AesCryptoServiceProvider aesCryptoServiceProvider = new AesCryptoServiceProvider { KeySize = m_bitSize, Mode = CipherMode.CBC }) + { + using (ICryptoTransform cryptoTransform = aesCryptoServiceProvider.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; + } + } +} \ No newline at end of file diff --git a/Lidgren.Network/Encryption/NetDESEncryption.cs b/Lidgren.Network/Encryption/NetDESEncryption.cs new file mode 100644 index 0000000..d212468 --- /dev/null +++ b/Lidgren.Network/Encryption/NetDESEncryption.cs @@ -0,0 +1,175 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Text; + +namespace Lidgren.Network +{ + /// + /// DES encryption + /// + public class NetDESEncryption : 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 NetDESEncryption() + { + + DESCryptoServiceProvider des = new DESCryptoServiceProvider(); + List temp = new List(); + foreach (KeySizes keysize in des.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 des.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; + } + + /// + /// NetDESEncryption constructor + /// + public NetDESEncryption(byte[] key, byte[] iv) + { + if (!m_keysizes.Contains(key.Length * 8)) + { + string lengths = m_keysizes.Aggregate("", (current, i) => current + string.Format("{0}, ", i)); + lengths = lengths.Remove(lengths.Length - 3); + throw new NetException(string.Format("Not a valid key size. (Valid values are: {0})", lengths)); + } + + if (!m_blocksizes.Contains(iv.Length * 8)) + { + string lengths = m_blocksizes.Aggregate("", (current, i) => current + string.Format("{0}, ", i)); + lengths = lengths.Remove(lengths.Length - 3); + throw new NetException(string.Format("Not a valid iv size. (Valid values are: {0})", lengths)); + } + m_key = key; + m_iv = iv; + m_bitSize = m_key.Length * 8; + } + + /// + /// NetDESEncryption constructor + /// + public NetDESEncryption(string key, int bitsize) + { + if (!m_keysizes.Contains(bitsize)) + { + string lengths = m_keysizes.Aggregate("", (current, i) => current + string.Format("{0}, ", i)); + lengths = lengths.Remove(lengths.Length - 3); + throw new NetException(string.Format("Not a valid key size. (Valid values are: {0})", lengths)); + } + 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; + } + + /// + /// NetDESEncryption constructor + /// + public NetDESEncryption(string key) + : this(key, m_keysizes.Max()) + { + } + + /// + /// Encrypt outgoing message + /// + public bool Encrypt(NetOutgoingMessage msg) + { + try + { + // nested usings are fun! + using (DESCryptoServiceProvider desCryptoServiceProvider = new DESCryptoServiceProvider { KeySize = m_bitSize, Mode = CipherMode.CBC }) + { + using (ICryptoTransform cryptoTransform = desCryptoServiceProvider.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 (DESCryptoServiceProvider desCryptoServiceProvider = new DESCryptoServiceProvider { KeySize = m_bitSize, Mode = CipherMode.CBC }) + { + using (ICryptoTransform cryptoTransform = desCryptoServiceProvider.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; + } + } +} \ No newline at end of file diff --git a/Lidgren.Network/Encryption/NetRC2Encryption.cs b/Lidgren.Network/Encryption/NetRC2Encryption.cs new file mode 100644 index 0000000..a65d234 --- /dev/null +++ b/Lidgren.Network/Encryption/NetRC2Encryption.cs @@ -0,0 +1,176 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Text; + +namespace Lidgren.Network +{ + /// + /// RC2 encryption + /// + public class NetRC2Encryption : 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 NetRC2Encryption() + { + + RC2CryptoServiceProvider rc2 = new RC2CryptoServiceProvider(); + List temp = new List(); + foreach (KeySizes keysize in rc2.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 rc2.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; + } + + /// + /// NetRC2Encryption constructor + /// + public NetRC2Encryption(byte[] key, byte[] iv) + { + if (!m_keysizes.Contains(key.Length * 8)) + { + string lengths = m_keysizes.Aggregate("", (current, i) => current + string.Format("{0}, ", i)); + lengths = lengths.Remove(lengths.Length - 3); + throw new NetException(string.Format("Not a valid key size. (Valid values are: {0})", lengths)); + } + + if (!m_blocksizes.Contains(iv.Length * 8)) + { + string lengths = m_blocksizes.Aggregate("", (current, i) => current + string.Format("{0}, ", i)); + lengths = lengths.Remove(lengths.Length - 3); + throw new NetException(string.Format("Not a valid iv size. (Valid values are: {0})", lengths)); + } + m_key = key; + m_iv = iv; + m_bitSize = m_key.Length * 8; + } + + /// + /// NetRC2Encryption constructor + /// + public NetRC2Encryption(string key, int bitsize) + { + if (!m_keysizes.Contains(bitsize)) + { + string lengths = m_keysizes.Aggregate("", (current, i) => current + string.Format("{0}, ", i)); + lengths = lengths.Remove(lengths.Length - 3); + throw new NetException(string.Format("Not a valid key size. (Valid values are: {0})", lengths)); + } + 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; + } + + /// + /// NetRC2Encryption constructor + /// + /// + public NetRC2Encryption(string key) + : this(key, m_keysizes.Max()) + { + } + + /// + /// Encrypt outgoing message + /// + public bool Encrypt(NetOutgoingMessage msg) + { + try + { + // nested usings are fun! + using (RC2CryptoServiceProvider rc2CryptoServiceProvider = new RC2CryptoServiceProvider { KeySize = m_bitSize, Mode = CipherMode.CBC }) + { + using (ICryptoTransform cryptoTransform = rc2CryptoServiceProvider.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 (RC2CryptoServiceProvider rc2CryptoServiceProvider = new RC2CryptoServiceProvider { KeySize = m_bitSize, Mode = CipherMode.CBC }) + { + using (ICryptoTransform cryptoTransform = rc2CryptoServiceProvider.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; + } + } +} \ No newline at end of file diff --git a/Lidgren.Network/Encryption/NetTripleDESEncryption.cs b/Lidgren.Network/Encryption/NetTripleDESEncryption.cs new file mode 100644 index 0000000..a1bfd10 --- /dev/null +++ b/Lidgren.Network/Encryption/NetTripleDESEncryption.cs @@ -0,0 +1,175 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +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)) + { + string lengths = m_keysizes.Aggregate("", (current, i) => current + string.Format("{0}, ", i)); + lengths = lengths.Remove(lengths.Length - 3); + throw new NetException(string.Format("Not a valid key size. (Valid values are: {0})", lengths)); + } + + if (!m_blocksizes.Contains(iv.Length * 8)) + { + string lengths = m_blocksizes.Aggregate("", (current, i) => current + string.Format("{0}, ", i)); + lengths = lengths.Remove(lengths.Length - 3); + throw new NetException(string.Format("Not a valid iv size. (Valid values are: {0})", lengths)); + } + 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)) + { + string lengths = m_keysizes.Aggregate("", (current, i) => current + string.Format("{0}, ", i)); + lengths = lengths.Remove(lengths.Length - 3); + throw new NetException(string.Format("Not a valid key size. (Valid values are: {0})", lengths)); + } + 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.Max()) + { + } + + /// + /// 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; + } + } +} \ No newline at end of file diff --git a/Lidgren.Network/Lidgren.Network.csproj b/Lidgren.Network/Lidgren.Network.csproj index c16f353..d310e1f 100644 --- a/Lidgren.Network/Lidgren.Network.csproj +++ b/Lidgren.Network/Lidgren.Network.csproj @@ -72,9 +72,13 @@ + + + + diff --git a/UnitTests/EncryptionTests.cs b/UnitTests/EncryptionTests.cs index 32db22e..0b071b0 100644 --- a/UnitTests/EncryptionTests.cs +++ b/UnitTests/EncryptionTests.cs @@ -12,12 +12,16 @@ namespace UnitTests public static void Run(NetPeer peer) { // - // Test XTEA + // Test encryption // List algos = new List(); algos.Add(new NetXorEncryption("TopSecret")); algos.Add(new NetXtea("TopSecret")); + algos.Add(new NetAESEncryption("TopSecret")); + algos.Add(new NetRC2Encryption("TopSecret")); + algos.Add(new NetDESEncryption("TopSecret")); + algos.Add(new NetTripleDESEncryption("TopSecret")); foreach (var algo in algos) {