我正在为一些数据寻找非常简单的混淆(比如加密和解密,但不一定安全)功能。这不是关键任务。我需要一些东西来保持诚实的人诚实,但比ROT13或Base64更强大一点。
我更喜欢一些已经包含在. net框架2.0中的东西,这样我就不必担心任何外部依赖。
我真的不想在公钥/私钥等方面浪费时间。我不太懂加密,但我知道我写的任何东西都是没有价值的……事实上,我可能会把数学搞砸,让它变得微不足道。
我正在为一些数据寻找非常简单的混淆(比如加密和解密,但不一定安全)功能。这不是关键任务。我需要一些东西来保持诚实的人诚实,但比ROT13或Base64更强大一点。
我更喜欢一些已经包含在. net框架2.0中的东西,这样我就不必担心任何外部依赖。
我真的不想在公钥/私钥等方面浪费时间。我不太懂加密,但我知道我写的任何东西都是没有价值的……事实上,我可能会把数学搞砸,让它变得微不足道。
当前回答
我一直在使用Mark Brittingham的公认答案,它对我帮助很大。最近,我不得不向另一个组织发送加密文本,这就出现了一些问题。OP不需要这些选项,但由于这是一个流行的问题,我发布了我的修改(加密和解密函数从这里借来):
每条消息都有不同的IV -在获得十六进制之前将IV字节连接到密码字节。当然,这是一个需要传达给接收密文的各方的约定。 允许两个构造函数——一个用于默认的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;
}
}
其他回答
我知道你说过你不关心它有多安全,但如果你选择DES,你也可以选择AES,这是最新的加密方法。
只是想补充一下,我已经改进了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()前置。
命名空间System.Security.Cryptography包含TripleDESCryptoServiceProvider类和RijndaelManaged类
不要忘记添加对系统的引用。安全大会。
我清理了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();
}
}