简单的不安全的双向“混淆”为C#
我正在寻找一些数据非常简单的混淆(如encryption和解密,但不一定安全)的function。 这不是任务关键。 我需要一些诚实的人保持诚实,但是比ROT13或者Base64稍强一些。
我更喜欢已经包含在.NET Framework 2.0中的东西,所以我不必担心任何外部依赖。
我真的不想乱用公共/私人密钥等等。我对encryption知之甚less,但是我确实知道我所写的任何东西都不值钱。事实上,我可能搞砸了math,使它微不足道的破解。
其他答案在这里工作正常,但AES是一个更安全和最新的encryptionalgorithm。 这是我几年前获得的一个类,用于执行AESencryption,随着时间的推移,我已经修改了这个encryption方法,以便对Web应用程序更加友好(例如,我已经构build了使用URL友好string的encryption/解密方法)。 它也有与字节数组一起工作的方法。
注意:您应该在密钥(32字节)和向量(16字节)数组中使用不同的值! 你不想让别人弄清楚你的密钥,只是假设你原来使用这个代码! 所有你需要做的就是改变Key和Vector数组中的一些数字(必须是<= 255)(我在Vector数组中留下了一个无效值,以确保你这样做)。 您可以使用https://www.random.org/bytes/轻松生成一个新的集合:;
- 生成
Key
- 生成
Vector
使用它很简单:只需实例化类,然后调用(通常)EncryptToString(string StringToEncrypt)和DecryptString(string StringToDecrypt)作为方法。 一旦你有了这个课程,这不会更容易(或更安全)。
using System; using System.Data; using System.Security.Cryptography; using System.IO; public class SimpleAES { // Change these keys private byte[] Key = __Replace_Me__({ 123, 217, 19, 11, 24, 26, 85, 45, 114, 184, 27, 162, 37, 112, 222, 209, 241, 24, 175, 144, 173, 53, 196, 29, 24, 26, 17, 218, 131, 236, 53, 209 }); // a hardcoded IV should not be used for production AES-CBC code // IVs should be unpredictable per ciphertext private byte[] Vector = __Replace_Me__({ 146, 64, 191, 111, 23, 3, 113, 119, 231, 121, 2521, 112, 79, 32, 114, 156 }); private ICryptoTransform EncryptorTransform, DecryptorTransform; private System.Text.UTF8Encoding UTFEncoder; public SimpleAES() { //This is our encryption method RijndaelManaged rm = new RijndaelManaged(); //Create an encryptor and a decryptor using our encryption method, key, and vector. EncryptorTransform = rm.CreateEncryptor(this.Key, this.Vector); DecryptorTransform = rm.CreateDecryptor(this.Key, this.Vector); //Used to translate bytes to text and vice versa UTFEncoder = new System.Text.UTF8Encoding(); } /// -------------- Two Utility Methods (not used but may be useful) ----------- /// Generates an encryption key. static public byte[] GenerateEncryptionKey() { //Generate a Key. RijndaelManaged rm = new RijndaelManaged(); rm.GenerateKey(); return rm.Key; } /// Generates a unique encryption vector static public byte[] GenerateEncryptionVector() { //Generate a Vector RijndaelManaged rm = new RijndaelManaged(); rm.GenerateIV(); return rm.IV; } /// ----------- The commonly used methods ------------------------------ /// Encrypt some text and return a string suitable for passing in a URL. public string EncryptToString(string TextValue) { return ByteArrToString(Encrypt(TextValue)); } /// Encrypt some text and return an encrypted byte array. public byte[] Encrypt(string TextValue) { //Translates our text value into a byte array. Byte[] bytes = UTFEncoder.GetBytes(TextValue); //Used to stream the data in and out of the CryptoStream. MemoryStream memoryStream = new MemoryStream(); /* * We will have to write the unencrypted bytes to the stream, * then read the encrypted result back from the stream. */ #region Write the decrypted value to the encryption stream CryptoStream cs = new CryptoStream(memoryStream, EncryptorTransform, CryptoStreamMode.Write); cs.Write(bytes, 0, bytes.Length); cs.FlushFinalBlock(); #endregion #region Read encrypted value back out of the stream memoryStream.Position = 0; byte[] encrypted = new byte[memoryStream.Length]; memoryStream.Read(encrypted, 0, encrypted.Length); #endregion //Clean up. cs.Close(); memoryStream.Close(); return encrypted; } /// The other side: Decryption methods public string DecryptString(string EncryptedString) { return Decrypt(StrToByteArray(EncryptedString)); } /// Decryption when working with byte arrays. public string Decrypt(byte[] EncryptedValue) { #region Write the encrypted value to the decryption stream MemoryStream encryptedStream = new MemoryStream(); CryptoStream decryptStream = new CryptoStream(encryptedStream, DecryptorTransform, CryptoStreamMode.Write); decryptStream.Write(EncryptedValue, 0, EncryptedValue.Length); decryptStream.FlushFinalBlock(); #endregion #region Read the decrypted value from the stream. encryptedStream.Position = 0; Byte[] decryptedBytes = new Byte[encryptedStream.Length]; encryptedStream.Read(decryptedBytes, 0, decryptedBytes.Length); encryptedStream.Close(); #endregion return UTFEncoder.GetString(decryptedBytes); } /// Convert a string to a byte array. NOTE: Normally we'd create a Byte Array from a string using an ASCII encoding (like so). // System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding(); // return encoding.GetBytes(str); // However, this results in character values that cannot be passed in a URL. So, instead, I just // lay out all of the byte values in a long string of numbers (three per - must pad numbers less than 100). public byte[] StrToByteArray(string str) { if (str.Length == 0) throw new Exception("Invalid string value in StrToByteArray"); byte val; byte[] byteArr = new byte[str.Length / 3]; int i = 0; int j = 0; do { val = byte.Parse(str.Substring(i, 3)); byteArr[j++] = val; i += 3; } while (i < str.Length); return byteArr; } // Same comment as above. Normally the conversion would use an ASCII encoding in the other direction: // System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); // return enc.GetString(byteArr); public string ByteArrToString(byte[] byteArr) { byte val; string tempStr = ""; for (int i = 0; i <= byteArr.GetUpperBound(0); i++) { val = byteArr[i]; if (val < (byte)10) tempStr += "00" + val.ToString(); else if (val < (byte)100) tempStr += "0" + val.ToString(); else tempStr += val.ToString(); } return tempStr; } }
我清理了SimpleAES(以上)供我使用。 固定卷积encryption/解密方法; 用于编码字节缓冲区,string和URL友好string的分离方法; 利用现有的库进行URL编码。
代码更小,更简单,速度更快,输出更简洁。 例如, johnsmith@gmail.com
产生:
SimpleAES: "096114178117140150104121138042115022037019164188092040214235183167012211175176167001017163166152" SimplerAES: "YHKydYyWaHmKKnMWJROkvFwo1uu3pwzTr7CnARGjppg%3d"
码:
public class SimplerAES { private static byte[] key = __Replace_Me__({ 123, 217, 19, 11, 24, 26, 85, 45, 114, 184, 27, 162, 37, 112, 222, 209, 241, 24, 175, 144, 173, 53, 196, 29, 24, 26, 17, 218, 131, 236, 53, 209 }); // a hardcoded IV should not be used for production AES-CBC code // IVs should be unpredictable per ciphertext private static byte[] vector = __Replace_Me_({ 146, 64, 191, 111, 23, 3, 113, 119, 231, 121, 221, 112, 79, 32, 114, 156 }); private ICryptoTransform encryptor, decryptor; private UTF8Encoding encoder; public SimplerAES() { RijndaelManaged rm = new RijndaelManaged(); encryptor = rm.CreateEncryptor(key, vector); decryptor = rm.CreateDecryptor(key, vector); encoder = new UTF8Encoding(); } public string Encrypt(string unencrypted) { return Convert.ToBase64String(Encrypt(encoder.GetBytes(unencrypted))); } public string Decrypt(string encrypted) { return encoder.GetString(Decrypt(Convert.FromBase64String(encrypted))); } public byte[] Encrypt(byte[] buffer) { return Transform(buffer, encryptor); } public byte[] Decrypt(byte[] buffer) { return Transform(buffer, decryptor); } protected byte[] Transform(byte[] buffer, ICryptoTransform transform) { MemoryStream stream = new MemoryStream(); using (CryptoStream cs = new CryptoStream(stream, transform, CryptoStreamMode.Write)) { cs.Write(buffer, 0, buffer.Length); } return stream.ToArray(); } }
是的,添加System.Security
程序集,导入System.Security.Cryptography
命名空间。 下面是对称(DES)algorithmencryption的一个简单例子:
DESCryptoServiceProvider des = new DESCryptoServiceProvider(); des.GenerateKey(); byte[] key = des.Key; // save this! ICryptoTransform encryptor = des.CreateEncryptor(); // encrypt byte[] enc = encryptor.TransformFinalBlock(new byte[] { 1, 2, 3, 4 }, 0, 4); ICryptoTransform decryptor = des.CreateDecryptor(); // decrypt byte[] originalAgain = decryptor.TransformFinalBlock(enc, 0, enc.Length); Debug.Assert(originalAgain[0] == 1);
我想补充说,我已经通过添加一个随机的IV在encryption的string中传回来改进了Mud的SimplerAES。 这改进了encryption,因为每次encryption相同的string将导致不同的输出。
public class StringEncryption { private readonly Random random; private readonly byte[] key; private readonly RijndaelManaged rm; private readonly UTF8Encoding encoder; public StringEncryption() { this.random = new Random(); this.rm = new RijndaelManaged(); this.encoder = new UTF8Encoding(); this.key = Convert.FromBase64String("Your+Secret+Static+Encryption+Key+Goes+Here="); } public string Encrypt(string unencrypted) { var vector = new byte[16]; this.random.NextBytes(vector); var cryptogram = vector.Concat(this.Encrypt(this.encoder.GetBytes(unencrypted), vector)); return Convert.ToBase64String(cryptogram.ToArray()); } public string Decrypt(string encrypted) { var cryptogram = Convert.FromBase64String(encrypted); if (cryptogram.Length < 17) { throw new ArgumentException("Not a valid encrypted string", "encrypted"); } var vector = cryptogram.Take(16).ToArray(); var buffer = cryptogram.Skip(16).ToArray(); return this.encoder.GetString(this.Decrypt(buffer, vector)); } private byte[] Encrypt(byte[] buffer, byte[] vector) { var encryptor = this.rm.CreateEncryptor(this.key, vector); return this.Transform(buffer, encryptor); } private byte[] Decrypt(byte[] buffer, byte[] vector) { var decryptor = this.rm.CreateDecryptor(this.key, vector); return this.Transform(buffer, decryptor); } private byte[] Transform(byte[] buffer, ICryptoTransform transform) { var stream = new MemoryStream(); using (var cs = new CryptoStream(stream, transform, CryptoStreamMode.Write)) { cs.Write(buffer, 0, buffer.Length); } return stream.ToArray(); } }
和奖金unit testing
[Test] public void EncryptDecrypt() { // Arrange var subject = new StringEncryption(); var originalString = "Testing123!£$"; // Act var encryptedString1 = subject.Encrypt(originalString); var encryptedString2 = subject.Encrypt(originalString); var decryptedString1 = subject.Decrypt(encryptedString1); var decryptedString2 = subject.Decrypt(encryptedString2); // Assert Assert.AreEqual(originalString, decryptedString1, "Decrypted string should match original string"); Assert.AreEqual(originalString, decryptedString2, "Decrypted string should match original string"); Assert.AreNotEqual(originalString, encryptedString1, "Encrypted string should not match original string"); Assert.AreNotEqual(encryptedString1, encryptedString2, "String should never be encrypted the same twice"); }
标记(优秀)答案的变体
- 添加“使用”
- 使类IDisposable
- 删除URL编码代码,使示例更简单。
- 添加一个简单的testing夹具来演示使用
希望这可以帮助
[TestFixture] public class RijndaelHelperTests { [Test] public void UseCase() { //These two values should not be hard coded in your code. byte[] key = {251, 9, 67, 117, 237, 158, 138, 150, 255, 97, 103, 128, 183, 65, 76, 161, 7, 79, 244, 225, 146, 180, 51, 123, 118, 167, 45, 10, 184, 181, 202, 190}; byte[] vector = {214, 11, 221, 108, 210, 71, 14, 15, 151, 57, 241, 174, 177, 142, 115, 137}; using (var rijndaelHelper = new RijndaelHelper(key, vector)) { var encrypt = rijndaelHelper.Encrypt("StringToEncrypt"); var decrypt = rijndaelHelper.Decrypt(encrypt); Assert.AreEqual("StringToEncrypt", decrypt); } } } public class RijndaelHelper : IDisposable { Rijndael rijndael; UTF8Encoding encoding; public RijndaelHelper(byte[] key, byte[] vector) { encoding = new UTF8Encoding(); rijndael = Rijndael.Create(); rijndael.Key = key; rijndael.IV = vector; } public byte[] Encrypt(string valueToEncrypt) { var bytes = encoding.GetBytes(valueToEncrypt); using (var encryptor = rijndael.CreateEncryptor()) using (var stream = new MemoryStream()) using (var crypto = new CryptoStream(stream, encryptor, CryptoStreamMode.Write)) { crypto.Write(bytes, 0, bytes.Length); crypto.FlushFinalBlock(); stream.Position = 0; var encrypted = new byte[stream.Length]; stream.Read(encrypted, 0, encrypted.Length); return encrypted; } } public string Decrypt(byte[] encryptedValue) { using (var decryptor = rijndael.CreateDecryptor()) using (var stream = new MemoryStream()) using (var crypto = new CryptoStream(stream, decryptor, CryptoStreamMode.Write)) { crypto.Write(encryptedValue, 0, encryptedValue.Length); crypto.FlushFinalBlock(); stream.Position = 0; var decryptedBytes = new Byte[stream.Length]; stream.Read(decryptedBytes, 0, decryptedBytes.Length); return encoding.GetString(decryptedBytes); } } public void Dispose() { if (rijndael != null) { rijndael.Dispose(); } } }
[编辑]多年后,我回来说: 不要这样做! 看看XORencryption有什么问题? 了解详情。
一个非常简单,容易的双向encryption是XORencryption。
- 拿出一个密码。 让我们成为
mypass
。 - 将密码转换为二进制(根据ASCII)。 密码变为01101101 01111001 01110000 01100001 01110011 01110011。
- 采取你想要编码的消息。 将其转换为二进制。
- 看消息的长度。 如果消息长度为400字节,则通过反复重复将密码转换为400字节的string。 它会变成01101101 01111001 01110000 01100001 01110011 01110011 01101101 01111001 01110000 01100001 01110011 01110011 01101101 01111001 01110000 01100001 01110011 01110011 …(或
mypassmypassmypass...
) - 用长密码XOR消息。
- 发送结果。
- 另一次,用相同的密码XORencryption的消息(
mypassmypassmypass...
)。 - 有你的消息!
如果你只是想要简单的encryption(例如,一个确定的破解者可能破坏,但locking大多数偶然用户),只需select两个相同长度的密码短语,比如说:
deoxyribonucleicacid while (x>0) { x-- };
和你的数据和他们两个(如果需要循环密码) (a) 。 例如:
1111-2222-3333-4444-5555-6666-7777 deoxyribonucleicaciddeoxyribonucle while (x>0) { x-- };while (x>0) {
有人search你的二进制文件可能会认为DNAstring是一个关键,但他们不太可能认为C代码是除了二进制文件保存的未初始化内存以外的任何东西。
(a)请记住,这是非常简单的encryption,并且根据某些定义,可能根本不被认为是encryption(因为encryption的目的是为了防止未经授权的访问,而不是使其变得更加困难)。 当然,当某人用钢pipe站在钥匙盒上时,即使是最强的encryption也是不安全的。
正如第一句话所述,这是一个让临时攻击者足够困难的方法,他们将继续前进。 这类似于防止家中盗窃 – 你不需要让它变得坚不可摧,你只需要让它比隔壁的房子更难受。:-)
encryption很简单:正如其他人指出的那样,System.Security.Cryptography命名空间中有一些类为您完成所有工作。 使用它们而不是任何本地解决scheme。
但解密也很容易。 您拥有的问题不是encryptionalgorithm,而是保护对用于解密的密钥的访问。
我会使用以下解决scheme之一:
-
使用带有CurrentUser作用域的ProtectedData类的DPAPI。 这很容易,因为你不必担心一个关键。 数据只能由同一个用户解密,所以在用户和机器之间共享数据是没有好处的。
-
使用带有LocalMachine范围的ProtectedData类的DPAPI。 适用于例如保护单个安全服务器上的configuration数据。 但是任何可以login到计算机的人都可以对其进行encryption,除非服务器是安全的,否则不行。
-
任何对称algorithm。 我通常使用静态SymmetricAlgorithm.Create()方法,如果我不在乎使用什么algorithm(事实上它是Rijndael默认情况下)。 在这种情况下,您需要以某种方式保护您的密钥。 例如,您可以用某种方式对其进行混淆,并将其隐藏在代码中。 但是请注意,任何能够反编译代码的人都可能find密钥。
我想发布我的解决scheme,因为上述解决scheme都不像我的那么简单。 让我知道你的想法:
// This will return an encrypted string based on the unencrypted parameter public static string Encrypt(this string DecryptedValue) { HttpServerUtility.UrlTokenEncode(MachineKey.Protect(Encoding.UTF8.GetBytes(DecryptedValue.Trim()))); } // This will return an unencrypted string based on the parameter public static string Decrypt(this string EncryptedValue) { Encoding.UTF8.GetString(MachineKey.Unprotect(HttpServerUtility.UrlTokenDecode(EncryptedValue))); }
可选的
这假定用于encryption该值的服务器的MachineKey与用于解密该值的那个相同。 如果需要,可以在Web.config中指定一个静态MachineKey,以便应用程序可以解密/encryption数据,而不pipe它在哪里运行(例如,开发与生产服务器)。 您可以按照这些说明生成静态机器密钥 。
我把几个答案和评论中find的最好的结合在一起。
- 随机初始化向量预encryptionencryption文本(@jbtule)
- 使用TransformFinalBlock()而不是MemoryStream(@RenniePet)
- 没有预先填写的密钥,以避免任何人复制和粘贴灾难
- 正确处理和使用模式
码:
/// <summary> /// Simple encryption/decryption using a random initialization vector /// and prepending it to the crypto text. /// </summary> /// <remarks>Based on multiple answers in http://stackoverflow.com/questions/165808/simple-two-way-encryption-for-c-sharp </remarks> public class SimpleAes : IDisposable { /// <summary> /// Initialization vector length in bytes. /// </summary> private const int IvBytes = 16; /// <summary> /// Must be exactly 16, 24 or 32 bytes long. /// </summary> private static readonly byte[] Key = Convert.FromBase64String("FILL ME WITH 24 (2 pad chars), 32 OR 44 (1 pad char) RANDOM CHARS"); // Base64 has a blowup of four-thirds (33%) private readonly UTF8Encoding _encoder; private readonly ICryptoTransform _encryptor; private readonly RijndaelManaged _rijndael; public SimpleAes() { _rijndael = new RijndaelManaged {Key = Key}; _rijndael.GenerateIV(); _encryptor = _rijndael.CreateEncryptor(); _encoder = new UTF8Encoding(); } public string Decrypt(string encrypted) { return _encoder.GetString(Decrypt(Convert.FromBase64String(encrypted))); } public void Dispose() { _rijndael.Dispose(); _encryptor.Dispose(); } public string Encrypt(string unencrypted) { return Convert.ToBase64String(Encrypt(_encoder.GetBytes(unencrypted))); } private byte[] Decrypt(byte[] buffer) { // IV is prepended to cryptotext byte[] iv = buffer.Take(IvBytes).ToArray(); using (ICryptoTransform decryptor = _rijndael.CreateDecryptor(_rijndael.Key, iv)) { return decryptor.TransformFinalBlock(buffer, IvBytes, buffer.Length - IvBytes); } } private byte[] Encrypt(byte[] buffer) { // Prepend cryptotext with IV byte [] inputBuffer = _encryptor.TransformFinalBlock(buffer, 0, buffer.Length); return _rijndael.IV.Concat(inputBuffer).ToArray(); } }
更新2015-07-18:通过@bpsilver和@Evereq的注释修复私有Encrypt()方法中的错误。 IV被意外encryption,现在按照Decrypt()的预期,以明文forms添加。
命名空间System.Security.Cryptography
包含TripleDESCryptoServiceProvider
和RijndaelManaged
类
不要忘记添加一个对System.Security
程序集的引用。
我改变了这个 :
public string ByteArrToString(byte[] byteArr) { byte val; string tempStr = ""; for (int i = 0; i <= byteArr.GetUpperBound(0); i++) { val = byteArr[i]; if (val < (byte)10) tempStr += "00" + val.ToString(); else if (val < (byte)100) tempStr += "0" + val.ToString(); else tempStr += val.ToString(); } return tempStr; }
对此:
public string ByteArrToString(byte[] byteArr) { string temp = ""; foreach (byte b in byteArr) temp += b.ToString().PadLeft(3, '0'); return temp; }
我知道你说过你并不在意它是多么的安全,但是如果你select了DES,你最好还是采取AES,这是最新的encryption方法。
使用内置的.Net密码库,这个例子展示了如何使用高级encryption标准(AES)。
using System; using System.IO; using System.Security.Cryptography; namespace Aes_Example { class AesExample { public static void Main() { try { string original = "Here is some data to encrypt!"; // Create a new instance of the Aes // class. This generates a new key and initialization // vector (IV). using (Aes myAes = Aes.Create()) { // Encrypt the string to an array of bytes. byte[] encrypted = EncryptStringToBytes_Aes(original, myAes.Key, myAes.IV); // Decrypt the bytes to a string. string roundtrip = DecryptStringFromBytes_Aes(encrypted, myAes.Key, myAes.IV); //Display the original data and the decrypted data. Console.WriteLine("Original: {0}", original); Console.WriteLine("Round Trip: {0}", roundtrip); } } catch (Exception e) { Console.WriteLine("Error: {0}", e.Message); } } static byte[] EncryptStringToBytes_Aes(string plainText, byte[] Key,byte[] IV) { // Check arguments. if (plainText == null || plainText.Length <= 0) throw new ArgumentNullException("plainText"); if (Key == null || Key.Length <= 0) throw new ArgumentNullException("Key"); if (IV == null || IV.Length <= 0) throw new ArgumentNullException("Key"); byte[] encrypted; // Create an Aes object // with the specified key and IV. using (Aes aesAlg = Aes.Create()) { aesAlg.Key = Key; aesAlg.IV = IV; // Create a decrytor to perform the stream transform. ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV); // Create the streams used for encryption. using (MemoryStream msEncrypt = new MemoryStream()) { using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) { using (StreamWriter swEncrypt = new StreamWriter(csEncrypt)) { //Write all data to the stream. swEncrypt.Write(plainText); } encrypted = msEncrypt.ToArray(); } } } // Return the encrypted bytes from the memory stream. return encrypted; } static string DecryptStringFromBytes_Aes(byte[] cipherText, byte[] Key, byte[] IV) { // Check arguments. if (cipherText == null || cipherText.Length <= 0) throw new ArgumentNullException("cipherText"); if (Key == null || Key.Length <= 0) throw new ArgumentNullException("Key"); if (IV == null || IV.Length <= 0) throw new ArgumentNullException("Key"); // Declare the string used to hold // the decrypted text. string plaintext = null; // Create an Aes object // with the specified key and IV. using (Aes aesAlg = Aes.Create()) { aesAlg.Key = Key; aesAlg.IV = IV; // Create a decrytor to perform the stream transform. ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV); // Create the streams used for decryption. using (MemoryStream msDecrypt = new MemoryStream(cipherText)) { using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)) { using (StreamReader srDecrypt = new StreamReader(csDecrypt)) { // Read the decrypted bytes from the decrypting stream // and place them in a string. plaintext = srDecrypt.ReadToEnd(); } } } } return plaintext; } } }
I've been using the accepted answer by Mark Brittingham and its has helped me a lot. Recently I had to send encrypted text to a different organization and that's where some issues came up. The OP does not require these options but since this is a popular question I'm posting my modification ( Encrypt
and Decrypt
functions borrowed from here ):
- Different IV for every message – Concatenates IV bytes to the cipher bytes before obtaining the hex. Of course this is a convention that needs to be conveyed to the parties receiving the cipher text.
- Allows two constructors – one for default
RijndaelManaged
values, and one where property values can be specified (based on mutual agreement between encrypting and decrypting parties)
Here is the class (test sample at the end):
/// <summary> /// Based on https://msdn.microsoft.com/en-us/library/system.security.cryptography.rijndaelmanaged(v=vs.110).aspx /// Uses UTF8 Encoding /// http://security.stackexchange.com/a/90850 /// </summary> public class AnotherAES : IDisposable { private RijndaelManaged rijn; /// <summary> /// Initialize algo with key, block size, key size, padding mode and cipher mode to be known. /// </summary> /// <param name="key">ASCII key to be used for encryption or decryption</param> /// <param name="blockSize">block size to use for AES algorithm. 128, 192 or 256 bits</param> /// <param name="keySize">key length to use for AES algorithm. 128, 192, or 256 bits</param> /// <param name="paddingMode"></param> /// <param name="cipherMode"></param> public AnotherAES(string key, int blockSize, int keySize, PaddingMode paddingMode, CipherMode cipherMode) { rijn = new RijndaelManaged(); rijn.Key = Encoding.UTF8.GetBytes(key); rijn.BlockSize = blockSize; rijn.KeySize = keySize; rijn.Padding = paddingMode; rijn.Mode = cipherMode; } /// <summary> /// Initialize algo just with key /// Defaults for RijndaelManaged class: /// Block Size: 256 bits (32 bytes) /// Key Size: 128 bits (16 bytes) /// Padding Mode: PKCS7 /// Cipher Mode: CBC /// </summary> /// <param name="key"></param> public AnotherAES(string key) { rijn = new RijndaelManaged(); byte[] keyArray = Encoding.UTF8.GetBytes(key); rijn.Key = keyArray; } /// <summary> /// Based on https://msdn.microsoft.com/en-us/library/system.security.cryptography.rijndaelmanaged(v=vs.110).aspx /// Encrypt a string using RijndaelManaged encryptor. /// </summary> /// <param name="plainText">string to be encrypted</param> /// <param name="IV">initialization vector to be used by crypto algorithm</param> /// <returns></returns> public byte[] Encrypt(string plainText, byte[] IV) { if (rijn == null) throw new ArgumentNullException("Provider not initialized"); // Check arguments. if (plainText == null || plainText.Length <= 0) throw new ArgumentNullException("plainText cannot be null or empty"); if (IV == null || IV.Length <= 0) throw new ArgumentNullException("IV cannot be null or empty"); byte[] encrypted; // Create a decrytor to perform the stream transform. using (ICryptoTransform encryptor = rijn.CreateEncryptor(rijn.Key, IV)) { // Create the streams used for encryption. using (MemoryStream msEncrypt = new MemoryStream()) { using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) { using (StreamWriter swEncrypt = new StreamWriter(csEncrypt)) { //Write all data to the stream. swEncrypt.Write(plainText); } encrypted = msEncrypt.ToArray(); } } } // Return the encrypted bytes from the memory stream. return encrypted; }//end EncryptStringToBytes /// <summary> /// Based on https://msdn.microsoft.com/en-us/library/system.security.cryptography.rijndaelmanaged(v=vs.110).aspx /// </summary> /// <param name="cipherText">bytes to be decrypted back to plaintext</param> /// <param name="IV">initialization vector used to encrypt the bytes</param> /// <returns></returns> public string Decrypt(byte[] cipherText, byte[] IV) { if (rijn == null) throw new ArgumentNullException("Provider not initialized"); // Check arguments. if (cipherText == null || cipherText.Length <= 0) throw new ArgumentNullException("cipherText cannot be null or empty"); if (IV == null || IV.Length <= 0) throw new ArgumentNullException("IV cannot be null or empty"); // Declare the string used to hold the decrypted text. string plaintext = null; // Create a decrytor to perform the stream transform. using (ICryptoTransform decryptor = rijn.CreateDecryptor(rijn.Key, IV)) { // Create the streams used for decryption. using (MemoryStream msDecrypt = new MemoryStream(cipherText)) { using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)) { using (StreamReader srDecrypt = new StreamReader(csDecrypt)) { // Read the decrypted bytes from the decrypting stream and place them in a string. plaintext = srDecrypt.ReadToEnd(); } } } } return plaintext; }//end DecryptStringFromBytes /// <summary> /// Generates a unique encryption vector using RijndaelManaged.GenerateIV() method /// </summary> /// <returns></returns> public byte[] GenerateEncryptionVector() { if (rijn == null) throw new ArgumentNullException("Provider not initialized"); //Generate a Vector rijn.GenerateIV(); return rijn.IV; }//end GenerateEncryptionVector /// <summary> /// Based on https://stackoverflow.com/a/1344255 /// Generate a unique string given number of bytes required. /// This string can be used as IV. IV byte size should be equal to cipher-block byte size. /// Allows seeing IV in plaintext so it can be passed along a url or some message. /// </summary> /// <param name="numBytes"></param> /// <returns></returns> public static string GetUniqueString(int numBytes) { char[] chars = new char[62]; chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".ToCharArray(); byte[] data = new byte[1]; using (RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider()) { data = new byte[numBytes]; crypto.GetBytes(data); } StringBuilder result = new StringBuilder(numBytes); foreach (byte b in data) { result.Append(chars[b % (chars.Length)]); } return result.ToString(); }//end GetUniqueKey() /// <summary> /// Converts a string to byte array. Useful when converting back hex string which was originally formed from bytes. /// </summary> /// <param name="hex"></param> /// <returns></returns> public static byte[] StringToByteArray(String hex) { int NumberChars = hex.Length; byte[] bytes = new byte[NumberChars / 2]; for (int i = 0; i < NumberChars; i += 2) bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16); return bytes; }//end StringToByteArray /// <summary> /// Dispose RijndaelManaged object initialized in the constructor /// </summary> public void Dispose() { if (rijn != null) rijn.Dispose(); }//end Dispose() }//end class
and..
Here is the test sample:
class Program { string key; static void Main(string[] args) { Program p = new Program(); //get 16 byte key (just demo - typically you will have a predetermined key) p.key = AnotherAES.GetUniqueString(16); string plainText = "Hello World!"; //encrypt string hex = p.Encrypt(plainText); //decrypt string roundTrip = p.Decrypt(hex); Console.WriteLine("Round Trip: {0}", roundTrip); } string Encrypt(string plainText) { Console.WriteLine("\nSending (encrypt side)..."); Console.WriteLine("Plain Text: {0}", plainText); Console.WriteLine("Key: {0}", key); string hex = string.Empty; string ivString = AnotherAES.GetUniqueString(16); Console.WriteLine("IV: {0}", ivString); using (AnotherAES aes = new AnotherAES(key)) { //encrypting side byte[] IV = Encoding.UTF8.GetBytes(ivString); //get encrypted bytes (IV bytes prepended to cipher bytes) byte[] encryptedBytes = aes.Encrypt(plainText, IV); byte[] encryptedBytesWithIV = IV.Concat(encryptedBytes).ToArray(); //get hex string to send with url //this hex has both IV and ciphertext hex = BitConverter.ToString(encryptedBytesWithIV).Replace("-", ""); Console.WriteLine("sending hex: {0}", hex); } return hex; } string Decrypt(string hex) { Console.WriteLine("\nReceiving (decrypt side)..."); Console.WriteLine("received hex: {0}", hex); string roundTrip = string.Empty; Console.WriteLine("Key " + key); using (AnotherAES aes = new AnotherAES(key)) { //get bytes from url byte[] encryptedBytesWithIV = AnotherAES.StringToByteArray(hex); byte[] IV = encryptedBytesWithIV.Take(16).ToArray(); Console.WriteLine("IV: {0}", System.Text.Encoding.Default.GetString(IV)); byte[] cipher = encryptedBytesWithIV.Skip(16).ToArray(); roundTrip = aes.Decrypt(cipher, IV); } return roundTrip; } }
Using TripleDESCryptoServiceProvider in System.Security.Cryptography :
public static class CryptoHelper { private const string Key = "MyHashString"; private static TripleDESCryptoServiceProvider GetCryproProvider() { var md5 = new MD5CryptoServiceProvider(); var key = md5.ComputeHash(Encoding.UTF8.GetBytes(Key)); return new TripleDESCryptoServiceProvider() { Key = key, Mode = CipherMode.ECB, Padding = PaddingMode.PKCS7 }; } public static string Encrypt(string plainString) { var data = Encoding.UTF8.GetBytes(plainString); var tripleDes = GetCryproProvider(); var transform = tripleDes.CreateEncryptor(); var resultsByteArray = transform.TransformFinalBlock(data, 0, data.Length); return Convert.ToBase64String(resultsByteArray); } public static string Decrypt(string encryptedString) { var data = Convert.FromBase64String(encryptedString); var tripleDes = GetCryproProvider(); var transform = tripleDes.CreateDecryptor(); var resultsByteArray = transform.TransformFinalBlock(data, 0, data.Length); return Encoding.UTF8.GetString(resultsByteArray); } }
I think this is the worlds simplest one !
string encrypted = "Text".Aggregate("", (c, a) => c + (char) (a + 2));
testing
Console.WriteLine(("Hello").Aggregate("", (c, a) => c + (char) (a + 1))); //Output is Ifmmp Console.WriteLine(("Ifmmp").Aggregate("", (c, a) => c + (char)(a - 1))); //Output is Hello