我正在为一些数据寻找非常简单的混淆(比如加密和解密,但不一定安全)功能。这不是关键任务。我需要一些东西来保持诚实的人诚实,但比ROT13或Base64更强大一点。
我更喜欢一些已经包含在. net框架2.0中的东西,这样我就不必担心任何外部依赖。
我真的不想在公钥/私钥等方面浪费时间。我不太懂加密,但我知道我写的任何东西都是没有价值的……事实上,我可能会把数学搞砸,让它变得微不足道。
我正在为一些数据寻找非常简单的混淆(比如加密和解密,但不一定安全)功能。这不是关键任务。我需要一些东西来保持诚实的人诚实,但比ROT13或Base64更强大一点。
我更喜欢一些已经包含在. net框架2.0中的东西,这样我就不必担心任何外部依赖。
我真的不想在公钥/私钥等方面浪费时间。我不太懂加密,但我知道我写的任何东西都是没有价值的……事实上,我可能会把数学搞砸,让它变得微不足道。
当前回答
如果你只是想要简单的加密(即,一个坚定的破解者可能会破解,但会锁定大多数普通用户),只需选择两个长度相等的密码短语,例如:
deoxyribonucleicacid
while (x>0) { x-- };
和xor你的数据与他们(循环密码短语,如果需要)(a)。例如:
1111-2222-3333-4444-5555-6666-7777
deoxyribonucleicaciddeoxyribonucle
while (x>0) { x-- };while (x>0) {
搜索二进制文件的人很可能认为DNA字符串是一个密钥,但他们不太可能认为C代码是用二进制文件保存的未初始化内存。
(a)请记住,这是非常简单的加密,根据某些定义,可能根本不被认为是加密(因为加密的目的是防止未经授权的访问,而不仅仅是使其更加困难)。当然,即使是最强的加密也不安全因为有人拿着钢管站在钥匙持有人旁边。
正如第一句所述,这是一种让随意的攻击者变得足够困难的方法,他们会继续前进。这类似于防止入室盗窃——你不需要让它变得坚不可摧,你只需要让它比隔壁的房子不那么坚不可摧:-)
其他回答
我一直在使用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;
}
}
马克斯(优秀)答案的变体
添加“使用” 将类设置为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();
}
}
}
如果你只是想要简单的加密(即,一个坚定的破解者可能会破解,但会锁定大多数普通用户),只需选择两个长度相等的密码短语,例如:
deoxyribonucleicacid
while (x>0) { x-- };
和xor你的数据与他们(循环密码短语,如果需要)(a)。例如:
1111-2222-3333-4444-5555-6666-7777
deoxyribonucleicaciddeoxyribonucle
while (x>0) { x-- };while (x>0) {
搜索二进制文件的人很可能认为DNA字符串是一个密钥,但他们不太可能认为C代码是用二进制文件保存的未初始化内存。
(a)请记住,这是非常简单的加密,根据某些定义,可能根本不被认为是加密(因为加密的目的是防止未经授权的访问,而不仅仅是使其更加困难)。当然,即使是最强的加密也不安全因为有人拿着钢管站在钥匙持有人旁边。
正如第一句所述,这是一种让随意的攻击者变得足够困难的方法,他们会继续前进。这类似于防止入室盗窃——你不需要让它变得坚不可摧,你只需要让它比隔壁的房子不那么坚不可摧:-)
我清理了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();
}
}
多年后,我回来对他们说:不要这样做!看XOR加密有什么问题?获取详细信息。
一种非常简单的双向加密是异或加密。
Come up with a password. Let's have it be mypass. Convert the password into binary (according to ASCII). The password becomes 01101101 01111001 01110000 01100001 01110011 01110011. Take the message you want to encode. Convert that into binary, also. Look at the length of the message. If the message length is 400 bytes, turn the password into a 400 byte string by repeating it over and over again. It would become 01101101 01111001 01110000 01100001 01110011 01110011 01101101 01111001 01110000 01100001 01110011 01110011 01101101 01111001 01110000 01100001 01110011 01110011... (or mypassmypassmypass...) XOR the message with the long password. Send the result. Another time, XOR the encrypted message with the same password (mypassmypassmypass...). There's your message!