Base64Encoder.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using System.IO;
  5. namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities.Encoders
  6. {
  7. public class Base64Encoder
  8. : IEncoder
  9. {
  10. protected readonly byte[] encodingTable =
  11. {
  12. (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
  13. (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
  14. (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
  15. (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
  16. (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
  17. (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
  18. (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
  19. (byte)'v',
  20. (byte)'w', (byte)'x', (byte)'y', (byte)'z',
  21. (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6',
  22. (byte)'7', (byte)'8', (byte)'9',
  23. (byte)'+', (byte)'/'
  24. };
  25. protected byte padding = (byte)'=';
  26. /*
  27. * set up the decoding table.
  28. */
  29. protected readonly byte[] decodingTable = new byte[128];
  30. protected void InitialiseDecodingTable()
  31. {
  32. Arrays.Fill(decodingTable, (byte)0xff);
  33. for (int i = 0; i < encodingTable.Length; i++)
  34. {
  35. decodingTable[encodingTable[i]] = (byte)i;
  36. }
  37. }
  38. public Base64Encoder()
  39. {
  40. InitialiseDecodingTable();
  41. }
  42. public int Encode(byte[] inBuf, int inOff, int inLen, byte[] outBuf, int outOff)
  43. {
  44. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  45. return Encode(inBuf.AsSpan(inOff, inLen), outBuf.AsSpan(outOff));
  46. #else
  47. int inPos = inOff;
  48. int inEnd = inOff + inLen - 2;
  49. int outPos = outOff;
  50. while (inPos < inEnd)
  51. {
  52. uint a1 = inBuf[inPos++];
  53. uint a2 = inBuf[inPos++];
  54. uint a3 = inBuf[inPos++];
  55. outBuf[outPos++] = encodingTable[(a1 >> 2) & 0x3F];
  56. outBuf[outPos++] = encodingTable[((a1 << 4) | (a2 >> 4)) & 0x3F];
  57. outBuf[outPos++] = encodingTable[((a2 << 2) | (a3 >> 6)) & 0x3F];
  58. outBuf[outPos++] = encodingTable[a3 & 0x3F];
  59. }
  60. switch (inLen - (inPos - inOff))
  61. {
  62. case 1:
  63. {
  64. uint a1 = inBuf[inPos++];
  65. outBuf[outPos++] = encodingTable[(a1 >> 2) & 0x3F];
  66. outBuf[outPos++] = encodingTable[(a1 << 4) & 0x3F];
  67. outBuf[outPos++] = padding;
  68. outBuf[outPos++] = padding;
  69. break;
  70. }
  71. case 2:
  72. {
  73. uint a1 = inBuf[inPos++];
  74. uint a2 = inBuf[inPos++];
  75. outBuf[outPos++] = encodingTable[(a1 >> 2) & 0x3F];
  76. outBuf[outPos++] = encodingTable[((a1 << 4) | (a2 >> 4)) & 0x3F];
  77. outBuf[outPos++] = encodingTable[(a2 << 2) & 0x3F];
  78. outBuf[outPos++] = padding;
  79. break;
  80. }
  81. }
  82. return outPos - outOff;
  83. #endif
  84. }
  85. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  86. public int Encode(ReadOnlySpan<byte> input, Span<byte> output)
  87. {
  88. int inPos = 0;
  89. int inEnd = input.Length - 2;
  90. int outPos = 0;
  91. while (inPos < inEnd)
  92. {
  93. uint a1 = input[inPos++];
  94. uint a2 = input[inPos++];
  95. uint a3 = input[inPos++];
  96. output[outPos++] = encodingTable[(a1 >> 2) & 0x3F];
  97. output[outPos++] = encodingTable[((a1 << 4) | (a2 >> 4)) & 0x3F];
  98. output[outPos++] = encodingTable[((a2 << 2) | (a3 >> 6)) & 0x3F];
  99. output[outPos++] = encodingTable[a3 & 0x3F];
  100. }
  101. switch (input.Length - inPos)
  102. {
  103. case 1:
  104. {
  105. uint a1 = input[inPos++];
  106. output[outPos++] = encodingTable[(a1 >> 2) & 0x3F];
  107. output[outPos++] = encodingTable[(a1 << 4) & 0x3F];
  108. output[outPos++] = padding;
  109. output[outPos++] = padding;
  110. break;
  111. }
  112. case 2:
  113. {
  114. uint a1 = input[inPos++];
  115. uint a2 = input[inPos++];
  116. output[outPos++] = encodingTable[(a1 >> 2) & 0x3F];
  117. output[outPos++] = encodingTable[((a1 << 4) | (a2 >> 4)) & 0x3F];
  118. output[outPos++] = encodingTable[(a2 << 2) & 0x3F];
  119. output[outPos++] = padding;
  120. break;
  121. }
  122. }
  123. return outPos;
  124. }
  125. #endif
  126. /**
  127. * encode the input data producing a base 64 output stream.
  128. *
  129. * @return the number of bytes produced.
  130. */
  131. public int Encode(byte[] buf, int off, int len, Stream outStream)
  132. {
  133. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  134. return Encode(buf.AsSpan(off, len), outStream);
  135. #else
  136. if (len < 0)
  137. return 0;
  138. byte[] tmp = new byte[72];
  139. int remaining = len;
  140. while (remaining > 0)
  141. {
  142. int inLen = System.Math.Min(54, remaining);
  143. int outLen = Encode(buf, off, inLen, tmp, 0);
  144. outStream.Write(tmp, 0, outLen);
  145. off += inLen;
  146. remaining -= inLen;
  147. }
  148. return (len + 2) / 3 * 4;
  149. #endif
  150. }
  151. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  152. public int Encode(ReadOnlySpan<byte> data, Stream outStream)
  153. {
  154. Span<byte> tmp = stackalloc byte[72];
  155. int result = (data.Length + 2) / 3 * 4;
  156. while (!data.IsEmpty)
  157. {
  158. int inLen = System.Math.Min(54, data.Length);
  159. int outLen = Encode(data[..inLen], tmp);
  160. outStream.Write(tmp[..outLen]);
  161. data = data[inLen..];
  162. }
  163. return result;
  164. }
  165. #endif
  166. private bool Ignore(char c)
  167. {
  168. return c == '\n' || c =='\r' || c == '\t' || c == ' ';
  169. }
  170. /**
  171. * decode the base 64 encoded byte data writing it to the given output stream,
  172. * whitespace characters will be ignored.
  173. *
  174. * @return the number of bytes produced.
  175. */
  176. public int Decode(byte[] data, int off, int length, Stream outStream)
  177. {
  178. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  179. return Decode(data.AsSpan(off, length), outStream);
  180. #else
  181. byte b1, b2, b3, b4;
  182. byte[] outBuffer = new byte[54]; // S/MIME standard
  183. int bufOff = 0;
  184. int outLen = 0;
  185. int end = off + length;
  186. while (end > off)
  187. {
  188. if (!Ignore((char)data[end - 1]))
  189. break;
  190. end--;
  191. }
  192. int finish = end - 4;
  193. int i = NextI(data, off, finish);
  194. while (i < finish)
  195. {
  196. b1 = decodingTable[data[i++]];
  197. i = NextI(data, i, finish);
  198. b2 = decodingTable[data[i++]];
  199. i = NextI(data, i, finish);
  200. b3 = decodingTable[data[i++]];
  201. i = NextI(data, i, finish);
  202. b4 = decodingTable[data[i++]];
  203. if ((b1 | b2 | b3 | b4) >= 0x80)
  204. throw new IOException("invalid characters encountered in base64 data");
  205. outBuffer[bufOff++] = (byte)((b1 << 2) | (b2 >> 4));
  206. outBuffer[bufOff++] = (byte)((b2 << 4) | (b3 >> 2));
  207. outBuffer[bufOff++] = (byte)((b3 << 6) | b4);
  208. if (bufOff == outBuffer.Length)
  209. {
  210. outStream.Write(outBuffer, 0, bufOff);
  211. bufOff = 0;
  212. }
  213. outLen += 3;
  214. i = NextI(data, i, finish);
  215. }
  216. if (bufOff > 0)
  217. {
  218. outStream.Write(outBuffer, 0, bufOff);
  219. }
  220. int e0 = NextI(data, i, end);
  221. int e1 = NextI(data, e0 + 1, end);
  222. int e2 = NextI(data, e1 + 1, end);
  223. int e3 = NextI(data, e2 + 1, end);
  224. outLen += DecodeLastBlock(outStream, (char)data[e0], (char)data[e1], (char)data[e2], (char)data[e3]);
  225. return outLen;
  226. #endif
  227. }
  228. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  229. public int Decode(ReadOnlySpan<byte> data, Stream outStream)
  230. {
  231. byte b1, b2, b3, b4;
  232. Span<byte> outBuffer = stackalloc byte[54]; // S/MIME standard
  233. int bufOff = 0;
  234. int outLen = 0;
  235. int end = data.Length;
  236. while (end > 0)
  237. {
  238. if (!Ignore((char)data[end - 1]))
  239. break;
  240. end--;
  241. }
  242. int finish = end - 4;
  243. int i = NextI(data, 0, finish);
  244. while (i < finish)
  245. {
  246. b1 = decodingTable[data[i++]];
  247. i = NextI(data, i, finish);
  248. b2 = decodingTable[data[i++]];
  249. i = NextI(data, i, finish);
  250. b3 = decodingTable[data[i++]];
  251. i = NextI(data, i, finish);
  252. b4 = decodingTable[data[i++]];
  253. if ((b1 | b2 | b3 | b4) >= 0x80)
  254. throw new IOException("invalid characters encountered in base64 data");
  255. outBuffer[bufOff++] = (byte)((b1 << 2) | (b2 >> 4));
  256. outBuffer[bufOff++] = (byte)((b2 << 4) | (b3 >> 2));
  257. outBuffer[bufOff++] = (byte)((b3 << 6) | b4);
  258. if (bufOff == outBuffer.Length)
  259. {
  260. outStream.Write(outBuffer);
  261. bufOff = 0;
  262. }
  263. outLen += 3;
  264. i = NextI(data, i, finish);
  265. }
  266. if (bufOff > 0)
  267. {
  268. outStream.Write(outBuffer[..bufOff]);
  269. }
  270. int e0 = NextI(data, i, end);
  271. int e1 = NextI(data, e0 + 1, end);
  272. int e2 = NextI(data, e1 + 1, end);
  273. int e3 = NextI(data, e2 + 1, end);
  274. outLen += DecodeLastBlock(outStream, (char)data[e0], (char)data[e1], (char)data[e2], (char)data[e3]);
  275. return outLen;
  276. }
  277. #endif
  278. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  279. private int NextI(ReadOnlySpan<byte> data, int i, int finish)
  280. #else
  281. private int NextI(byte[] data, int i, int finish)
  282. #endif
  283. {
  284. while ((i < finish) && Ignore((char)data[i]))
  285. {
  286. i++;
  287. }
  288. return i;
  289. }
  290. /**
  291. * decode the base 64 encoded string data writing it to the given output stream,
  292. * whitespace characters will be ignored.
  293. *
  294. * @return the number of bytes produced.
  295. */
  296. public int DecodeString(string data, Stream outStream)
  297. {
  298. // Platform Implementation
  299. // byte[] bytes = Convert.FromBase64String(data);
  300. // outStream.Write(bytes, 0, bytes.Length);
  301. // return bytes.Length;
  302. byte b1, b2, b3, b4;
  303. int length = 0;
  304. int end = data.Length;
  305. while (end > 0)
  306. {
  307. if (!Ignore(data[end - 1]))
  308. break;
  309. end--;
  310. }
  311. int finish = end - 4;
  312. int i = NextI(data, 0, finish);
  313. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  314. Span<byte> buf = stackalloc byte[3];
  315. #endif
  316. while (i < finish)
  317. {
  318. b1 = decodingTable[data[i++]];
  319. i = NextI(data, i, finish);
  320. b2 = decodingTable[data[i++]];
  321. i = NextI(data, i, finish);
  322. b3 = decodingTable[data[i++]];
  323. i = NextI(data, i, finish);
  324. b4 = decodingTable[data[i++]];
  325. if ((b1 | b2 | b3 | b4) >= 0x80)
  326. throw new IOException("invalid characters encountered in base64 data");
  327. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  328. buf[0] = (byte)((b1 << 2) | (b2 >> 4));
  329. buf[1] = (byte)((b2 << 4) | (b3 >> 2));
  330. buf[2] = (byte)((b3 << 6) | b4);
  331. outStream.Write(buf);
  332. #else
  333. outStream.WriteByte((byte)((b1 << 2) | (b2 >> 4)));
  334. outStream.WriteByte((byte)((b2 << 4) | (b3 >> 2)));
  335. outStream.WriteByte((byte)((b3 << 6) | b4));
  336. #endif
  337. length += 3;
  338. i = NextI(data, i, finish);
  339. }
  340. length += DecodeLastBlock(outStream, data[end - 4], data[end - 3], data[end - 2], data[end - 1]);
  341. return length;
  342. }
  343. private int DecodeLastBlock(
  344. Stream outStream,
  345. char c1,
  346. char c2,
  347. char c3,
  348. char c4)
  349. {
  350. if (c3 == padding)
  351. {
  352. if (c4 != padding)
  353. throw new IOException("invalid characters encountered at end of base64 data");
  354. byte b1 = decodingTable[c1];
  355. byte b2 = decodingTable[c2];
  356. if ((b1 | b2) >= 0x80)
  357. throw new IOException("invalid characters encountered at end of base64 data");
  358. outStream.WriteByte((byte)((b1 << 2) | (b2 >> 4)));
  359. return 1;
  360. }
  361. if (c4 == padding)
  362. {
  363. byte b1 = decodingTable[c1];
  364. byte b2 = decodingTable[c2];
  365. byte b3 = decodingTable[c3];
  366. if ((b1 | b2 | b3) >= 0x80)
  367. throw new IOException("invalid characters encountered at end of base64 data");
  368. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  369. Span<byte> buf = stackalloc byte[2] {
  370. (byte)((b1 << 2) | (b2 >> 4)),
  371. (byte)((b2 << 4) | (b3 >> 2)),
  372. };
  373. outStream.Write(buf);
  374. #else
  375. outStream.WriteByte((byte)((b1 << 2) | (b2 >> 4)));
  376. outStream.WriteByte((byte)((b2 << 4) | (b3 >> 2)));
  377. #endif
  378. return 2;
  379. }
  380. {
  381. byte b1 = decodingTable[c1];
  382. byte b2 = decodingTable[c2];
  383. byte b3 = decodingTable[c3];
  384. byte b4 = decodingTable[c4];
  385. if ((b1 | b2 | b3 | b4) >= 0x80)
  386. throw new IOException("invalid characters encountered at end of base64 data");
  387. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  388. Span<byte> buf = stackalloc byte[3] {
  389. (byte)((b1 << 2) | (b2 >> 4)),
  390. (byte)((b2 << 4) | (b3 >> 2)),
  391. (byte)((b3 << 6) | b4),
  392. };
  393. outStream.Write(buf);
  394. #else
  395. outStream.WriteByte((byte)((b1 << 2) | (b2 >> 4)));
  396. outStream.WriteByte((byte)((b2 << 4) | (b3 >> 2)));
  397. outStream.WriteByte((byte)((b3 << 6) | b4));
  398. #endif
  399. return 3;
  400. }
  401. }
  402. private int NextI(string data, int i, int finish)
  403. {
  404. while ((i < finish) && Ignore(data[i]))
  405. {
  406. i++;
  407. }
  408. return i;
  409. }
  410. }
  411. }
  412. #pragma warning restore
  413. #endif