2014-07-01 60 views
4

我需要通過OFB模式下的加密消息從C#應用程序與另一個應用程序進行通信。我知道RijndaelManaged不支持AES OFB模式。有沒有人比我更有經驗知道使用OFB模式進行加密/解密的其他方式?用於RijndaelManaged的AES OFB加密

+0

您能否明確說明您的平臺要求?看起來有[4.5中實現的OFB模式](http://msdn.microsoft.com/en-us/library/system.security.cryptography.ciphermode.aspx) –

+0

請注意,您不需要提及標題中的語言,但是你應該*使用標籤指示它。否則,遵循這些標籤的人將不會被通知他們。 –

+0

CipherMode.OFB適用於所有框架,我將「其他版本」更改爲「.NET Framework 1.1」,並列出了OFB。但是,當使用它時,我得到的錯誤類似於「指定的密碼模式對此算法無效」,我使用的VS 2013與目標框架設置爲「.NET Framework 4.5」 – user3794709

回答

1

以下流通過使用由零饋CBC密碼流生成的密鑰流來實現OFB。

public class OFBStream : Stream 
{ 
    private const int BLOCKS = 16; 
    private const int EOS = 0; // the goddess of dawn is found at the end of the stream 

    private Stream parent; 
    private CryptoStream cbcStream; 
    private CryptoStreamMode mode; 
    private byte[] keyStreamBuffer; 
    private int keyStreamBufferOffset; 
    private byte[] readWriteBuffer; 

    public OFBStream (Stream parent, SymmetricAlgorithm algo, CryptoStreamMode mode) 
    { 
     if (algo.Mode != CipherMode.CBC) 
      algo.Mode = CipherMode.CBC; 
     if (algo.Padding != PaddingMode.None) 
      algo.Padding = PaddingMode.None; 
     this.parent = parent; 
     this.cbcStream = new CryptoStream (new ZeroStream(), algo.CreateEncryptor(), CryptoStreamMode.Read); 
     this.mode = mode; 
     keyStreamBuffer = new byte[algo.BlockSize * BLOCKS]; 
     readWriteBuffer = new byte[keyStreamBuffer.Length]; 
    } 

    public override int Read (byte[] buffer, int offset, int count) 
    { 
     if (!CanRead) { 
      throw new NotSupportedException(); 
     } 

     int toRead = Math.Min (count, readWriteBuffer.Length); 
     int read = parent.Read (readWriteBuffer, 0, toRead); 
     if (read == EOS) 
      return EOS; 

     for (int i = 0; i < read; i++) { 
      // NOTE could be optimized (branches for each byte) 
      if (keyStreamBufferOffset % keyStreamBuffer.Length == 0) { 
       FillKeyStreamBuffer(); 
       keyStreamBufferOffset = 0; 
      } 

      buffer [offset + i] = (byte)(readWriteBuffer [i] 
       ^keyStreamBuffer [keyStreamBufferOffset++]); 
     } 

     return read; 
    } 

    public override void Write (byte[] buffer, int offset, int count) 
    { 
     if (!CanWrite) { 
      throw new NotSupportedException(); 
     } 

     int readWriteBufferOffset = 0; 
     for (int i = 0; i < count; i++) { 
      if (keyStreamBufferOffset % keyStreamBuffer.Length == 0) { 
       FillKeyStreamBuffer(); 
       keyStreamBufferOffset = 0; 
      } 

      if (readWriteBufferOffset % readWriteBuffer.Length == 0) { 
       parent.Write (readWriteBuffer, 0, readWriteBufferOffset); 
       readWriteBufferOffset = 0; 
      } 

      readWriteBuffer [readWriteBufferOffset++] = (byte)(buffer [offset + i] 
       ^keyStreamBuffer [keyStreamBufferOffset++]); 
     } 

     parent.Write (readWriteBuffer, 0, readWriteBufferOffset); 
    } 

    private void FillKeyStreamBuffer() 
    { 
     int read = cbcStream.Read (keyStreamBuffer, 0, keyStreamBuffer.Length); 
     // NOTE undocumented feature 
     // only works if keyStreamBuffer.Length % blockSize == 0 
     if (read != keyStreamBuffer.Length) 
      throw new InvalidOperationException ("Implementation error: could not read all bytes from CBC stream"); 
    } 

    public override bool CanRead { 
     get { return mode == CryptoStreamMode.Read; } 
    } 

    public override bool CanWrite { 
     get { return mode == CryptoStreamMode.Write; } 
    } 

    public override void Flush() 
    { 
     // should never have to be flushed, implementation empty 
    } 

    public override bool CanSeek { 
     get { return false; } 
    } 

    public override long Seek (long offset, System.IO.SeekOrigin origin) 
    { 
     throw new NotSupportedException(); 
    } 

    public override long Position { 
     get { throw new NotSupportedException(); } 
     set { throw new NotSupportedException(); } 
    } 

    public override long Length { 
     get { throw new NotSupportedException(); } 
    } 

    public override void SetLength (long value) 
    { 
     throw new NotSupportedException(); 
    } 

} 

其他類ZeroStream要求OFBStream

class ZeroStream : System.IO.Stream 
{ 
    public override int Read (byte[] buffer, int offset, int count) 
    { 
     for (int i = 0; i < count; i++) { 
      buffer [offset + i] = 0; 
     } 

     return count; 
    } 

    public override bool CanRead { 
     get { return true; } 
    } 

    ... the rest is not implemented 
} 

而且作爲我的測試向量你可以使用它:

// NIST CAVP test vector F.4.1: OFB-AES128.Encrypt from NIST SP 800-38A 

RijndaelManaged aes = new RijndaelManaged(); 
aes.Key = FromHex ("2b7e151628aed2a6abf7158809cf4f3c"); 
aes.IV = FromHex ("000102030405060708090A0B0C0D0E0F"); 
MemoryStream testVectorStream = new MemoryStream (FromHex (
    "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710")); 
OFBStream testOFBStream = new OFBStream (testVectorStream, aes, CryptoStreamMode.Read); 
MemoryStream cipherTextStream = new MemoryStream(); 
testOFBStream.CopyTo (cipherTextStream); 
Console.WriteLine (ToHex (cipherTextStream.ToArray())); 

注意,流處理還沒有已經完全測試(尚未)。

+0

對我的C#技能有任何意見都是值得歡迎的。這不是我的主要語言。請注意,並非所有參數在使用前都經過完全測試。 –

+0

謝謝你的工作,你介意提供一些關於如何使用這個新班級的代碼?如何調用它,傳遞Key,IV和明文,在我的情況下,所有這些都是byte []。 – user3794709

+0

你是如何相處的?如果你需要一個ToHex/FromHex實現,它從[這裏](http://stackoverflow.com/a/311179/589259)被盜,並重新命名。 –