我正在尝试加密流并再次解密。加密时,我首先将salt和IV(8和16字节)存储到目标流中。解密时,我在调用CopyTo()的行中出现填充错误。该课程的完整来源可以在Gist。
中找到加密的相关代码段是:
// Set position to start of stream.
encryptedOutStream.Seek (0, SeekOrigin.Begin);
// Store the salt in the output stream. The salt is not a secret. Salt is used to generate different keys for identical passwords.
var keyInfo = GenerateKey (password);
encryptedOutStream.Write (keyInfo.Salt, 0, keyInfo.Salt.Length);
// Store the IV in the output stream. The IV is randomly generated if not set explicitly. It is not a secret and used to create
// different encrypted output for identical plaintext input when using CBC cipher mode.
encryptedOutStream.Write (aesAlgo.IV, 0, aesAlgo.IV.Length);
// Let the algorithm know our key.
aesAlgo.Key = keyInfo.Key;
// Get an encrypting ICryptoTransform interface from the algorithm.
using(var cryptoTransform = aesAlgo.CreateEncryptor ())
// Pump the input stream through a crypto stream wrapping a memory stream.
using(var encryptionStream = new CryptoStream(encryptedOutStream, cryptoTransform, CryptoStreamMode.Write))
{
plainInStream.CopyTo (encryptionStream);
}
和解密:
// Read the salt.
byte[] salt = new byte[8];
encryptedInStream.Read (salt, 0, 8);
// Read the IV.
byte[] iv = new byte[16];
encryptedInStream.Read (iv, 0, 16);
aesAlgo.IV = iv;
// Generate the key from the password and the salt.
var keyInfo = GenerateKey (password, salt);
aesAlgo.Key = keyInfo.Key;
// Get a decrypting ICryptoTransform interface from the algorithm.
using(var cryptoTransform = aesAlgo.CreateDecryptor ())
// Pump the input stream through a crypto stream wrapping a memory stream.
using(var decryptionStream = new CryptoStream(encryptedInStream, cryptoTransform, CryptoStreamMode.Read))
{
decryptionStream.CopyTo (decryptedOutStream);
}
答案 0 :(得分:0)
我怀疑涉及EncryptString
和DecryptString
方法的问题,特别是行:
encryptedString = Encoding.UTF8.GetString(encryptedOutStream.ToArray());
和
using (var encryptedInStream = new MemoryStream(Encoding.UTF8.GetBytes(s)))
实际上,此代码错误地尝试在密文上使用文本编码,密文是二进制数据。当二进制数据不是合法的UTF8序列,破坏密文并引入填充问题时,这将引入错误。相反,需要使用二进制编码方法(最简单的是,base64)。
要更正此问题,请将以上行更改为:
// change line 281:
// encryptedString = Encoding.UTF8.GetString(encryptedOutStream.ToArray());
// to:
encryptedString = Convert.ToBase64String(encryptedOutStream.ToArray());
// change line 251:
// using (var encryptedInStream = new MemoryStream(Encoding.UTF8.GetBytes(s)))
// to:
using (var encryptedInStream = new MemoryStream(Convert.FromBase64String(s)))
通过此更改,转换似乎有效。使用密码“password”加密然后解密明文“payload”的简单驱动程序将打印所需的输出:
string password = "password";
SymmetricCrypto c = new SymmetricCrypto();
string ct = c.EncryptString("payload", password);
Console.WriteLine(ct); // prints sLSZfzVQGCoML29... (ciphertext will vary)
string dt = c.DecryptString(ct, password);
Console.WriteLine(dt); // prints "payload"