Simple insecure two-way “obfuscation” for C#
我在为一些数据寻找非常简单的混淆(比如加密和解密,但不一定是安全的)功能。这不是关键任务。我需要一些东西来保持诚实的人诚实,但比ROT13或BASE64强一点。
我更喜欢已经包含在.NET Framework 2.0中的内容,因此我不必担心任何外部依赖关系。
我真的不想乱弄公共/私人密钥等。我对加密不太了解,但我知道的足够多,我写的任何东西都不会一文不值……事实上,我可能会把数学搞砸,让它变得微不足道。
这里的其他答案也可以,但是AES是一种更安全和最新的加密算法。这是我几年前获得的用于执行AES加密的类,随着时间的推移,我对它进行了修改,以便对Web应用程序更友好(例如,我构建了使用URL友好字符串的加密/解密方法)。它还具有处理字节数组的方法。
注意:您应该在键(32字节)和向量(16字节)数组中使用不同的值!您不希望有人通过假设您按原样使用此代码来计算您的密钥!您所要做的就是更改键和向量数组中的一些数字(必须小于等于255)(我在向量数组中留下了一个无效值,以确保您执行此操作…)。您可以使用https://www.random.org/bytes/轻松生成新集合:
- 生成
Key 。 - 生成
Vector 。
使用它很简单:只需实例化类,然后(通常)调用encryptToString(StringStringToEncrypt)和decryptString(StringStringToDecrypt)作为方法。一旦你有了这个课程,它就变得更容易(或更安全)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | 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; } } |
我把单工(上图)清理干净以备使用。固定的卷积加密/解密方法;用于编码字节缓冲区、字符串和对URL友好的字符串的分离方法;使用现有库进行URL编码。
代码小,简单,速度快,输出更简洁。例如,
1 2 | SimpleAES:"096114178117140150104121138042115022037019164188092040214235183167012211175176167001017163166152" SimplerAES:"YHKydYyWaHmKKnMWJROkvFwo1uu3pwzTr7CnARGjppg%3d" |
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | 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(); } } |
是的,添加
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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); |
我只是想补充一下,我已经改进了Mud的单纯形,增加了一个随机的IV,它在加密字符串中传递回来。这改进了加密,因为每次加密相同的字符串都会导致不同的输出。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | 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(); } } |
和奖励单元测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | [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编码代码以简化示例。
- 添加一个简单的测试夹具来演示用法
希望这有帮助
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | [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(); } } } |
[编辑]几年后,我回来说:不要这样做!看到XOR加密有什么问题吗?详情。
一个非常简单,简单的双向加密是XOR加密。
我把我从几个答案和评论中发现的最好的结合起来。
- 加密文本前的随机初始化向量(@jbtule)
- 使用transformFinalBlock()而不是memoryStream(@renniepet)
- 没有预先填充的密钥以避免任何人复制和粘贴灾难
- 正确处置和使用模式
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | /// <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的注释修复了private encrypt()方法中的错误。IV被意外地加密了,现在按decrypt()的预期以明文形式预先结束。
如果您只想简单加密(即,一个确定的解密程序可能会中断,但会锁定大多数临时用户),只需选择两个长度相同的密码,比如:
1 2 | deoxyribonucleicacid while (x>0) { x-- }; |
和XOR您的数据与它们(如果需要,循环密码短语)(A)。例如:
1 2 3 | 1111-2222-3333-4444-5555-6666-7777 deoxyribonucleicaciddeoxyribonucle while (x>0) { x-- };while (x>0) { |
搜索二进制文件的人很可能认为DNA字符串是一个密钥,但他们不太可能认为C代码是与二进制文件一起保存的未初始化内存以外的任何东西。
(a)请记住,这是非常简单的加密,根据某些定义,可能根本不被视为加密(因为加密的目的是防止未经授权的访问,而不仅仅是增加访问难度)。当然,当有人拿着钢管站在钥匙架上时,即使是最强的加密也不安全。
如第一句所述,这是一种使偶然攻击者难以继续前进的手段。这类似于防止你家里的入室盗窃——你不需要让它牢不可破,你只需要让它比隔壁的房子更不容易怀孕即可:—)
我想发布我的解决方案,因为上面的任何一个解决方案都没有我的简单。告诉我你的想法:
1 2 3 4 5 6 7 8 9 10 11 | // 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))); } |
可选的
这假定用于加密值的服务器的machinekey与用于解密值的machinekey相同。如果需要,可以在web.config中指定一个静态machinekey,这样应用程序就可以解密/加密数据,而不管数据在哪里运行(例如,Development与Production Server)。可以按照这些说明生成静态机器密钥。
加密很容易:正如其他人指出的,System.Security.Cryptography命名空间中有一些类可以为您完成所有工作。使用它们,而不是任何本土解决方案。
但解密也很容易。您所面临的问题不是加密算法,而是保护对用于解密的密钥的访问。
我将使用以下解决方案之一:
DPAPI使用带当前用户作用域的ProtectedData类。这很容易,因为你不用担心钥匙。数据只能由同一个用户解密,因此不适合在用户或计算机之间共享数据。
DPAPI使用带localmachine作用域的ProtectedData类。适用于保护单个安全服务器上的配置数据。但是任何可以登录到机器的人都可以对其进行加密,所以除非服务器是安全的,否则没有任何好处。
任何对称算法。我通常使用静态对称算法.create()方法,如果我不关心使用的是什么算法(实际上它默认是rijndael)。在这种情况下,你需要以某种方式保护你的钥匙。例如,您可以用某种方式混淆它,并将其隐藏在代码中。但是请注意,任何聪明到可以对代码进行反编译的人都有可能找到密钥。
在使用tripledescryptoserviceprovider system.security.cryptography:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 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); } } |
命名空间
别忘了添加对
使用内置的.NET密码库,本例演示如何使用高级加密标准(AES)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | 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; } } } |
我改变了这个:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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; } |
对此:
1 2 3 4 5 6 7 | public string ByteArrToString(byte[] byteArr) { string temp =""; foreach (byte b in byteArr) temp += b.ToString().PadLeft(3, '0'); return temp; } |
我知道你说过你不在乎它有多安全,但是如果你选择了DES,你最好选择AES,它是最新的加密方法。
我一直在使用马克·布里廷汉姆的公认答案,它对我有很大帮助。最近我不得不将加密文本发送到另一个组织,这就是出现问题的地方。OP不需要这些选项,但由于这是一个常见的问题,我将发布我的修改(这里借用了
这是课程(结尾的测试样本):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | /// <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 |
并且…
这是测试样品:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | 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(" Sending (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(" Receiving (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; } } |
我认为这是世界上最简单的一个!
1 | string encrypted ="Text".Aggregate("", (c, a) => c + (char) (a + 2)); |
试验
1 2 3 4 | 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 |