// // System.Security.Cryptography.FromBase64Transform // // Author: // Sergey Chaban (serge@wildwestsoftware.com) // using System; using System.Security.Cryptography; namespace System.Security.Cryptography { public enum FromBase64TransformMode : int { IgnoreWhiteSpaces, DoNotIgnoreWhiteSpaces } public class FromBase64Transform : ICryptoTransform { private FromBase64TransformMode mode; private byte [] accumulator; private byte [] filterBuffer; private int accPtr; /// /// Creates a new instance of the decoder /// with the default transformation mode (IgnoreWhiteSpaces). /// public FromBase64Transform () : this (FromBase64TransformMode.IgnoreWhiteSpaces) { } /// /// Creates a new instance of the decoder /// with the specified transformation mode. /// public FromBase64Transform (FromBase64TransformMode mode) { this.mode = mode; accumulator = new byte [4]; filterBuffer = new byte [4]; accPtr = 0; } /// /// public virtual bool CanTransformMultipleBlocks { get { return false; } } /// /// Returns the input block size for the Base64 decoder. /// /// /// The input block size for Base64 decoder is always 1 byte. /// public virtual int InputBlockSize { get { return 1; } } /// /// Returns the output block size for the Base64 decoder. /// /// /// The value returned by this property is always 3. /// public virtual int OutputBlockSize { get { return 3; } } private int Filter (byte [] buffer, int offset, int count) { int end = offset + count; int len = filterBuffer.Length; int ptr = 0; byte [] filter = this.filterBuffer; for (int i = offset; i < end; i++) { byte b = buffer [i]; if (!Char.IsWhiteSpace ((char) b)) { if (ptr >= len) { len <<= 1; this.filterBuffer = new byte [len]; Array.Copy(filter, 0, this.filterBuffer, 0, len >> 1); filter = this.filterBuffer; } filter [ptr++] = b; } } return ptr; } private int DoTransform (byte [] inputBuffer, int inputOffset, int inputCount, byte [] outputBuffer, int outputOffset) { int full = inputCount >> 2; if (full == 0) return 0; int rem = 0; if (inputBuffer[inputCount - 1] == (byte)'=') { ++rem; --full; } if (inputBuffer[inputCount - 2] == (byte)'=') ++rem; byte [] lookup = Base64Table.DecodeTable; int b0,b1,b2,b3; for (int i = 0; i < full; i++) { b0 = lookup [inputBuffer [inputOffset++]]; b1 = lookup [inputBuffer [inputOffset++]]; b2 = lookup [inputBuffer [inputOffset++]]; b3 = lookup [inputBuffer [inputOffset++]]; outputBuffer [outputOffset++] = (byte) ((b0 << 2) | (b1 >> 4)); outputBuffer [outputOffset++] = (byte) ((b1 << 4) | (b2 >> 2)); outputBuffer [outputOffset++] = (byte) ((b2 << 6) | b3); } int res = full * 3; switch (rem) { case 0: break; case 1: b0 = lookup [inputBuffer [inputOffset++]]; b1 = lookup [inputBuffer [inputOffset++]]; b2 = lookup [inputBuffer [inputOffset++]]; outputBuffer [outputOffset++] = (byte) ((b0 << 2) | (b1 >> 4)); outputBuffer [outputOffset++] = (byte) ((b1 << 4) | (b2 >> 2)); res += 2; break; case 2: b0 = lookup [inputBuffer [inputOffset++]]; b1 = lookup [inputBuffer [inputOffset++]]; outputBuffer [outputOffset++] = (byte) ((b0 << 2) | (b1 >> 4)); ++res; break; default: break; } return res; } /// /// public virtual int TransformBlock (byte [] inputBuffer, int inputOffset, int inputCount, byte [] outputBuffer, int outputOffset) { int n; byte [] src; int srcOff; int res = 0; if (mode == FromBase64TransformMode.IgnoreWhiteSpaces) { n = Filter (inputBuffer, inputOffset, inputCount); src = filterBuffer; srcOff = 0; } else { n = inputCount; src = inputBuffer; srcOff = inputOffset; } int count = accPtr + n; if (count < 4) { Array.Copy (src, srcOff, accumulator, accPtr, n); accPtr = count; } else { byte [] tmpBuff = new byte [count]; Array.Copy (accumulator, 0, tmpBuff, 0, accPtr); Array.Copy (src, srcOff, tmpBuff, accPtr, n); accPtr = count & 3; Array.Copy (src, srcOff + (n - accPtr), accumulator, 0, accPtr); res = DoTransform (tmpBuff, 0, count & (~3), outputBuffer, outputOffset); } return res; } /// /// public virtual byte [] TransformFinalBlock (byte [] inputBuffer, int inputOffset, int inputCount) { byte [] src; int srcOff; int n; if (mode == FromBase64TransformMode.IgnoreWhiteSpaces) { n = Filter (inputBuffer, inputOffset, inputCount); src = filterBuffer; srcOff = 0; } else { n = inputCount; src = inputBuffer; srcOff = inputOffset; } int dataLen = accPtr + n; byte [] tmpBuf = new byte [dataLen]; int resLen = ((dataLen) >> 2) * 3; byte [] res = new byte [resLen]; Array.Copy (accumulator, 0, tmpBuf, 0, accPtr); Array.Copy (src, srcOff, tmpBuf, accPtr, n); DoTransform (tmpBuf, 0, dataLen, res, 0); accPtr = 0; return res; } /// /// public override string ToString () { return "mono::System.Security.Cryptography.FromBase64Transform"; } } // FromBase64Transform } // System.Security.Cryptography