ToBase64Transform.cs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. //
  2. // System.Security.Cryptography.ToBase64Transform
  3. //
  4. // Author:
  5. // Sergey Chaban ([email protected])
  6. //
  7. using System;
  8. using System.Security.Cryptography;
  9. namespace System.Security.Cryptography {
  10. public class ToBase64Transform : ICryptoTransform {
  11. /// <summary>
  12. /// Default constructor.
  13. /// </summary>
  14. public ToBase64Transform ()
  15. {
  16. }
  17. /// <summary>
  18. /// </summary>
  19. public virtual bool CanTransformMultipleBlocks {
  20. get {
  21. return false;
  22. }
  23. }
  24. /// <summary>
  25. /// Returns the input block size for the Base64 encoder.
  26. /// </summary>
  27. /// <remarks>
  28. /// The returned value is always 3.
  29. /// </remarks>
  30. public virtual int InputBlockSize {
  31. get {
  32. return 3;
  33. }
  34. }
  35. /// <summary>
  36. /// Returns the output block size for the Base64 encoder.
  37. /// </summary>
  38. /// <remarks>
  39. /// The value returned by this property is always 4.
  40. /// </remarks>
  41. public virtual int OutputBlockSize {
  42. get {
  43. return 4;
  44. }
  45. }
  46. /// <summary>
  47. /// </summary>
  48. public virtual int TransformBlock (byte [] inputBuffer,
  49. int inputOffset,
  50. int inputCount,
  51. byte [] outputBuffer,
  52. int outputOffset)
  53. {
  54. if (inputCount != this.InputBlockSize)
  55. throw new CryptographicException();
  56. byte [] lookup = Base64Table.EncodeTable;
  57. int b1 = inputBuffer [inputOffset];
  58. int b2 = inputBuffer [inputOffset + 1];
  59. int b3 = inputBuffer [inputOffset + 2];
  60. outputBuffer [outputOffset] = lookup [b1 >> 2];
  61. outputBuffer [outputOffset+1] = lookup [((b1 << 4) & 0x30) | (b2 >> 4)];
  62. outputBuffer [outputOffset+2] = lookup [((b2 << 2) & 0x3c) | (b3 >> 6)];
  63. outputBuffer [outputOffset+3] = lookup [b3 & 0x3f];
  64. return this.OutputBlockSize;
  65. }
  66. // LAMESPEC: It's not clear from Beta2 docs what should be
  67. // happening here if inputCount > InputBlockSize.
  68. // It just "Converts the specified region of the specified
  69. // byte array" and that's all.
  70. // Beta2 implementation throws some strange (and undocumented)
  71. // exception in such case. The exception is thrown by
  72. // System.Convert and not the method itself.
  73. // Anyhow, this implementation just encodes blocks of any size,
  74. // like any usual Base64 encoder.
  75. /// <summary>
  76. /// </summary>
  77. public virtual byte [] TransformFinalBlock (byte [] inputBuffer,
  78. int inputOffset,
  79. int inputCount)
  80. {
  81. int blockLen = this.InputBlockSize;
  82. int outLen = this.OutputBlockSize;
  83. int fullBlocks = inputCount / blockLen;
  84. int tail = inputCount % blockLen;
  85. byte [] res = new byte [(inputCount != 0)
  86. ? ((inputCount + 2) / blockLen) * outLen
  87. : 0];
  88. int outputOffset = 0;
  89. for (int i = 0; i < fullBlocks; i++) {
  90. TransformBlock (inputBuffer, inputOffset,
  91. blockLen, res, outputOffset);
  92. inputOffset += blockLen;
  93. outputOffset += outLen;
  94. }
  95. byte [] lookup = Base64Table.EncodeTable;
  96. int b1,b2;
  97. // When fewer than 24 input bits are available
  98. // in an input group, zero bits are added
  99. // (on the right) to form an integral number of
  100. // 6-bit groups.
  101. switch (tail) {
  102. case 0:
  103. break;
  104. case 1:
  105. b1 = inputBuffer [inputOffset];
  106. res [outputOffset] = lookup [b1 >> 2];
  107. res [outputOffset+1] = lookup [(b1 << 4) & 0x30];
  108. // padding
  109. res [outputOffset+2] = (byte)'=';
  110. res [outputOffset+3] = (byte)'=';
  111. break;
  112. case 2:
  113. b1 = inputBuffer [inputOffset];
  114. b2 = inputBuffer [inputOffset + 1];
  115. res [outputOffset] = lookup [b1 >> 2];
  116. res [outputOffset+1] = lookup [((b1 << 4) & 0x30) | (b2 >> 4)];
  117. res [outputOffset+2] = lookup [(b2 << 2) & 0x3c];
  118. // one-byte padding
  119. res [outputOffset+3] = (byte)'=';
  120. break;
  121. default:
  122. break;
  123. }
  124. return res;
  125. }
  126. /// <summary>
  127. /// </summary>
  128. public override string ToString ()
  129. {
  130. return "mono::System.Security.Cryptography.ToBase64Transform";
  131. }
  132. } // ToBase64Transform
  133. // FIXME: Ought to be in a standalone file.
  134. internal sealed class Base64Table {
  135. // This is the Base64 alphabet as described in RFC 2045
  136. // (Table 1, page 25).
  137. private static string ALPHABET =
  138. "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  139. private static byte[] encodeTable;
  140. private static byte[] decodeTable;
  141. static Base64Table ()
  142. {
  143. int len = ALPHABET.Length;
  144. encodeTable = new byte [len];
  145. for (int i=0; i < len; i++) {
  146. encodeTable [i] = (byte) ALPHABET [i];
  147. }
  148. decodeTable = new byte [1 + (int)'z'];
  149. for (int i=0; i < decodeTable.Length; i++) {
  150. decodeTable [i] = Byte.MaxValue;
  151. }
  152. for (int i=0; i < len; i++) {
  153. char ch = ALPHABET [i];
  154. decodeTable [(int)ch] = (byte) i;
  155. }
  156. }
  157. private Base64Table ()
  158. {
  159. // Never instantiated.
  160. }
  161. internal static byte [] EncodeTable {
  162. get {
  163. return encodeTable;
  164. }
  165. }
  166. internal static byte [] DecodeTable {
  167. get {
  168. return decodeTable;
  169. }
  170. }
  171. } // Base64Table
  172. } // System.Security.Cryptography