FromBase64Transform.cs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  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 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 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 int OutputBlockSize {
  63. get {
  64. return 3;
  65. }
  66. }
  67. void System.IDisposable.Dispose ()
  68. {
  69. }
  70. private int Filter (byte [] buffer, int offset, int count)
  71. {
  72. int end = offset + count;
  73. int len = filterBuffer.Length;
  74. int ptr = 0;
  75. byte [] filter = this.filterBuffer;
  76. for (int i = offset; i < end; i++) {
  77. byte b = buffer [i];
  78. if (!Char.IsWhiteSpace ((char) b)) {
  79. if (ptr >= len) {
  80. len <<= 1;
  81. this.filterBuffer = new byte [len];
  82. Array.Copy(filter, 0, this.filterBuffer, 0, len >> 1);
  83. filter = this.filterBuffer;
  84. }
  85. filter [ptr++] = b;
  86. }
  87. }
  88. return ptr;
  89. }
  90. private int DoTransform (byte [] inputBuffer,
  91. int inputOffset,
  92. int inputCount,
  93. byte [] outputBuffer,
  94. int outputOffset)
  95. {
  96. int full = inputCount >> 2;
  97. if (full == 0) return 0;
  98. int rem = 0;
  99. if (inputBuffer[inputCount - 1] == (byte)'=') {
  100. ++rem;
  101. --full;
  102. }
  103. if (inputBuffer[inputCount - 2] == (byte)'=') ++rem;
  104. byte [] lookup = Base64Table.DecodeTable;
  105. int b0,b1,b2,b3;
  106. for (int i = 0; i < full; i++) {
  107. b0 = lookup [inputBuffer [inputOffset++]];
  108. b1 = lookup [inputBuffer [inputOffset++]];
  109. b2 = lookup [inputBuffer [inputOffset++]];
  110. b3 = lookup [inputBuffer [inputOffset++]];
  111. outputBuffer [outputOffset++] = (byte) ((b0 << 2) | (b1 >> 4));
  112. outputBuffer [outputOffset++] = (byte) ((b1 << 4) | (b2 >> 2));
  113. outputBuffer [outputOffset++] = (byte) ((b2 << 6) | b3);
  114. }
  115. int res = full * 3;
  116. switch (rem) {
  117. case 0:
  118. break;
  119. case 1:
  120. b0 = lookup [inputBuffer [inputOffset++]];
  121. b1 = lookup [inputBuffer [inputOffset++]];
  122. b2 = lookup [inputBuffer [inputOffset++]];
  123. outputBuffer [outputOffset++] = (byte) ((b0 << 2) | (b1 >> 4));
  124. outputBuffer [outputOffset++] = (byte) ((b1 << 4) | (b2 >> 2));
  125. res += 2;
  126. break;
  127. case 2:
  128. b0 = lookup [inputBuffer [inputOffset++]];
  129. b1 = lookup [inputBuffer [inputOffset++]];
  130. outputBuffer [outputOffset++] = (byte) ((b0 << 2) | (b1 >> 4));
  131. ++res;
  132. break;
  133. default:
  134. break;
  135. }
  136. return res;
  137. }
  138. /// <summary>
  139. /// </summary>
  140. public int TransformBlock (byte [] inputBuffer,
  141. int inputOffset,
  142. int inputCount,
  143. byte [] outputBuffer,
  144. int outputOffset)
  145. {
  146. int n;
  147. byte [] src;
  148. int srcOff;
  149. int res = 0;
  150. if (mode == FromBase64TransformMode.IgnoreWhiteSpaces) {
  151. n = Filter (inputBuffer, inputOffset, inputCount);
  152. src = filterBuffer;
  153. srcOff = 0;
  154. } else {
  155. n = inputCount;
  156. src = inputBuffer;
  157. srcOff = inputOffset;
  158. }
  159. int count = accPtr + n;
  160. if (count < 4) {
  161. Array.Copy (src, srcOff, accumulator, accPtr, n);
  162. accPtr = count;
  163. } else {
  164. byte [] tmpBuff = new byte [count];
  165. Array.Copy (accumulator, 0, tmpBuff, 0, accPtr);
  166. Array.Copy (src, srcOff, tmpBuff, accPtr, n);
  167. accPtr = count & 3;
  168. Array.Copy (src, srcOff + (n - accPtr), accumulator, 0, accPtr);
  169. res = DoTransform (tmpBuff, 0, count & (~3), outputBuffer, outputOffset);
  170. }
  171. return res;
  172. }
  173. /// <summary>
  174. /// </summary>
  175. public byte [] TransformFinalBlock (byte [] inputBuffer,
  176. int inputOffset,
  177. int inputCount)
  178. {
  179. byte [] src;
  180. int srcOff;
  181. int n;
  182. if (mode == FromBase64TransformMode.IgnoreWhiteSpaces) {
  183. n = Filter (inputBuffer, inputOffset, inputCount);
  184. src = filterBuffer;
  185. srcOff = 0;
  186. } else {
  187. n = inputCount;
  188. src = inputBuffer;
  189. srcOff = inputOffset;
  190. }
  191. int dataLen = accPtr + n;
  192. byte [] tmpBuf = new byte [dataLen];
  193. int resLen = ((dataLen) >> 2) * 3;
  194. byte [] res = new byte [resLen];
  195. Array.Copy (accumulator, 0, tmpBuf, 0, accPtr);
  196. Array.Copy (src, srcOff, tmpBuf, accPtr, n);
  197. int actLen = DoTransform (tmpBuf, 0, dataLen, res, 0);
  198. accPtr = 0;
  199. if (actLen < resLen) {
  200. byte [] newres = new byte [actLen];
  201. Array.Copy (res, newres, actLen);
  202. return newres;
  203. } else
  204. return res;
  205. }
  206. } // FromBase64Transform
  207. } // System.Security.Cryptography