FromBase64Transform.cs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. //
  2. // System.Security.Cryptography.FromBase64Transform
  3. //
  4. // Author:
  5. // Sergey Chaban ([email protected])
  6. //
  7. using System;
  8. using System.Security.Cryptography;
  9. namespace System.Security.Cryptography {
  10. public enum FromBase64TransformMode : int {
  11. IgnoreWhiteSpaces,
  12. DoNotIgnoreWhiteSpaces
  13. }
  14. public class FromBase64Transform : ICryptoTransform {
  15. private FromBase64TransformMode mode;
  16. private byte [] accumulator;
  17. private byte [] filterBuffer;
  18. private int accPtr;
  19. /// <summary>
  20. /// Creates a new instance of the decoder
  21. /// with the default transformation mode (IgnoreWhiteSpaces).
  22. /// </summary>
  23. public FromBase64Transform ()
  24. : this (FromBase64TransformMode.IgnoreWhiteSpaces)
  25. {
  26. }
  27. /// <summary>
  28. /// Creates a new instance of the decoder
  29. /// with the specified transformation mode.
  30. /// </summary>
  31. public FromBase64Transform (FromBase64TransformMode mode)
  32. {
  33. this.mode = mode;
  34. accumulator = new byte [4];
  35. filterBuffer = new byte [4];
  36. accPtr = 0;
  37. }
  38. /// <summary>
  39. /// </summary>
  40. public virtual bool CanTransformMultipleBlocks {
  41. get {
  42. return false;
  43. }
  44. }
  45. /// <summary>
  46. /// Returns the input block size for the Base64 decoder.
  47. /// </summary>
  48. /// <remarks>
  49. /// The input block size for Base64 decoder is always 1 byte.
  50. /// </remarks>
  51. public virtual int InputBlockSize {
  52. get {
  53. return 1;
  54. }
  55. }
  56. /// <summary>
  57. /// Returns the output block size for the Base64 decoder.
  58. /// </summary>
  59. /// <remarks>
  60. /// The value returned by this property is always 3.
  61. /// </remarks>
  62. public virtual int OutputBlockSize {
  63. get {
  64. return 3;
  65. }
  66. }
  67. private int Filter (byte [] buffer, int offset, int count)
  68. {
  69. int end = offset + count;
  70. int len = filterBuffer.Length;
  71. int ptr = 0;
  72. byte [] filter = this.filterBuffer;
  73. for (int i = offset; i < end; i++) {
  74. byte b = buffer [i];
  75. if (!Char.IsWhiteSpace ((char) b)) {
  76. if (ptr >= len) {
  77. len <<= 1;
  78. this.filterBuffer = new byte [len];
  79. Array.Copy(filter, 0, this.filterBuffer, 0, len >> 1);
  80. filter = this.filterBuffer;
  81. }
  82. filter [ptr++] = b;
  83. }
  84. }
  85. return ptr;
  86. }
  87. private int DoTransform (byte [] inputBuffer,
  88. int inputOffset,
  89. int inputCount,
  90. byte [] outputBuffer,
  91. int outputOffset)
  92. {
  93. int full = inputCount >> 2;
  94. if (full == 0) return 0;
  95. int rem = 0;
  96. if (inputBuffer[inputCount - 1] == (byte)'=') {
  97. ++rem;
  98. --full;
  99. }
  100. if (inputBuffer[inputCount - 2] == (byte)'=') ++rem;
  101. byte [] lookup = Base64Table.DecodeTable;
  102. int b0,b1,b2,b3;
  103. for (int i = 0; i < full; i++) {
  104. b0 = lookup [inputBuffer [inputOffset++]];
  105. b1 = lookup [inputBuffer [inputOffset++]];
  106. b2 = lookup [inputBuffer [inputOffset++]];
  107. b3 = lookup [inputBuffer [inputOffset++]];
  108. outputBuffer [outputOffset++] = (byte) ((b0 << 2) | (b1 >> 4));
  109. outputBuffer [outputOffset++] = (byte) ((b1 << 4) | (b2 >> 2));
  110. outputBuffer [outputOffset++] = (byte) ((b2 << 6) | b3);
  111. }
  112. int res = full * 3;
  113. switch (rem) {
  114. case 0:
  115. break;
  116. case 1:
  117. b0 = lookup [inputBuffer [inputOffset++]];
  118. b1 = lookup [inputBuffer [inputOffset++]];
  119. b2 = lookup [inputBuffer [inputOffset++]];
  120. outputBuffer [outputOffset++] = (byte) ((b0 << 2) | (b1 >> 4));
  121. outputBuffer [outputOffset++] = (byte) ((b1 << 4) | (b2 >> 2));
  122. res += 2;
  123. break;
  124. case 2:
  125. b0 = lookup [inputBuffer [inputOffset++]];
  126. b1 = lookup [inputBuffer [inputOffset++]];
  127. outputBuffer [outputOffset++] = (byte) ((b0 << 2) | (b1 >> 4));
  128. ++res;
  129. break;
  130. default:
  131. break;
  132. }
  133. return res;
  134. }
  135. /// <summary>
  136. /// </summary>
  137. public virtual int TransformBlock (byte [] inputBuffer,
  138. int inputOffset,
  139. int inputCount,
  140. byte [] outputBuffer,
  141. int outputOffset)
  142. {
  143. int n;
  144. byte [] src;
  145. int srcOff;
  146. int res = 0;
  147. if (mode == FromBase64TransformMode.IgnoreWhiteSpaces) {
  148. n = Filter (inputBuffer, inputOffset, inputCount);
  149. src = filterBuffer;
  150. srcOff = 0;
  151. } else {
  152. n = inputCount;
  153. src = inputBuffer;
  154. srcOff = inputOffset;
  155. }
  156. int count = accPtr + n;
  157. if (count < 4) {
  158. Array.Copy (src, srcOff, accumulator, accPtr, n);
  159. accPtr = count;
  160. } else {
  161. byte [] tmpBuff = new byte [count];
  162. Array.Copy (accumulator, 0, tmpBuff, 0, accPtr);
  163. Array.Copy (src, srcOff, tmpBuff, accPtr, n);
  164. accPtr = count & 3;
  165. Array.Copy (src, srcOff + (n - accPtr), accumulator, 0, accPtr);
  166. res = DoTransform (tmpBuff, 0, count & (~3), outputBuffer, outputOffset);
  167. }
  168. return res;
  169. }
  170. /// <summary>
  171. /// </summary>
  172. public virtual byte [] TransformFinalBlock (byte [] inputBuffer,
  173. int inputOffset,
  174. int inputCount)
  175. {
  176. byte [] src;
  177. int srcOff;
  178. int n;
  179. if (mode == FromBase64TransformMode.IgnoreWhiteSpaces) {
  180. n = Filter (inputBuffer, inputOffset, inputCount);
  181. src = filterBuffer;
  182. srcOff = 0;
  183. } else {
  184. n = inputCount;
  185. src = inputBuffer;
  186. srcOff = inputOffset;
  187. }
  188. int dataLen = accPtr + n;
  189. byte [] tmpBuf = new byte [dataLen];
  190. int resLen = ((dataLen) >> 2) * 3;
  191. byte [] res = new byte [resLen];
  192. Array.Copy (accumulator, 0, tmpBuf, 0, accPtr);
  193. Array.Copy (src, srcOff, tmpBuf, accPtr, n);
  194. DoTransform (tmpBuf, 0, dataLen, res, 0);
  195. accPtr = 0;
  196. return res;
  197. }
  198. /// <summary>
  199. /// </summary>
  200. public override string ToString ()
  201. {
  202. return "mono::System.Security.Cryptography.FromBase64Transform";
  203. }
  204. } // FromBase64Transform
  205. } // System.Security.Cryptography