从CryptoStream正确读取字符串?

huangapple go评论85阅读模式
英文:

Read string from CryptoStream correctly?

问题

我尝试从文件中编写和读取字符串,使用以下代码进行**写入**:

```csharp
...
Aes aes = Aes.Create();
aes.KeySize = 256;
aes.BlockSize = 128;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(passwordBytes, salt, 185000, HashAlgorithmName.SHA512);
aes.Key = key.GetBytes(aes.KeySize / 8);
aes.IV = key.GetBytes(aes.BlockSize / 8);
createstream.Write(salt, 0, salt.Length);

using (DeflateStream compresstream = new DeflateStream(createstream, CompressionLevel.Optimal))
{
    using (CryptoStream cryptostream = new CryptoStream(compresstream, aes.CreateEncryptor(), CryptoStreamMode.Write))
    {
        byte[] str = Encoding.UTF8.GetBytes("TestString")!;
        byte[] strl = BitConverter.GetBytes(str.Length);
        cryptostream.Write(strl, 0, 4);
        cryptostream.Write(str, 0, str.Length);

        byte[] str1 = Encoding.UTF8.GetBytes("TestString2")!;
        byte[] strl1 = BitConverter.GetBytes(str1.Length);
        cryptostream.Write(strl1, 0, 4);
        cryptostream.Write(str1, 0, str1.Length);
    }
}

以及用于读取的代码:

...
readstream.Read(salt, 0, salt.Length);
...
Aes aes = Aes.Create();
aes.KeySize = 256;
aes.BlockSize = 128;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(passwordBytes, salt, 185000, HashAlgorithmName.SHA512);
aes.Key = key.GetBytes(aes.KeySize / 8);
aes.IV = key.GetBytes(aes.BlockSize / 8);

using (DeflateStream decompresstream = new DeflateStream(readstream, CompressionMode.Decompress))
{
    using (CryptoStream decryptostream = new CryptoStream(decompresstream, aes.CreateDecryptor(), CryptoStreamMode.Read))
    {
        byte[] str = new byte[4];
        decryptostream.Read(str, 0, str.Length);
        int size = BitConverter.ToInt32(str, 0);
        byte[] strl = new byte[size];
        decryptostream.Read(strl, 0, size);
        string result = Encoding.UTF8.GetString(strl);

        byte[] str1 = new byte[4];
        decryptostream.Read(str1, 0, str1.Length);
        int size1 = BitConverter.ToInt32(str1, 0);
        byte[] strl1 = new byte[size1];
        decryptostream.Read(strl1, 0, size1);
        string result1 = Encoding.UTF8.GetString(strl1);

        Console.WriteLine($"字符串:{result} {result1}");

        Console.ReadLine();
    }
}

我的问题是...在读取后,我得到这个结果:字符串:TestString TestStrin。为什么 CryptoStream 截断了我的字符串?

如果我写入数字,CryptoStream 可以正确读取所有内容。如何正确使用 CryptoStream 写入或读取字符串?


<details>
<summary>英文:</summary>

I try write and read back string from file. Use this code for the **write**:

...
Aes aes = Aes.Create();
aes.KeySize = 256;
aes.BlockSize = 128;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(passwordBytes, salt, 185000, HashAlgorithmName.SHA512);
aes.Key = key.GetBytes(aes.KeySize / 8);
aes.IV = key.GetBytes(aes.BlockSize / 8);
createstream.Write(salt, 0, salt.Length);

            using (DeflateStream compresstream = new DeflateStream(createstream, CompressionLevel.Optimal))
            {
                using (CryptoStream cryptostream = new CryptoStream(compresstream, aes.CreateEncryptor(), CryptoStreamMode.Write))
                {
                    byte[] str = Encoding.UTF8.GetBytes(&quot;TestString&quot;)!;
                    byte[] strl = BitConverter.GetBytes(str.Length);
                    cryptostream.Write(strl, 0, 4);
                    cryptostream.Write(str, 0, str.Length);

                    byte[] str1 = Encoding.UTF8.GetBytes(&quot;TestString2&quot;)!;
                    byte[] strl1 = BitConverter.GetBytes(str1.Length);
                    cryptostream.Write(strl1, 0, 4);
                    cryptostream.Write(str1, 0, str1.Length);
                }
            }
And this for the **read** back:

...
readstream.Read(salt, 0, salt.Length);
...
Aes aes = Aes.Create();
aes.KeySize = 256;
aes.BlockSize = 128;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(passwordBytes, salt, 185000, HashAlgorithmName.SHA512);
aes.Key = key.GetBytes(aes.KeySize / 8);
aes.IV = key.GetBytes(aes.BlockSize / 8);

            using (DeflateStream decompresstream = new DeflateStream(readstream, CompressionMode.Decompress))
            {
                using (CryptoStream decryptostream = new CryptoStream(decompresstream, aes.CreateDecryptor(), CryptoStreamMode.Read))
                {
                    byte[] str = new byte[4];
                    decryptostream.Read(str, 0, str.Length);
                    int size = BitConverter.ToInt32(str, 0);
                    byte[] strl = new byte[size];
                    decryptostream.Read(strl, 0, size);
                    string result = Encoding.UTF8.GetString(strl);

                    byte[] str1 = new byte[4];
                    decryptostream.Read(str1, 0, str1.Length);
                    int size1 = BitConverter.ToInt32(str1, 0);
                    byte[] strl1 = new byte[size1];
                    decryptostream.Read(strl1, 0, size1);
                    string result1 = Encoding.UTF8.GetString(strl1);

                    Console.WriteLine($&quot;String: {result} {result1}&quot;);

                    Console.ReadLine();
                }
            }
My problem is...after reading back, i get this result: String: **TestString TestStrin**. Why cryptostream is cut my string?


If i write the digits, the CryptoStream is read correctly for all. How to right write or read string correctly use **CryptoStream**?

</details>


# 答案1
**得分**: 1

尝试切换到[`ReadExactly`][1](自 [tag:.net-7.0] 起可用)而不是使用`Read`:

```csharp
using (DeflateStream decompresstream = new DeflateStream(readstream, CompressionMode.Decompress))
using (CryptoStream decryptostream =
       new CryptoStream(decompresstream, aes.CreateDecryptor(), CryptoStreamMode.Read))
{
    byte[] str = new byte[4];
    decryptostream.ReadExactly(str, 0, str.Length);
    int size = BitConverter.ToInt32(str, 0);
    byte[] strl = new byte[size];
    decryptostream.ReadExactly(strl, 0, strl.Length);
    string result = Encoding.UTF8.GetString(strl);

    byte[] str1 = new byte[4];
    decryptostream.ReadExactly(str1, 0, str1.Length);
    int size1 = BitConverter.ToInt32(str1, 0);
    byte[] strl1 = new byte[size1];
    decryptostream.ReadExactly(strl1, 0, strl1.Length);
        
    string result1 = Encoding.UTF8.GetString(strl1);

    Console.WriteLine($&quot;String: {result} {result1}&quot;);
}

如果您使用较早版本,则需要自己实现,例如通过while循环。大致如下:

public static class StreamExts
{
	public static void ReadExactlyOrTillEnd(this Stream stream, byte[] buffer)
	{
		if (buffer.Length == 0)
		{
			return;
		}

		var read = -1;
		var total = 0;
		while (total &lt; buffer.Length &amp;&amp; read != 0)
		{
			read = stream.Read(buffer, total, buffer.Length - total);
			total += read;
		}
	}
}

阅读更多:

英文:

Try switching to ReadExactly (available since [tag:.net-7.0]) from Read:

using (DeflateStream decompresstream = new DeflateStream(readstream, CompressionMode.Decompress))
using (CryptoStream decryptostream =
       new CryptoStream(decompresstream, aes.CreateDecryptor(), CryptoStreamMode.Read))
{
    byte[] str = new byte[4];
    decryptostream.ReadExactly(str, 0, str.Length);
    int size = BitConverter.ToInt32(str, 0);
    byte[] strl = new byte[size];
    decryptostream.ReadExactly(strl, 0, strl.Length);
    string result = Encoding.UTF8.GetString(strl);

    byte[] str1 = new byte[4];
    decryptostream.ReadExactly(str1, 0, str1.Length);
    int size1 = BitConverter.ToInt32(str1, 0);
    byte[] strl1 = new byte[size1];
    decryptostream.ReadExactly(strl1, 0, strl1.Length);
        
    string result1 = Encoding.UTF8.GetString(strl1);

    Console.WriteLine($&quot;String: {result} {result1}&quot;);
}

If you are running earlier version then you will need to implement it yourself for example via while cycle. Something along these lines:

public static class StreamExts
{
	public static void ReadExactlyOrTillEnd(this Stream stream, byte[] buffer)
	{
		if (buffer.Length == 0)
		{
			return;
		}

		var read = -1;
		var total = 0;
		while (total &lt; buffer.Length &amp;&amp; read != 0)
		{
			read = stream.Read(buffer, total, buffer.Length - total);
			total += read;
		}
	}
}

Read more:

huangapple
  • 本文由 发表于 2023年7月18日 00:15:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/76706353.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定