FromBase64Transform.cs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. //
  2. // System.Security.Cryptography.FromBase64Transform
  3. //
  4. // Author:
  5. // Sergey Chaban ([email protected])
  6. //
  7. using System;
  8. namespace System.Security.Cryptography {
  9. public enum FromBase64TransformMode : int {
  10. IgnoreWhiteSpaces,
  11. DoNotIgnoreWhiteSpaces
  12. }
  13. public class FromBase64Transform : ICryptoTransform {
  14. private FromBase64TransformMode mode;
  15. private byte [] accumulator;
  16. private byte [] filterBuffer;
  17. private int accPtr;
  18. private bool m_disposed;
  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. m_disposed = false;
  38. }
  39. ~FromBase64Transform ()
  40. {
  41. Dispose (false);
  42. }
  43. /// <summary>
  44. /// </summary>
  45. public bool CanTransformMultipleBlocks {
  46. get {
  47. return false;
  48. }
  49. }
  50. public virtual bool CanReuseTransform {
  51. get { return false; }
  52. }
  53. /// <summary>
  54. /// Returns the input block size for the Base64 decoder.
  55. /// </summary>
  56. /// <remarks>
  57. /// The input block size for Base64 decoder is always 1 byte.
  58. /// </remarks>
  59. public int InputBlockSize {
  60. get {
  61. return 1;
  62. }
  63. }
  64. /// <summary>
  65. /// Returns the output block size for the Base64 decoder.
  66. /// </summary>
  67. /// <remarks>
  68. /// The value returned by this property is always 3.
  69. /// </remarks>
  70. public int OutputBlockSize {
  71. get {
  72. return 3;
  73. }
  74. }
  75. public void Clear()
  76. {
  77. Dispose (true);
  78. }
  79. void IDisposable.Dispose ()
  80. {
  81. Dispose (true);
  82. GC.SuppressFinalize (this); // Finalization is now unnecessary
  83. }
  84. protected virtual void Dispose (bool disposing)
  85. {
  86. if (!m_disposed) {
  87. // dispose unmanaged objects
  88. if (disposing) {
  89. // dispose managed objects
  90. }
  91. m_disposed = true;
  92. }
  93. }
  94. private int Filter (byte [] buffer, int offset, int count)
  95. {
  96. int end = offset + count;
  97. int len = filterBuffer.Length;
  98. int ptr = 0;
  99. byte [] filter = this.filterBuffer;
  100. for (int i = offset; i < end; i++) {
  101. byte b = buffer [i];
  102. if (!Char.IsWhiteSpace ((char) b)) {
  103. if (ptr >= len) {
  104. len <<= 1;
  105. this.filterBuffer = new byte [len];
  106. Array.Copy(filter, 0, this.filterBuffer, 0, len >> 1);
  107. filter = this.filterBuffer;
  108. }
  109. filter [ptr++] = b;
  110. }
  111. }
  112. return ptr;
  113. }
  114. private int DoTransform (byte [] inputBuffer,
  115. int inputOffset,
  116. int inputCount,
  117. byte [] outputBuffer,
  118. int outputOffset)
  119. {
  120. int full = inputCount >> 2;
  121. if (full == 0) return 0;
  122. int rem = 0;
  123. if (inputBuffer[inputCount - 1] == (byte)'=') {
  124. ++rem;
  125. --full;
  126. }
  127. if (inputBuffer[inputCount - 2] == (byte)'=') ++rem;
  128. byte [] lookup = Base64Table.DecodeTable;
  129. int b0,b1,b2,b3;
  130. for (int i = 0; i < full; i++) {
  131. b0 = lookup [inputBuffer [inputOffset++]];
  132. b1 = lookup [inputBuffer [inputOffset++]];
  133. b2 = lookup [inputBuffer [inputOffset++]];
  134. b3 = lookup [inputBuffer [inputOffset++]];
  135. outputBuffer [outputOffset++] = (byte) ((b0 << 2) | (b1 >> 4));
  136. outputBuffer [outputOffset++] = (byte) ((b1 << 4) | (b2 >> 2));
  137. outputBuffer [outputOffset++] = (byte) ((b2 << 6) | b3);
  138. }
  139. int res = full * 3;
  140. switch (rem) {
  141. case 0:
  142. break;
  143. case 1:
  144. b0 = lookup [inputBuffer [inputOffset++]];
  145. b1 = lookup [inputBuffer [inputOffset++]];
  146. b2 = lookup [inputBuffer [inputOffset++]];
  147. outputBuffer [outputOffset++] = (byte) ((b0 << 2) | (b1 >> 4));
  148. outputBuffer [outputOffset++] = (byte) ((b1 << 4) | (b2 >> 2));
  149. res += 2;
  150. break;
  151. case 2:
  152. b0 = lookup [inputBuffer [inputOffset++]];
  153. b1 = lookup [inputBuffer [inputOffset++]];
  154. outputBuffer [outputOffset++] = (byte) ((b0 << 2) | (b1 >> 4));
  155. ++res;
  156. break;
  157. default:
  158. break;
  159. }
  160. return res;
  161. }
  162. /// <summary>
  163. /// </summary>
  164. public int TransformBlock (byte [] inputBuffer,
  165. int inputOffset,
  166. int inputCount,
  167. byte [] outputBuffer,
  168. int outputOffset)
  169. {
  170. int n;
  171. byte [] src;
  172. int srcOff;
  173. int res = 0;
  174. if (mode == FromBase64TransformMode.IgnoreWhiteSpaces) {
  175. n = Filter (inputBuffer, inputOffset, inputCount);
  176. src = filterBuffer;
  177. srcOff = 0;
  178. } else {
  179. n = inputCount;
  180. src = inputBuffer;
  181. srcOff = inputOffset;
  182. }
  183. int count = accPtr + n;
  184. if (count < 4) {
  185. Array.Copy (src, srcOff, accumulator, accPtr, n);
  186. accPtr = count;
  187. } else {
  188. byte [] tmpBuff = new byte [count];
  189. Array.Copy (accumulator, 0, tmpBuff, 0, accPtr);
  190. Array.Copy (src, srcOff, tmpBuff, accPtr, n);
  191. accPtr = count & 3;
  192. Array.Copy (src, srcOff + (n - accPtr), accumulator, 0, accPtr);
  193. res = DoTransform (tmpBuff, 0, count & (~3), outputBuffer, outputOffset);
  194. }
  195. return res;
  196. }
  197. /// <summary>
  198. /// </summary>
  199. public byte [] TransformFinalBlock (byte [] inputBuffer,
  200. int inputOffset,
  201. int inputCount)
  202. {
  203. byte [] src;
  204. int srcOff;
  205. int n;
  206. if (mode == FromBase64TransformMode.IgnoreWhiteSpaces) {
  207. n = Filter (inputBuffer, inputOffset, inputCount);
  208. src = filterBuffer;
  209. srcOff = 0;
  210. } else {
  211. n = inputCount;
  212. src = inputBuffer;
  213. srcOff = inputOffset;
  214. }
  215. int dataLen = accPtr + n;
  216. byte [] tmpBuf = new byte [dataLen];
  217. int resLen = ((dataLen) >> 2) * 3;
  218. byte [] res = new byte [resLen];
  219. Array.Copy (accumulator, 0, tmpBuf, 0, accPtr);
  220. Array.Copy (src, srcOff, tmpBuf, accPtr, n);
  221. int actLen = DoTransform (tmpBuf, 0, dataLen, res, 0);
  222. accPtr = 0;
  223. if (actLen < resLen) {
  224. byte [] newres = new byte [actLen];
  225. Array.Copy (res, newres, actLen);
  226. return newres;
  227. } else
  228. return res;
  229. }
  230. } // FromBase64Transform
  231. } // System.Security.Cryptography