我正在现有的文件管理程序中实现本地加密。
我能找到的大部分示例代码,例如Microsoft's,演示了如何直接写入文件,但我需要做的是提供一个在程序中其他地方使用的流:
<body onload="startGame()">
<input type="text" name="Box" id="Box" value="" placeholder="Write whatever"/>
<button onclick="myGameArea.myFunction()">Submit</button>
</body>
我的问题在最后一行的注释中概述但是一个:如何将IV添加到CryptoStream的开头,这样它将是读取CryptoStream时返回的第一个X字节,给定控制时间实际上开始读取流并写入文件超出了我的代码范围?
答案 0 :(得分:4)
好的......既然你的问题很明显,那就是&#34;相当&#34;简单......遗憾的是,.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 => throw new NotImplementedException();
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;
}
}
}
答案 1 :(得分:1)
使用CryptoStream
在两个当地方之间进行通信并不是一个好的设计。您应该使用通用InputStream
或管道(用于进程间通信)。然后,您可以将MemoryStream
与IV CryptoStream
合并,然后返回组合。请参阅answer of xanatos了解如何执行此操作(如果需要,您可能仍需要填写Seek
功能。)
CryptoStream
只能处理密文。因为你需要更改接收器上的代码无论如何如果你想解密,你也可以重构为InputStream
。
如果您需要保留当前的设计,那么就有可用的黑客攻击。首先&#34;解密&#34; IV使用ECB模式而不填充。作为单个分组密码,始终成功,结果将是一个数据块 - 当使用CipherStream
加密时 - 再次变为IV。
步骤:
CipherStream
的密钥; CipherStream
; CipherStream
; 您需要创建一个InputStream
,它首先接收解密的IV(作为MemoryStream
),然后创建明文(作为FileStream
),以实现此目的。再次,also see the answer of xanatos如何做到这一点。或者参见例如this combiner和this HugeStream
关于好的&#39;堆栈溢出。然后使用组合流作为CipherInputStream
的源。
但不用说,像这样的黑客应该在很方便的情况下记录和删除。
注意:
OutputStream
通常对加密更有意义,设计可能还有其他问题。答案 2 :(得分:-1)
感谢那些花时间回答的人。最后我意识到我必须知道缓冲代码中的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 */