3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 // <OWNER>Microsoft</OWNER>
13 // This file contains two ICryptoTransforms: ToBase64Transform and FromBase64Transform
14 // they may be attached to a CryptoStream in either read or write mode
16 namespace System.Security.Cryptography {
20 using System.Diagnostics.Contracts;
23 [System.Runtime.InteropServices.ComVisible(true)]
24 public enum FromBase64TransformMode {
25 IgnoreWhiteSpaces = 0,
26 DoNotIgnoreWhiteSpaces = 1,
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 {
36 public int OutputBlockSize {
40 public bool CanTransformMultipleBlocks {
41 get { return(false); }
44 public virtual bool CanReuseTransform {
48 public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) {
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();
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);
65 public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount) {
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();
73 // Convert.ToBase64CharArray already does padding, so all we have to check is that
74 // the inputCount wasn't 0
76 // again, for now only a block at a time
77 if (inputCount == 0) {
78 return(EmptyArray<Byte>.Value);
80 char[] temp = new char[4];
81 Convert.ToBase64CharArray(inputBuffer, inputOffset, inputCount, temp, 0);
82 byte[] tempBytes = Encoding.ASCII.GetBytes(temp);
87 // must implement IDisposable, but in this case there's nothing to do.
89 public void Dispose() {
95 GC.SuppressFinalize(this);
98 protected virtual void Dispose(bool disposing) {
101 ~ToBase64Transform() {
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
112 [System.Runtime.InteropServices.ComVisible(true)]
113 public class FromBase64Transform : ICryptoTransform {
114 private byte[] _inputBuffer = new byte[4];
115 private int _inputIndex;
117 private FromBase64TransformMode _whitespaces;
120 public FromBase64Transform() : this(FromBase64TransformMode.IgnoreWhiteSpaces) {}
121 public FromBase64Transform(FromBase64TransformMode whitespaces) {
122 _whitespaces = whitespaces;
126 // converting from Base64 generates 3 bytes output from each 4 bytes input block
127 public int InputBlockSize {
131 public int OutputBlockSize {
135 public bool CanTransformMultipleBlocks {
136 get { return(false); }
139 public virtual bool CanReuseTransform {
140 get { return(true); }
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();
151 if (_inputBuffer == null)
152 throw new ObjectDisposedException(null, Environment.GetResourceString("ObjectDisposed_Generic"));
154 byte[] temp = new byte[inputCount];
158 if (_whitespaces == FromBase64TransformMode.IgnoreWhiteSpaces) {
159 temp = DiscardWhiteSpaces(inputBuffer, inputOffset, inputCount);
160 effectiveCount = temp.Length;
162 Buffer.InternalBlockCopy(inputBuffer, inputOffset, temp, 0, inputCount);
163 effectiveCount = inputCount;
166 if (effectiveCount + _inputIndex < 4) {
167 Buffer.InternalBlockCopy(temp, 0, _inputBuffer, _inputIndex, effectiveCount);
168 _inputIndex += effectiveCount;
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);
180 tempChar = Encoding.ASCII.GetChars(transformBuffer, 0, 4*numBlocks);
182 byte[] tempBytes = Convert.FromBase64CharArray(tempChar, 0, 4*numBlocks);
183 Buffer.BlockCopy(tempBytes, 0, outputBuffer, outputOffset, tempBytes.Length);
184 return(tempBytes.Length);
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();
195 if (_inputBuffer == null)
196 throw new ObjectDisposedException(null, Environment.GetResourceString("ObjectDisposed_Generic"));
198 byte[] temp = new byte[inputCount];
202 if (_whitespaces == FromBase64TransformMode.IgnoreWhiteSpaces) {
203 temp = DiscardWhiteSpaces(inputBuffer, inputOffset, inputCount);
204 effectiveCount = temp.Length;
206 Buffer.InternalBlockCopy(inputBuffer, inputOffset, temp, 0, inputCount);
207 effectiveCount = inputCount;
210 if (effectiveCount + _inputIndex < 4) {
212 return (EmptyArray<Byte>.Value);
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);
223 tempChar = Encoding.ASCII.GetChars(transformBuffer, 0, 4*numBlocks);
225 byte[] tempBytes = Convert.FromBase64CharArray(tempChar, 0, 4*numBlocks);
226 // reinitialize the transform
231 private byte[] DiscardWhiteSpaces(byte[] inputBuffer, int inputOffset, int inputCount) {
233 for (i=0; i<inputCount; i++)
234 if (Char.IsWhiteSpace((char)inputBuffer[inputOffset + i])) iCount++;
235 byte[] rgbOut = new byte[inputCount - iCount];
237 for (i=0; i<inputCount; i++)
238 if (!Char.IsWhiteSpace((char)inputBuffer[inputOffset + i])) {
239 rgbOut[iCount++] = inputBuffer[inputOffset + i];
244 // must implement IDisposable, which in this case means clearing the input buffer
246 public void Dispose() {
248 GC.SuppressFinalize(this);
251 // Reset the state of the transform so it can be used again
252 private void Reset() {
256 public void Clear() {
260 protected virtual void Dispose(bool disposing) {
261 // we always want to clear the input buffer
263 if (_inputBuffer != null)
264 Array.Clear(_inputBuffer, 0, _inputBuffer.Length);
270 ~FromBase64Transform() {
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