我正在一个现有的文件管理程序中实现本地加密。
我可以找到的许多示例代码,比如微软的,演示了如何直接写入文件,但我需要做的是提供一个在程序其他地方使用的流:
CryptoStream GetEncryptStream(string filename)
{
var rjndl = new RijndaelManaged();
rjndl.KeySize = 256;
rjndl.BlockSize = 256;
rjndl.Mode = CipherMode.CBC;
rjndl.Padding = PaddingMode.PKCS7;
// Open read stream of unencrypted source fileStream:
var fileStream = new FileStream(filename, FileMode.Open);
/* Get key and iv */
var transform = rjndl.CreateEncryptor(key, iv);
// CryptoStream in *read* mode:
var cryptoStream = new CryptoStream(fileStream, transform, CryptoStreamMode.Read);
/* What can I do here to insert the unencrypted IV at the start of the
stream so that the first X bytes returned by cryptoStream.Read are
the IV, before the bytes of the encrypted file are returned? */
return cryptoStream; // Return CryptoStream to be consumed elsewhere
}在最后一行的注释中概述了我的问题:如何将IV添加到CryptoStream的开头,以便它将是读取CryptoStream时返回的第一个X字节,考虑到何时实际开始读取流和写入文件的控制超出了我的代码范围?
发布于 2018-05-21 12:06:19
好的..。既然你的问题已经清楚了,这“相当”容易.遗憾的是,.NET没有包含一个类来合并两个Stream,但是我们可以轻松地创建它。MergedStream是一种只读的、向前式的多流合并.
你用的是:
var mergedStream = new MergedStream(new Stream[]
{
new MemoryStream(iv),
cryptoStream,
});现在..。当有人试图从MergedStream中读取时,首先将消耗包含IV的MemoryStream,然后使用cryptoStream。
public class MergedStream : Stream
{
private Stream[] streams;
private int position = 0;
private int currentStream = 0;
public MergedStream(Stream[] streams) => this.streams = streams;
public override bool CanRead => true;
public override bool CanSeek => false;
public override bool CanWrite => false;
public override long Length => streams.Sum(s => s.Length);
public override long Position
{
get => position;
set => throw new NotSupportedException();
}
public override void Flush()
{
}
public override int Read(byte[] buffer, int offset, int count)
{
if (streams == null)
{
throw new ObjectDisposedException(nameof(MergedStream));
}
if (currentStream >= streams.Length)
{
return 0;
}
int read;
while (true)
{
read = streams[currentStream].Read(buffer, offset, count);
position += read;
if (read != 0)
{
break;
}
currentStream++;
if (currentStream == streams.Length)
{
break;
}
}
return read;
}
public override long Seek(long offset, SeekOrigin origin)
=> throw new NotSupportedException();
public override void SetLength(long value)
=> throw new NotSupportedException();
public override void Write(byte[] buffer, int offset, int count)
=> throw new NotSupportedException();
protected override void Dispose(bool disposing)
{
try
{
if (disposing && streams != null)
{
for (int i = 0; i < streams.Length; i++)
{
streams[i].Close();
}
}
}
finally
{
streams = null;
}
}
}发布于 2018-05-21 11:14:50
使用CryptoStream在两个本地方之间进行通信并不是一个好的设计。您应该使用通用的InputStream或管道(用于进程间通信)。然后,您可以将IV的MemoryStream和CryptoStream组合起来,并返回组合。关于如何做到这一点,请参阅xanatos的回答 (如果需要的话,您可能仍然需要填写Seek功能)。
CryptoStream只能处理密文。由于您需要在接收端更改代码,如果您想解密,最好重构为InputStream。
如果您需要保持当前的设计,那么就有一个黑客可用。首先,使用欧洲央行模式“解密”IV,而不加填充。由于单个分组密码调用总是成功的,结果将是一个数据块--在使用CipherStream加密时--再次转化为IV。
步骤:
CipherStream的密钥;CipherStream;CipherStream加密“解密”IV;您将需要创建一个InputStream,它首先接收解密的IV (作为MemoryStream),然后是明文(作为FileStream),这样才是可行的。再说一遍,也请看xanatos的答案。介绍了如何做到这一点。或者,例如,在good ol‘StackOverflow上看到这个组合器和HugeStream。然后使用组合流作为CipherInputStream的源。
但是不用说,像这样的黑客应该在方便的时候就被记录下来并移除。
备注:
OutputStream通常对加密更有意义,设计中可能有其他错误。发布于 2018-05-21 11:50:54
感谢那些花时间回答的人。最后,我意识到我必须在缓冲代码中了解IV长度,没有办法绕过它,所以选择让它保持简单:
加密方法(伪码):
/* Get key and IV */
outFileStream.Write(IV); // Write IV to output stream
var transform = rijndaelManaged.CreateEncryptor(key, iv);
// CryptoStream in read mode:
var cryptoStream = new CryptoStream(inFileStream, transform, CryptoStreamMode.Read);
do
{
cryptoStream.Read(chunk, 0, blockSize); // Get and encrypt chunk
outFileStream.Write(chunk); // Write chunk
}
while (chunk.Length > 0)
/* Cleanup */解密方法(伪码):
/* Get key */
var iv = inFileStream.Read(ivLength); // Get IV from input stream
var transform = rijndaelManaged.CreateDecryptor(key, iv);
// CryptoStream in write mode:
var cryptoStream = new CryptoStream(outFileStream, transform, CryptoStreamMode.Write);
do
{
inFileStream.Read(chunk, 0, blockSize); // Get chunk
cryptoStream.Write(chunk); // Decrypt and write chunk
}
while (chunk.Length > 0)
/* Cleanup */https://stackoverflow.com/questions/50445749
复制相似问题