ToBase64Transform.cs 5.4 KB

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