Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / mscorlib / system / security / cryptography / base64transforms.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6 // <OWNER>Microsoft</OWNER>
7 // 
8
9 //
10 // Base64Transform.cs
11 //
12
13 // This file contains two ICryptoTransforms: ToBase64Transform and FromBase64Transform
14 // they may be attached to a CryptoStream in either read or write mode
15
16 namespace System.Security.Cryptography {
17     using System;
18     using System.IO;
19     using System.Text;
20     using System.Diagnostics.Contracts;
21
22     [Serializable]
23 [System.Runtime.InteropServices.ComVisible(true)]
24     public enum FromBase64TransformMode {
25         IgnoreWhiteSpaces = 0,
26         DoNotIgnoreWhiteSpaces = 1,
27     }
28
29 [System.Runtime.InteropServices.ComVisible(true)]
30     public class ToBase64Transform : ICryptoTransform {
31         // converting to Base64 takes 3 bytes input and generates 4 bytes output
32         public int InputBlockSize {
33             get { return(3); }
34         }
35
36         public int OutputBlockSize {
37             get { return(4); }
38         }
39
40         public bool CanTransformMultipleBlocks {
41             get { return(false); }
42         }
43
44         public virtual bool CanReuseTransform { 
45             get { return(true); }
46         }
47
48         public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) {
49             // Do some validation
50             if (inputBuffer == null) throw new ArgumentNullException("inputBuffer");
51             if (inputOffset < 0) throw new ArgumentOutOfRangeException("inputOffset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
52             if (inputCount < 0 || (inputCount > inputBuffer.Length)) throw new ArgumentException(Environment.GetResourceString("Argument_InvalidValue"));
53             if ((inputBuffer.Length - inputCount) < inputOffset) throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
54             Contract.EndContractBlock();
55
56             // for now, only convert 3 bytes to 4
57             char[] temp = new char[4];
58             Convert.ToBase64CharArray(inputBuffer, inputOffset, 3, temp, 0);
59             byte[] tempBytes = Encoding.ASCII.GetBytes(temp);
60             if (tempBytes.Length != 4) throw new CryptographicException(Environment.GetResourceString( "Cryptography_SSE_InvalidDataSize" ));
61             Buffer.BlockCopy(tempBytes, 0, outputBuffer, outputOffset, tempBytes.Length);
62             return(tempBytes.Length);
63         }
64
65         public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount) { 
66             // Do some validation
67             if (inputBuffer == null) throw new ArgumentNullException("inputBuffer");
68             if (inputOffset < 0) throw new ArgumentOutOfRangeException("inputOffset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
69             if (inputCount < 0 || (inputCount > inputBuffer.Length)) throw new ArgumentException(Environment.GetResourceString("Argument_InvalidValue"));
70             if ((inputBuffer.Length - inputCount) < inputOffset) throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
71             Contract.EndContractBlock();
72
73             // Convert.ToBase64CharArray already does padding, so all we have to check is that
74             // the inputCount wasn't 0
75
76             // again, for now only a block at a time
77             if (inputCount == 0) {
78                 return(EmptyArray<Byte>.Value);
79             } else {
80                 char[] temp = new char[4];
81                 Convert.ToBase64CharArray(inputBuffer, inputOffset, inputCount, temp, 0);
82                 byte[] tempBytes = Encoding.ASCII.GetBytes(temp);
83                 return(tempBytes);
84             }
85         }
86
87         // must implement IDisposable, but in this case there's nothing to do.
88
89         public void Dispose() {
90             Clear();
91         }
92
93         public void Clear() {
94             Dispose(true);
95             GC.SuppressFinalize(this);
96         }
97
98         protected virtual void Dispose(bool disposing) {
99         }
100
101         ~ToBase64Transform() {
102             //
103             // A finalizer is not necessary here, however since we shipped a finalizer that called
104             // Dispose(false) in v2.0, we need to keep it around in case any existing code had subclassed
105             // this transform and expects to have a base class finalizer call its dispose method
106             // 
107
108             Dispose(false);
109         }
110     }
111
112 [System.Runtime.InteropServices.ComVisible(true)]
113     public class FromBase64Transform : ICryptoTransform {
114         private byte[] _inputBuffer = new byte[4];
115         private int    _inputIndex;
116         
117         private FromBase64TransformMode _whitespaces;
118
119         // Constructors
120         public FromBase64Transform() : this(FromBase64TransformMode.IgnoreWhiteSpaces) {}
121         public FromBase64Transform(FromBase64TransformMode whitespaces) {
122             _whitespaces = whitespaces;
123             _inputIndex = 0;
124         }
125         
126         // converting from Base64 generates 3 bytes output from each 4 bytes input block
127         public int InputBlockSize {
128             get { return(1); }
129         }
130
131         public int OutputBlockSize {
132             get { return(3); }
133         }
134
135         public bool CanTransformMultipleBlocks {
136             get { return(false); }
137         }
138
139         public virtual bool CanReuseTransform { 
140             get { return(true); }
141         }
142
143         public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) {
144             // Do some validation
145             if (inputBuffer == null) throw new ArgumentNullException("inputBuffer");
146             if (inputOffset < 0) throw new ArgumentOutOfRangeException("inputOffset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
147             if (inputCount < 0 || (inputCount > inputBuffer.Length)) throw new ArgumentException(Environment.GetResourceString("Argument_InvalidValue"));
148             if ((inputBuffer.Length - inputCount) < inputOffset) throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
149             Contract.EndContractBlock();
150
151             if (_inputBuffer == null)
152                 throw new ObjectDisposedException(null, Environment.GetResourceString("ObjectDisposed_Generic"));
153
154             byte[] temp = new byte[inputCount];
155             char[] tempChar;
156             int effectiveCount;
157
158             if (_whitespaces == FromBase64TransformMode.IgnoreWhiteSpaces) {
159                 temp = DiscardWhiteSpaces(inputBuffer, inputOffset, inputCount);
160                 effectiveCount = temp.Length;
161             } else {
162                 Buffer.InternalBlockCopy(inputBuffer, inputOffset, temp, 0, inputCount);
163                 effectiveCount = inputCount;
164             }            
165
166             if (effectiveCount + _inputIndex < 4) {
167                 Buffer.InternalBlockCopy(temp, 0, _inputBuffer, _inputIndex, effectiveCount);
168                 _inputIndex += effectiveCount;  
169                 return 0;  
170             }
171             
172             // Get the number of 4 bytes blocks to transform
173             int numBlocks = (effectiveCount + _inputIndex) / 4;
174             byte[] transformBuffer = new byte[_inputIndex + effectiveCount];
175             Buffer.InternalBlockCopy(_inputBuffer, 0, transformBuffer, 0, _inputIndex);
176             Buffer.InternalBlockCopy(temp, 0, transformBuffer, _inputIndex, effectiveCount);
177             _inputIndex = (effectiveCount + _inputIndex) % 4; 
178             Buffer.InternalBlockCopy(temp, effectiveCount - _inputIndex, _inputBuffer, 0, _inputIndex);
179
180             tempChar = Encoding.ASCII.GetChars(transformBuffer, 0, 4*numBlocks);
181
182             byte[] tempBytes = Convert.FromBase64CharArray(tempChar, 0, 4*numBlocks);
183             Buffer.BlockCopy(tempBytes, 0, outputBuffer, outputOffset, tempBytes.Length);
184             return(tempBytes.Length);
185         }
186
187         public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount) {
188             // Do some validation
189             if (inputBuffer == null) throw new ArgumentNullException("inputBuffer");
190             if (inputOffset < 0) throw new ArgumentOutOfRangeException("inputOffset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
191             if (inputCount < 0 || (inputCount > inputBuffer.Length)) throw new ArgumentException(Environment.GetResourceString("Argument_InvalidValue"));
192             if ((inputBuffer.Length - inputCount) < inputOffset) throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
193             Contract.EndContractBlock();
194
195             if (_inputBuffer == null)
196                 throw new ObjectDisposedException(null, Environment.GetResourceString("ObjectDisposed_Generic"));
197
198             byte[] temp = new byte[inputCount];
199             char[] tempChar;
200             int effectiveCount;
201
202             if (_whitespaces == FromBase64TransformMode.IgnoreWhiteSpaces) {
203                 temp = DiscardWhiteSpaces(inputBuffer, inputOffset, inputCount);
204                 effectiveCount = temp.Length;
205             } else {
206                 Buffer.InternalBlockCopy(inputBuffer, inputOffset, temp, 0, inputCount);
207                 effectiveCount = inputCount;
208             }            
209
210             if (effectiveCount + _inputIndex < 4) {
211                 Reset();
212                 return (EmptyArray<Byte>.Value);  
213             }
214             
215             // Get the number of 4 bytes blocks to transform
216             int numBlocks = (effectiveCount + _inputIndex) / 4;
217             byte[] transformBuffer = new byte[_inputIndex + effectiveCount];
218             Buffer.InternalBlockCopy(_inputBuffer, 0, transformBuffer, 0, _inputIndex);
219             Buffer.InternalBlockCopy(temp, 0, transformBuffer, _inputIndex, effectiveCount);
220             _inputIndex = (effectiveCount + _inputIndex) % 4; 
221             Buffer.InternalBlockCopy(temp, effectiveCount - _inputIndex, _inputBuffer, 0, _inputIndex);
222
223             tempChar = Encoding.ASCII.GetChars(transformBuffer, 0, 4*numBlocks);
224
225             byte[] tempBytes = Convert.FromBase64CharArray(tempChar, 0, 4*numBlocks);
226             // reinitialize the transform
227             Reset();
228             return(tempBytes);
229         }
230
231         private byte[] DiscardWhiteSpaces(byte[] inputBuffer, int inputOffset, int inputCount) {
232             int i, iCount = 0;
233             for (i=0; i<inputCount; i++)
234                 if (Char.IsWhiteSpace((char)inputBuffer[inputOffset + i])) iCount++;
235             byte[] rgbOut = new byte[inputCount - iCount];
236             iCount = 0;
237             for (i=0; i<inputCount; i++)
238                 if (!Char.IsWhiteSpace((char)inputBuffer[inputOffset + i])) {
239                     rgbOut[iCount++] = inputBuffer[inputOffset + i];
240                 }
241             return rgbOut;
242         }
243
244         // must implement IDisposable, which in this case means clearing the input buffer
245
246         public void Dispose() {
247             Dispose(true);
248             GC.SuppressFinalize(this);
249         }
250
251         // Reset the state of the transform so it can be used again
252         private void Reset() {
253             _inputIndex = 0;
254         }
255
256         public void Clear() {
257             Dispose();
258         }
259
260         protected virtual void Dispose(bool disposing) {
261             // we always want to clear the input buffer
262             if (disposing) {
263                 if (_inputBuffer != null)
264                     Array.Clear(_inputBuffer, 0, _inputBuffer.Length);
265                 _inputBuffer = null;
266                 _inputIndex = 0;
267             }
268         }
269
270         ~FromBase64Transform() {
271             //
272             // A finalizer is not necessary here, however since we shipped a finalizer that called
273             // Dispose(false) in v2.0, we need to keep it around in case any existing code had subclassed
274             // this transform and expects to have a base class finalizer call its dispose method
275             // 
276
277             Dispose(false);
278         }
279     }
280 }