英文:
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("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);
}
}
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($"String: {result} {result1}");
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($"String: {result} {result1}");
}
如果您使用较早版本,则需要自己实现,例如通过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 < buffer.Length && read != 0)
{
read = stream.Read(buffer, total, buffer.Length - total);
total += read;
}
}
}
阅读更多:
-
Stream.Read
:
> 返回:已读取到缓冲区的总字节数。如果当前不可用那么多字节,或者流的结尾已到达,则此数可能小于所请求的字节数,如果已达到流的结尾,则返回零(0)。
英文:
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($"String: {result} {result1}");
}
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 < buffer.Length && read != 0)
{
read = stream.Read(buffer, total, buffer.Length - total);
total += read;
}
}
}
Read more:
-
Stream.Read
:
> Returns: The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached. -
Partial and zero-byte reads in DeflateStream, GZipStream, and CryptoStream
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论