// // System.Security.Cryptography.ToBase64Transform // // Author: // Sergey Chaban (serge@wildwestsoftware.com) // using System; using System.Security.Cryptography; namespace System.Security.Cryptography { public class ToBase64Transform : ICryptoTransform { /// /// Default constructor. /// public ToBase64Transform () { } /// /// public virtual bool CanTransformMultipleBlocks { get { return false; } } /// /// Returns the input block size for the Base64 encoder. /// /// /// The returned value is always 3. /// public virtual int InputBlockSize { get { return 3; } } /// /// Returns the output block size for the Base64 encoder. /// /// /// The value returned by this property is always 4. /// public virtual int OutputBlockSize { get { return 4; } } /// /// public virtual int TransformBlock (byte [] inputBuffer, int inputOffset, int inputCount, byte [] outputBuffer, int outputOffset) { if (inputCount != this.InputBlockSize) throw new CryptographicException(); byte [] lookup = Base64Table.Table; int b1 = inputBuffer [inputOffset]; int b2 = inputBuffer [inputOffset + 1]; int b3 = inputBuffer [inputOffset + 2]; outputBuffer [outputOffset] = lookup [b1 >> 2]; outputBuffer [outputOffset+1] = lookup [((b1 << 4) & 0x30) | (b2 >> 4)]; outputBuffer [outputOffset+2] = lookup [((b2 << 2) & 0x3c) | (b3 >> 6)]; outputBuffer [outputOffset+3] = lookup [b3 & 0x3f]; return this.OutputBlockSize; } // LAMESPEC: It's not clear from Beta2 docs what should be // happening here if inputCount > InputBlockSize. // It just "Converts the specified region of the specified // byte array" and that's all. // Beta2 implementation throws some strange (and undocumented) // exception in such case. The exception is thrown by // System.Convert and not the method itself. // Anyhow, this implementation just encodes blocks of any size, // like any usual Base64 encoder. /// /// public virtual byte [] TransformFinalBlock (byte [] inputBuffer, int inputOffset, int inputCount) { int blockLen = this.InputBlockSize; int outLen = this.OutputBlockSize; int fullBlocks = inputCount / blockLen; int tail = inputCount % blockLen; byte [] res = new byte [(inputCount != 0) ? ((inputCount + 2) / blockLen) * outLen : 0]; int outputOffset = 0; for (int i = 0; i < fullBlocks; i++) { TransformBlock (inputBuffer, inputOffset, blockLen, res, outputOffset); inputOffset += blockLen; outputOffset += outLen; } byte [] lookup = Base64Table.Table; int b1,b2; // When fewer than 24 input bits are available // in an input group, zero bits are added // (on the right) to form an integral number of // 6-bit groups. switch (tail) { case 0: break; case 1: b1 = inputBuffer [inputOffset]; res [outputOffset] = lookup [b1 >> 2]; res [outputOffset+1] = lookup [(b1 << 4) & 0x30]; // padding res [outputOffset+2] = (byte)'='; res [outputOffset+3] = (byte)'='; break; case 2: b1 = inputBuffer [inputOffset]; b2 = inputBuffer [inputOffset + 1]; res [outputOffset] = lookup [b1 >> 2]; res [outputOffset+1] = lookup [((b1 << 4) & 0x30) | (b2 >> 4)]; res [outputOffset+2] = lookup [(b2 << 2) & 0x3c]; // one-byte padding res [outputOffset+3] = (byte)'='; break; default: break; } return res; } /// /// public override string ToString () { return "mono::System.Security.Cryptography.ToBase64Transform"; } internal sealed class Base64Table { // TODO: replace this with "precalculated" table. // This is the Base64 alphabet as described in RFC 2045 // (Table 1, page 25). private static string ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; private static byte[] table; static Base64Table () { int len = ALPHABET.Length; table = new byte [len]; for (int i=0; i < len; i++) { table [i] = (byte) ALPHABET [i]; } } private Base64Table () { // Never instantiated. } internal static byte [] Table { get { return table; } } } // Base64Table } // ToBase64Transform } // System.Security.Cryptography