我怀疑两年后你会回来接受答案,但是我只是按照你的要求做了,我认为这是一个相当普遍的问题,所以我发布这个是为了其他可能遇到的人的利益这个问题。
我将 GregS 的信息整合到我的实施中。为了您的特定目的,您可以将 Initialize 方法设为您的构造函数,去掉 net & diffie-hellman 代码,并将您的预共享密钥分配给 Aes 对象(而不是生成的密钥)。
请注意,我使用的是 AES256,尽管它已被损害为与 AES128 具有相似的强度(如果您的密钥由于实施不当而相关,我不知道)。如果您不相信 NIST 知道 NSA 是否在弄乱他们的规范,那么请不要使用 AES。
另外,这是一个起点!我正在解决在 .NET 中通过 NetworkStream 发送加密数据的常见问题!
112 行或更少,废话不多说:
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Security.Cryptography;
namespace FullDuplexCrypto
{
class CryptoNetworkStream : Stream
{
public CryptoNetworkStream(IPAddress address, int port)
{
Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
socket.Connect(address, port);
//socket.NoDelay = true;
Initialize(new NetworkStream(socket, true));
}
public CryptoNetworkStream(Socket socket)
{
Initialize(new NetworkStream(socket, true));
}
private void Initialize(Stream stream)
{
underlyer = stream;
using(ECDiffieHellmanCng dh = new ECDiffieHellmanCng())
{
dh.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
dh.HashAlgorithm = CngAlgorithm.Sha256;
byte[] buffer = dh.PublicKey.ToByteArray();
underlyer.Write(buffer, 0, buffer.Length);
underlyer.Read(buffer, 0, buffer.Length);
using(Aes aes = Aes.Create())
{
aes.KeySize = 256;
aes.Key = dh.DeriveKeyMaterial(CngKey.Import(buffer, CngKeyBlobFormat.EccPublicBlob));
aes.FeedbackSize = 8;
aes.Mode = CipherMode.CFB;
underlyer.Write(aes.IV, 0, aes.IV.Length);
encrypter = new CryptoStream(underlyer, aes.CreateEncryptor(), CryptoStreamMode.Write);
underlyer.Read(aes.IV, 0, aes.IV.Length);
decrypter = new CryptoStream(underlyer, aes.CreateDecryptor(), CryptoStreamMode.Read);
}
}
}
private Stream underlyer;
private Stream encrypter;
private Stream decrypter;
public override bool CanRead { get { return decrypter.CanRead; } }
public override bool CanWrite { get { return encrypter.CanWrite; } }
public override bool CanSeek { get { return underlyer.CanSeek; } }
public override long Length { get { return underlyer.Length; } }
public override long Position { get { return underlyer.Position; } set { underlyer.Position = value; } }
public override void Flush()
{
encrypter.Flush();
}
public override int Read(byte[] buffer, int offset, int count)
{
return decrypter.Read(buffer, offset, count);
}
public override void Write(byte[] buffer, int offset, int count)
{
encrypter.Write(buffer, offset, count);
}
public override long Seek(long offset, SeekOrigin origin)
{
return underlyer.Seek(offset, origin);
}
public override void SetLength(long value)
{
underlyer.SetLength(value);
}
private bool isDisposed = false;
protected override void Dispose(bool isDisposing)
{
if(!isDisposed)
{
if(isDisposing)
{
// Release managed resources.
encrypter.Dispose();
decrypter.Dispose();
underlyer.Dispose();
}
// Release unmanaged resources.
isDisposed = true;
}
base.Dispose(isDisposing);
}
}
}