2011-02-17 28 views
6

我试图将CryptoStream与AWS .NET SDk一起使用,因为CryptoStream不支持seek。我知道内容长度已知的地方应该可以将这些功能添加到CryptoStream中。我想知道如何做到这一点;任何示例代码也会有用。如何将查找和定位功能添加到CryptoStream

我有一个像这样的方法与FieStream传递并返回一个cryptoStream。我将返回的Stream对象分配给AWS SDk PutObjectRequest对象的InputStream。

public static Stream GetEncryptStream(Stream existingStream, 
    SymmetricAlgorithm cryptoServiceProvider, 
    string encryptionKey, string encryptionIV) 
{ 
    Stream existingStream = this.dataStream; 

    cryptoServiceProvider.Key = ASCIIEncoding.ASCII.GetBytes(encryptionKey); 
    cryptoServiceProvider.IV = ASCIIEncoding.ASCII.GetBytes(encryptionIV); 
    CryptoStream cryptoStream = new CryptoStream(existingStream, 
     cryptoServiceProvider.CreateEncryptor(), CryptoStreamMode.Read); 

    return cryptoStream ; 
} 
+0

嗨,你能告诉我们你在做什么这么远?我相信如果你有一个流媒体阅读器链接到你的CryptoStream,那么你可以移动位置,并寻求... – 2011-02-17 08:30:05

回答

4

一般用加密还没有一个1:输入字节和输出字节之间的一对一映射,所以为了寻求向后(尤其是)它会做很多的工作 - 甚至直接回到开始处,并且前进处理数据以消耗来自解密的流的[n]个字节。即使它知道每个字节映射到的位置,加密的状态依赖于它之前的数据(它不是解码器环; p),所以再次 - 它必须从开始读取(和重置回初始化向量),或者它必须跟踪位置和密码状态的快照,并返回到最近的快照,然后向前走。大量的工作和存储。

这将适用于寻求相对于任何一端。

当前位置向前移动将不会太糟糕,但你又不得不过程数据 - 不只是跳基流的位置。

没有实现这一点,大多数消费者可以使用方式 - 通常,如果你从CanSeek,意思是“随机访问”一true,但效率不高在这种情况下。

解决方法 - 考虑将解密的数据复制到MemoryStream或文件;那么您可以以随机访问的方式访问完全解密的数据。

+0

只要记住将解密的数据复制到未加密的内存流或文件可以保持数据开放,以便更容易通过不那么好的窥探人们 – Justin808 2011-02-17 10:20:37

+0

@ Justin808显然,这取决于它是否打算被保护*在传输/存储*,或者甚至你自己的服务器是否被认为是敌对的/处于危险中...... – 2011-02-17 10:40:51

1

作为Mark Gravell的回答的扩展,密码的可搜索性取决于您用于密码的Mode Of Operation。大多数操作模式都是不可搜索的,因为每个密文块都以某种方式依赖于前一个密文。欧洲央行是可以追求的,但使用它几乎是个坏主意。 CTR模式是另一种可以随机访问的模式,就像CBC一样。

但是,所有这些模式都有其自身的漏洞,因此,在选择一种模式之前,您应该仔细阅读并认真思考并且认真思考(最好咨询专家)。

2

它非常简单,只需使用ECB或任何其他您喜欢的加密方法生成与数据流大小相同的长键(stream.Position),然后应用XOR。它是可搜索的,非常快速和1对1加密,其输出长度与输入长度完全相同。这是有效的内存,你可以在巨大的文件上使用它。我认为这种方法也用于现代WinZip AES加密。你必须小心的唯一的事情就是:SAL

使用独特的盐为每个数据流否则就没有加密。 我还没有测试过它,但请让我知道如果你认为它有问题。

public class SeekableAesStream : Stream 
{ 
    private Stream baseStream; 
    private AesManaged aes; 
    private ICryptoTransform encryptor; 
    public bool autoDisposeBaseStream { get; set; } = true; 

    /// <param name="salt">//** WARNING **: MUST be unique for each stream otherwise there is NO security</param> 
    public SeekableAesStream(Stream baseStream, string password, byte[] salt) 
    { 
     this.baseStream = baseStream; 
     using (var key = new PasswordDeriveBytes(password, salt)) 
     { 
      aes = new AesManaged(); 
      aes.KeySize = 128; 
      aes.Mode = CipherMode.ECB; 
      aes.Padding = PaddingMode.None; 
      aes.Key = key.GetBytes(aes.KeySize/8); 
      aes.IV = new byte[16]; //zero buffer is adequate since we have to use new salt for each stream 
      encryptor = aes.CreateEncryptor(aes.Key, aes.IV); 
     } 
    } 

    private void cipher(byte[] buffer, int offset, int count, long streamPos) 
    { 
     //find block number 
     var blockSizeInByte = aes.BlockSize/8; 
     var blockNumber = (streamPos/blockSizeInByte) + 1; 
     var keyPos = streamPos % blockSizeInByte; 

     //buffer 
     var outBuffer = new byte[blockSizeInByte]; 
     var nonce = new byte[blockSizeInByte]; 
     var init = false; 

     for (int i = offset; i < count; i++) 
     { 
      //encrypt the nonce to form next xor buffer (unique key) 
      if (!init || (keyPos % blockSizeInByte) == 0) 
      { 
       BitConverter.GetBytes(blockNumber).CopyTo(nonce, 0); 
       encryptor.TransformBlock(nonce, 0, nonce.Length, outBuffer, 0); 
       if (init) keyPos = 0; 
       init = true; 
       blockNumber++; 
      } 
      buffer[i] ^= outBuffer[keyPos]; //simple XOR with generated unique key 
      keyPos++; 
     } 
    } 

    public override bool CanRead { get { return baseStream.CanRead; } } 
    public override bool CanSeek { get { return baseStream.CanSeek; } } 
    public override bool CanWrite { get { return baseStream.CanWrite; } } 
    public override long Length { get { return baseStream.Length; } } 
    public override long Position { get { return baseStream.Position; } set { baseStream.Position = value; } } 
    public override void Flush() { baseStream.Flush(); } 
    public override void SetLength(long value) { baseStream.SetLength(value); } 
    public override long Seek(long offset, SeekOrigin origin) { return baseStream.Seek(offset, origin); } 

    public override int Read(byte[] buffer, int offset, int count) 
    { 
     var streamPos = Position; 
     var ret = baseStream.Read(buffer, offset, count); 
     cipher(buffer, offset, count, streamPos); 
     return ret; 
    } 

    public override void Write(byte[] buffer, int offset, int count) 
    { 
     cipher(buffer, offset, count, Position); 
     baseStream.Write(buffer, offset, count); 
    } 

    protected override void Dispose(bool disposing) 
    { 
     if (disposing) 
     { 
      encryptor?.Dispose(); 
      aes?.Dispose(); 
      if (autoDisposeBaseStream) 
       baseStream?.Dispose(); 
     } 

     base.Dispose(disposing); 
    } 
} 

用法:

static void test() 
    { 
     var buf = new byte[255]; 
     for (byte i = 0; i < buf.Length; i++) 
      buf[i] = i; 

     //encrypting 
     var uniqueSalt = new byte[16]; //** WARNING **: MUST be unique for each stream otherwise there is NO security 
     var baseStream = new MemoryStream(); 
     var cryptor = new SeekableAesStream(baseStream, "password", uniqueSalt); 
     cryptor.Write(buf, 0, buf.Length); 

     //decrypting at position 200 
     cryptor.Position = 200; 
     var decryptedBuffer = new byte[50]; 
     cryptor.Read(decryptedBuffer, 0, 50); 

    } 
相关问题