[英]Why do I get an empty result when encrypting a string, even though I flushed the input stream?
我想通過 RijndaelManaged 加密一些字符串並獲得加密結果。 我想用 MemoryStream 來做。 但我得到了空字符串。 如果我使用Rijndael
class 而不是RijndaelManaged
,我會遇到同樣的問題。 我做錯了什么?
static string EncodeString(string text, byte[] key, byte[] iv) {
RijndaelManaged alg = new RijndaelManaged();
var encryptor = alg.CreateEncryptor(key, iv);
string encodedString = null;
using (var s = new MemoryStream())
using (var cs = new CryptoStream(s, encryptor, CryptoStreamMode.Write))
using (var sw = new StreamWriter(cs)) {
// encrypt the string
sw.Write(text);
sw.Flush();
cs.Flush();
s.Flush();
Console.WriteLine($"Stream position: {s.Position}"); // Oops... It is 0 still. Why?
// get encrypted string
var sr = new StreamReader(s);
s.Position = 0;
encodedString = sr.ReadToEnd(); // I get empty string here
}
return encodedString;
}
然后我使用這個方法:
RijndaelManaged alg = new RijndaelManaged();
alg.GenerateKey();
alg.GenerateIV();
var encodedString = EncodeString("Hello, Dev!", alg.Key, alg.IV); // I get empty string. Why?
您在這里有兩個問題:
問題 1:您嘗試在結果准備好之前讀取結果。 您需要先關閉 StreamWriter:
using (var s = new MemoryStream())
using (var cs = new CryptoStream(s, encryptor, CryptoStreamMode.Write))
using (var sw = new StreamWriter(cs)) {
// encrypt the string
sw.Write(text);
Console.WriteLine(s.ToArray().Length); // prints 0
sw.Close();
Console.WriteLine(s.ToArray().Length); // prints 16
...
}
但我為什么需要這個? 你沒有在我的代碼中看到所有這些Flush
語句嗎? 是的,但是 Rijndael 是一個塊 cypher。 它只能在讀取完整塊(或者您告訴它這是最后的部分塊)后加密一個塊。 Flush
允許將更多數據寫入 stream,因此加密器無法確定塊是否完整。
您可以通過明確告訴加密 stream 您已完成發送輸入來解決此問題。 參考實現通過使用嵌套的 using 語句關閉 StreamWriter(以及 CryptoStream)來實現這一點。 一旦 CryptoStream 關閉,它就會刷新最后一個塊。
using (var s = new MemoryStream())
using (var cs = new CryptoStream(s, encryptor, CryptoStreamMode.Write))
{
using (var sw = new StreamWriter(cs))
{
// encrypt the string
sw.Write(text);
}
Console.WriteLine(s.ToArray().Length); // prints 16
...
}
或者,正如 Jimi 在評論中提到的,您可以顯式調用FlushFinalBlock
。 此外,您可以通過將基本字符串顯式轉換為字節數組來跳過 StreamWriter:
using (var s = new MemoryStream())
using (var cs = new CryptoStream(s, encryptor, CryptoStreamMode.Write))
{
cs.Write(Encoding.UTF8.GetBytes(text));
cs.FlushFinalBlock();
Console.WriteLine(s.ToArray().Length); // prints 16
...
}
或者,正如 V.Lorz 在評論中提到的那樣,您可以將 CryptoStream 配置為隱式調用 FlushFinalBlock:
using (var s = new MemoryStream())
{
using (var cs = new CryptoStream(s, encryptor, CryptoStreamMode.Write))
{
cs.Write(Encoding.UTF8.GetBytes(text));
}
Console.WriteLine(s.ToArray().Length); // prints 16
...
}
問題 2:您嘗試將結果讀取為字符串。 加密不適用於字符串,它適用於字節 arrays。 因此,嘗試將結果讀取為 UTF-8 字符串將導致垃圾。
相反,例如,您可以使用生成的字節數組的 Base64 表示:
return Convert.ToBase64String(s.ToArray());
以下是應用了所有這些修復程序的代碼的工作小提琴:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.