3 using System.Security.Cryptography;
5 namespace SharpCompress.Common.Zip
7 internal class WinzipAesCryptoStream : Stream
9 private const int BLOCK_SIZE_IN_BYTES = 16;
10 private readonly SymmetricAlgorithm cipher;
11 private readonly byte[] counter = new byte[BLOCK_SIZE_IN_BYTES];
12 private readonly Stream stream;
13 private readonly ICryptoTransform transform;
14 private int nonce = 1;
15 private byte[] counterOut = new byte[BLOCK_SIZE_IN_BYTES];
16 private bool isFinalBlock;
17 private long totalBytesLeftToRead;
18 private bool isDisposed;
20 internal WinzipAesCryptoStream(Stream stream, WinzipAesEncryptionData winzipAesEncryptionData, long length)
23 totalBytesLeftToRead = length;
25 cipher = CreateCipher(winzipAesEncryptionData);
27 var iv = new byte[BLOCK_SIZE_IN_BYTES];
28 transform = cipher.CreateEncryptor(winzipAesEncryptionData.KeyBytes, iv);
31 private SymmetricAlgorithm CreateCipher(WinzipAesEncryptionData winzipAesEncryptionData)
33 RijndaelManaged cipher = new RijndaelManaged();
34 cipher.BlockSize = BLOCK_SIZE_IN_BYTES * 8;
35 cipher.KeySize = winzipAesEncryptionData.KeyBytes.Length * 8;
36 cipher.Mode = CipherMode.ECB;
37 cipher.Padding = PaddingMode.None;
41 public override bool CanRead
46 public override bool CanSeek
51 public override bool CanWrite
56 public override long Length
58 get { throw new NotImplementedException(); }
61 public override long Position
63 get { throw new NotImplementedException(); }
64 set { throw new NotImplementedException(); }
67 protected override void Dispose(bool disposing)
76 //read out last 10 auth bytes
77 var ten = new byte[10];
78 stream.Read(ten, 0, 10);
83 public override void Flush()
85 throw new NotImplementedException();
88 public override int Read(byte[] buffer, int offset, int count)
90 if (totalBytesLeftToRead == 0)
94 int bytesToRead = count;
95 if (count > totalBytesLeftToRead)
97 bytesToRead = (int)totalBytesLeftToRead;
99 int read = stream.Read(buffer, offset, bytesToRead);
100 totalBytesLeftToRead -= read;
102 ReadTransformBlocks(buffer, offset, read);
107 private int ReadTransformOneBlock(byte[] buffer, int offset, int last)
111 throw new InvalidOperationException();
114 int bytesRemaining = last - offset;
115 int bytesToRead = (bytesRemaining > BLOCK_SIZE_IN_BYTES)
116 ? BLOCK_SIZE_IN_BYTES
119 // update the counter
120 Array.Copy(BitConverter.GetBytes(nonce++), 0, counter, 0, 4);
122 // Determine if this is the final block
123 if ((bytesToRead == bytesRemaining) && (totalBytesLeftToRead == 0))
125 counterOut = transform.TransformFinalBlock(counter,
127 BLOCK_SIZE_IN_BYTES);
132 transform.TransformBlock(counter,
139 XorInPlace(buffer, offset, bytesToRead);
144 private void XorInPlace(byte[] buffer, int offset, int count)
146 for (int i = 0; i < count; i++)
148 buffer[offset + i] = (byte)(counterOut[i] ^ buffer[offset + i]);
152 private void ReadTransformBlocks(byte[] buffer, int offset, int count)
155 int last = count + offset;
157 while (posn < buffer.Length && posn < last)
159 int n = ReadTransformOneBlock(buffer, posn, last);
165 public override long Seek(long offset, SeekOrigin origin)
167 throw new NotImplementedException();
170 public override void SetLength(long value)
172 throw new NotImplementedException();
175 public override void Write(byte[] buffer, int offset, int count)
177 throw new NotImplementedException();