简单的不安全双向数据“混淆”?

我正在为一些数据寻找非常简单的混淆(比如加密和解密,但不一定安全)功能。这不是关键任务。我需要一些让诚实的人保持诚实的东西,但要比ROT13Base64强一点。

我更喜欢已经包含在net框架2.0中的东西,所以我不必担心任何外部依赖。

我真的不想在公钥/私钥等方面浪费时间。我不太懂加密,但我知道我写的任何东西都是没有价值的……事实上,我可能会把数学搞砸,让它变得微不足道。

229035 次浏览

命名空间System.Security.Cryptography包含TripleDESCryptoServiceProviderRijndaelManaged

不要忘记添加对System.Security程序集的引用。

是的,添加System.Security程序集,导入System.Security.Cryptography命名空间。这是一个简单的对称(DES)算法加密的例子:

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);

如果你只是想要简单的加密(即,一个坚定的破解者可能会破解,但会锁定大多数普通用户),只需选择两个长度相等的密码短语,例如:

deoxyribonucleicacid
while (x>0) { x-- };

和xor你的数据与他们(循环密码短语,如果需要)(一)。例如:

1111-2222-3333-4444-5555-6666-7777
deoxyribonucleicaciddeoxyribonucle
while (x>0) { x-- };while (x>0) {

搜索二进制文件的人很可能认为DNA字符串是一个密钥,但他们不太可能认为C代码是用二进制文件保存的未初始化内存。


(一)请记住,这是非常简单加密,根据某些定义,可能根本不被认为是加密(因为加密的目的是防止未经授权的访问,而不仅仅是使其更加困难)。当然,即使是最强的加密也不安全因为有人拿着钢管站在钥匙持有人旁边。

正如第一句所述,这是一种让随意的攻击者变得足够困难的方法,他们会继续前进。这类似于防止入室盗窃——你不需要让它变得坚不可摧,你只需要让它比隔壁的房子不那么坚不可摧:-)

我知道你说你不关心它有多安全,但如果你选择DES,你也可以采用AES,它是最新的加密方法。

加密很简单:正如其他人指出的那样,在System.Security.Cryptography名称空间中有一些类可以为您完成所有工作。使用它们,而不是任何自制的解决方案。

但是解密也很容易。您遇到的问题不是加密算法,而是保护对用于解密的密钥的访问。

我会使用以下解决方案之一:

  • DPAPI使用ProtectedData类和CurrentUser作用域。这很简单,因为你不需要担心钥匙。数据只能由同一用户解密,因此不适合在用户或机器之间共享数据。

  • DPAPI使用具有LocalMachine作用域的ProtectedData类。适用于保护单个安全服务器上的配置数据。但任何能登录到机器上的人都能加密,所以除非服务器是安全的,否则没什么用。

  • 任意对称算法。如果我不关心使用什么算法(实际上默认是Rijndael),我通常使用静态的SymmetricAlgorithm.Create()方法。在这种情况下,您需要以某种方式保护您的密钥。例如,你可以以某种方式混淆它,并隐藏在你的代码中。但是要注意,任何聪明到可以反编译代码的人都有可能找到密钥。

这里的其他答案都可以,但AES是一种更安全、最新的加密算法。这是我几年前获得的一个类,用于执行AES加密,随着时间的推移,我已经对其进行了修改,以使其对web应用程序(例如,g)更加友好。我已经构建了加密/解密方法,用于url友好的字符串)。它还有处理字节数组的方法。

注意:你应该在Key(32字节)和Vector(16字节)数组中使用不同的值!您不会希望别人通过假设您按原样使用此代码来找出您的密钥!你所要做的就是改变Key和Vector数组中的一些数字(必须是<= 255)(我在Vector数组中留下了一个无效的值,以确保你这样做…)你可以使用https://www.random.org/bytes/很容易地生成一个新集合:

使用它很简单:只需实例化类,然后调用(通常)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;
}
}

[编辑]多年后,我回来说:不要这样做!详细信息见异或加密有什么问题?

一种非常简单的双向加密是异或加密。

  1. 想出一个密码。让它是mypass
  2. 将密码转换为二进制(根据ASCII)。密码变为01101101 01111001 01110000 01100001 01110011 01110011。
  3. 取您想要编码的消息。也把它转换成二进制。
  4. 看看信息的长度。如果消息长度为400字节,则通过反复重复将密码转换为400字节的字符串。它将变成01101101 01111001 01110000 01100001 01110011 01110011 0111101 01111001 0111110000 011111001 01110011 01110011 0111101 01111001 01110011…(或mypassmypassmypass...)
  5. 异或具有长密码的消息。
  6. 发送结果。
  7. 另一次,用相同的密码(mypassmypassmypass...) XOR加密的消息。
  8. 这是你的留言!

我修改了:

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;
}

我清理了SimpleAES(上图)供我使用。固定复杂的加密/解密方法;用于编码字节缓冲区、字符串和url友好字符串的分离方法;利用现有的库进行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();
}
}

马克斯(优秀)答案的变体

  • 添加“使用”
  • 将类设置为IDisposable
  • 删除URL编码代码以简化示例。
  • 添加一个简单的测试装置来演示使用方法

希望这能有所帮助

[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();
}
}
}

只是想补充一下,我已经改进了Mud的SimplerAES,通过添加一个随机IV,在加密字符串中传递回。这改进了加密,因为加密同一个字符串每次都会产生不同的输出。

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();
}
}

奖励单元测试

[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");
}

我把我从几个答案和评论中找到的最好的东西结合起来。

  • 加密文本前的随机初始化向量(@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注释中private Encrypt()方法的错误。IV被意外加密,现在以明文形式被Decrypt()前置。

我认为这是世界上最简单的一个!

string encrypted = "Text".Aggregate("", (c, a) => c + (char) (a + 2));

测试

 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

我想发布我的解决方案,因为上面的解决方案都不像我的那么简单。让我知道你的想法:

 // 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中指定一个静态MachineKey。配置,使您的应用程序可以解密/加密数据,而不管它在哪里运行(例如开发还是生产服务器)。你可以按照下面的说明生成一个静态机器密钥

使用内置的. net Cryptography库,本示例展示如何使用高级加密标准(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;


}
}
}

我一直在使用马克Brittingham接受的答案,它帮助了我很多。最近,我不得不向另一个组织发送加密文本,这就出现了一些问题。OP不需要这些选项,但由于这是一个流行的问题,我发布了我的修改(EncryptDecrypt函数借用在这里):

  1. 每条消息都有不同的IV -在获得十六进制之前将IV字节连接到密码字节。当然,这是一个需要传达给接收密文的各方的约定。
  2. 允许两个构造函数——一个用于默认的RijndaelManaged值,另一个用于指定属性值(基于加密和解密双方的共同协议)

下面是类(测试样本在最后):

/// <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

和. .

下面是测试示例:

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;
}
}

enter image description here

System.Security.Cryptography中使用TripleDESCryptoServiceProvider:

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);
}
}