Dot-Net

如何在底層 .NET 流之上創建雙向加密流?

  • December 5, 2013

我有一個 Stream 通過不安全的通道傳輸和接收數據。我有一個預先共享的秘密,通道的兩個端點都已經擁有(比如密碼)。

我想使用秘密和原始不安全流建構一個新流。我遇到的兩個問題是:

  • CryptoStream 是單向的:只讀或只寫。我可以在原始 Stream 之上創建*兩個流(一個讀取流和一個寫入流),但這是不可接受的。*我是否必須編寫一個包裝流來獲得我想要的東西?(即單個讀/寫流)
  • 據說 CryptoStream 以塊的形式工作,並且在塊完成之前可能不會向底層流寫入任何內容。理想情況下,我想寫入任意數量的數據並立即將其發送到底層流(加密)。

有沒有一種簡單的方法可以實現這一目標?我知道 SslStream,但它是針對私鑰/公鑰和證書量身定制的,而不是預先共享的機密。

我懷疑兩年後你會回來接受答案,但是我只是做了你所問的,我認為這是一個相當普遍的問題,所以我發布這個是為了其他可能遇到這個問題的人的利益。

我將 GregS 的資訊合併到我的實現中。對於您的特定目的,您可以將 Initialize 方法設為您的建構子,去掉 net & diffie-hellman 程式碼,並將您的預共享密鑰分配給 Aes 對象(而不是生成的密鑰)。

請注意,我使用的是 AES256,儘管它已被損害為與 AES128 具有相似的強度(如果您的密鑰由於實施不當而相關,我不知道)。如果你不相信 NIST 知道 NSA 是否在弄亂他們的規範,那麼不要使用 AES。

此外,這是一個起點!我正在解決通過 .NET 中的 NetworkStream 發送加密數據的常見問題!

在一百十二行或更少的內容中,事不宜遲:

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);
       }
   }
}

引用自:https://stackoverflow.com/questions/6717356