假设我们有一条与HMAC签名的消息,然后该消息和HMAC被加密,然后通过TCP套接字发送:
// endpoint info excluded
TcpClient client = new TcpClient();
var stream = client.GetStream();
// assume pre-shared keys are used and set at this point
AesManaged aes = new AesManaged();
var aesEncryptor = aes.CreateEncryptor();
CryptoStream aesStream = new CryptoStream(
stream, aesEncryptor, CryptoStreamMode.Write);
// assume pre-shared keys here too
HMACSHA256 mac = new HMACSHA256();
CryptoStream macStream = new CryptoStream(
aesStream, mac, CryptoStreamMode.Write);
// assume a message with actual data is written to the macStream
// which updates the hash of the HMAC and also pipes the message
// to the aesStream which encrypts the data and writes it to the
// TCP socket stream
byte[] message = new byte[1024];
macStream.Write(message, 0, message.Length);
macStream.FlushFinalBlock();
// flushing the final block of the macStream actually flushes the
// final block of the aesStream, so I get an error when trying to
// write the HMAC hash to the aesStream
aesStream.Write(mac.Hash, 0, mac.Hash.Length);
aesStream.FlushFinalBlock();
我抽象了很多代码,所以这不是一个有效的例子。我可以解决这个问题,我将数据写入两次,一次是HMAC.TransformBlock,再次是aesStream,但我想避免这种情况。有什么想法吗?
答案 0 :(得分:2)
如果您通过套接字发送数据(因为您可能容易填充oracle attacs),您真的应该在MAC之前执行加密以创建安全解决方案,尤其是。因此,尽管您的问题是有效的,但最好更改流的顺序。
答案 1 :(得分:2)
由于我正在处理类似的主题,我会在这里给出答案:
就像Maarten Bodewes所写,我建议你加密 - 然后MAC。
然后,您可以在FlushFinalBlock()
上执行aesStream
后编写HMAC-Bytes。
不要忘记处理CryptoStreams和Algorithms对象!
var stream = client.GetStream();
HMACSHA256 mac = new HMACSHA256();
CryptoStream macStream = new CryptoStream(stream, mac, CryptoStreamMode.Write);
AesManaged aes = new AesManaged();
var aesEncryptor = aes.CreateEncryptor();
CryptoStream aesStream = new CryptoStream(macStream, aesEncryptor, CryptoStreamMode.Write);
byte[] message = new byte[1024];
aesStream.Write(message, 0, message.Length);
aesStream.FlushFinalBlock();
//No need to FlushFinalBlock() on macStream, would throw
//Write HMAC here
stream.Write(mac.Hash, 0, mac.Hash.Length);
//Dispose
aesStream.Dispose();
aes.Dispose();
macStream.Dispose();
mac.Dispose();
答案 2 :(得分:0)
所以我放了一个似乎正在工作的黑客。我创建了一个名为ProtectedStream
的流包装类。这是要点:
public class ProtectedStream : Stream
{
private Stream stream;
public ProtectedStream(Stream stream)
{
if(stream == null)
throw new ArgumentNullException("stream");
this.stream = stream;
}
public override void Close()
{
this.stream.Close();
base.Close();
}
public override int Read(byte[] buffer, int offset, int count)
{
return this.stream.Read(buffer, offset, count);
}
public override void Write(byte[] buffer, int offset, int count)
{
this.stream.Write(buffer, offset, count);
}
// and continue overriding every other overridable Stream member
// in the same fashion
}
然后原始代码如下所示:
// assume pre-shared keys are used and set at this point
AesManaged aes = new AesManaged();
var aesEncryptor = aes.CreateEncryptor();
CryptoStream aesStream = new CryptoStream(
stream, aesEncryptor, CryptoStreamMode.Write);
// assume pre-shared keys here too
HMACSHA256 mac = new HMACSHA256();
CryptoStream macStream = new CryptoStream(
new ProtectedStream(aesStream), mac, CryptoStreamMode.Write);
请注意,aesStream
包含在ProtectedStream
内。这隐含了aesStream
来自CryptoStream
的{{1}}这一事实,因此当您在macStream
上致电FlushFinalBlock
时,它不会在macStream
上调用FlushFinalBlock
{1}}。