Fix XMM scanning on Mac x86.
[mono.git] / mcs / class / System.IO.Compression / SharpCompress / Common / Zip / WinzipAesCryptoStream.cs
1 using System;
2 using System.IO;
3 using System.Security.Cryptography;
4
5 namespace SharpCompress.Common.Zip
6 {
7     internal class WinzipAesCryptoStream : Stream
8     {
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;
19
20         internal WinzipAesCryptoStream(Stream stream, WinzipAesEncryptionData winzipAesEncryptionData, long length)
21         {
22             this.stream = stream;
23             totalBytesLeftToRead = length;
24
25             cipher = CreateCipher(winzipAesEncryptionData);
26
27             var iv = new byte[BLOCK_SIZE_IN_BYTES];
28             transform = cipher.CreateEncryptor(winzipAesEncryptionData.KeyBytes, iv);
29         }
30
31         private SymmetricAlgorithm CreateCipher(WinzipAesEncryptionData winzipAesEncryptionData)
32         {
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;
38             return cipher;
39         }
40
41         public override bool CanRead
42         {
43             get { return true; }
44         }
45
46         public override bool CanSeek
47         {
48             get { return false; }
49         }
50
51         public override bool CanWrite
52         {
53             get { return false; }
54         }
55
56         public override long Length
57         {
58             get { throw new NotImplementedException(); }
59         }
60
61         public override long Position
62         {
63             get { throw new NotImplementedException(); }
64             set { throw new NotImplementedException(); }
65         }
66
67         protected override void Dispose(bool disposing)
68         {
69             if (isDisposed)
70             {
71                 return;
72             }
73             isDisposed = true;
74             if (disposing)
75             {
76                 //read out last 10 auth bytes
77                 var ten = new byte[10];
78                 stream.Read(ten, 0, 10);
79                 stream.Dispose();
80             }
81         }
82
83         public override void Flush()
84         {
85             throw new NotImplementedException();
86         }
87
88         public override int Read(byte[] buffer, int offset, int count)
89         {
90             if (totalBytesLeftToRead == 0)
91             {
92                 return 0;
93             }
94             int bytesToRead = count;
95             if (count > totalBytesLeftToRead)
96             {
97                 bytesToRead = (int)totalBytesLeftToRead;
98             }
99             int read = stream.Read(buffer, offset, bytesToRead);
100             totalBytesLeftToRead -= read;
101
102             ReadTransformBlocks(buffer, offset, read);
103
104             return read;
105         }
106
107         private int ReadTransformOneBlock(byte[] buffer, int offset, int last)
108         {
109             if (isFinalBlock)
110             {
111                 throw new InvalidOperationException();
112             }
113
114             int bytesRemaining = last - offset;
115             int bytesToRead = (bytesRemaining > BLOCK_SIZE_IN_BYTES)
116                                   ? BLOCK_SIZE_IN_BYTES
117                                   : bytesRemaining;
118
119             // update the counter
120             Array.Copy(BitConverter.GetBytes(nonce++), 0, counter, 0, 4);
121
122             // Determine if this is the final block
123             if ((bytesToRead == bytesRemaining) && (totalBytesLeftToRead == 0))
124             {
125                 counterOut = transform.TransformFinalBlock(counter,
126                                                            0,
127                                                            BLOCK_SIZE_IN_BYTES);
128                 isFinalBlock = true;
129             }
130             else
131             {
132                 transform.TransformBlock(counter,
133                                          0, // offset
134                                          BLOCK_SIZE_IN_BYTES,
135                                          counterOut,
136                                          0); // offset
137             }
138
139             XorInPlace(buffer, offset, bytesToRead);
140             return bytesToRead;
141         }
142
143
144         private void XorInPlace(byte[] buffer, int offset, int count)
145         {
146             for (int i = 0; i < count; i++)
147             {
148                 buffer[offset + i] = (byte)(counterOut[i] ^ buffer[offset + i]);
149             }
150         }
151
152         private void ReadTransformBlocks(byte[] buffer, int offset, int count)
153         {
154             int posn = offset;
155             int last = count + offset;
156
157             while (posn < buffer.Length && posn < last)
158             {
159                 int n = ReadTransformOneBlock(buffer, posn, last);
160                 posn += n;
161             }
162         }
163
164
165         public override long Seek(long offset, SeekOrigin origin)
166         {
167             throw new NotImplementedException();
168         }
169
170         public override void SetLength(long value)
171         {
172             throw new NotImplementedException();
173         }
174
175         public override void Write(byte[] buffer, int offset, int count)
176         {
177             throw new NotImplementedException();
178         }
179     }
180 }