Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

494 lines
12 KiB

  1. //+--------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 1999
  5. //
  6. // File: base64.cpp
  7. //
  8. // Contents: base64 encode/decode implementation
  9. //
  10. // History: 25-Jul-96 vich created
  11. //
  12. //---------------------------------------------------------------------------
  13. #include <windows.h>
  14. #include <assert.h>
  15. #include <dbgdef.h>
  16. #include "pkifmt.h"
  17. //#define BASE64_STRICT // enforce syntax check on input data
  18. #undef BASE64_STRICT // enforce syntax check on input data
  19. // The following table translates an ascii subset to 6 bit values as follows
  20. // (see RFC 1421 and/or RFC 1521):
  21. //
  22. // input hex (decimal)
  23. // 'A' --> 0x00 (0)
  24. // 'B' --> 0x01 (1)
  25. // ...
  26. // 'Z' --> 0x19 (25)
  27. // 'a' --> 0x1a (26)
  28. // 'b' --> 0x1b (27)
  29. // ...
  30. // 'z' --> 0x33 (51)
  31. // '0' --> 0x34 (52)
  32. // ...
  33. // '9' --> 0x3d (61)
  34. // '+' --> 0x3e (62)
  35. // '/' --> 0x3f (63)
  36. //
  37. // Encoded lines must be no longer than 76 characters.
  38. // The final "quantum" is handled as follows: The translation output shall
  39. // always consist of 4 characters. 'x', below, means a translated character,
  40. // and '=' means an equal sign. 0, 1 or 2 equal signs padding out a four byte
  41. // translation quantum means decoding the four bytes would result in 3, 2 or 1
  42. // unencoded bytes, respectively.
  43. //
  44. // unencoded size encoded data
  45. // -------------- ------------
  46. // 1 byte "xx=="
  47. // 2 bytes "xxx="
  48. // 3 bytes "xxxx"
  49. #define CB_BASE64LINEMAX 64 // others use 64 -- could be up to 76
  50. // Any other (invalid) input character value translates to 0x40 (64)
  51. const BYTE abDecode[256] =
  52. {
  53. /* 00: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  54. /* 10: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  55. /* 20: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
  56. /* 30: */ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
  57. /* 40: */ 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
  58. /* 50: */ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
  59. /* 60: */ 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
  60. /* 70: */ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
  61. /* 80: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  62. /* 90: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  63. /* a0: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  64. /* b0: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  65. /* c0: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  66. /* d0: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  67. /* e0: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  68. /* f0: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  69. };
  70. const UCHAR abEncode[] =
  71. /* 0 thru 25: */ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  72. /* 26 thru 51: */ "abcdefghijklmnopqrstuvwxyz"
  73. /* 52 thru 61: */ "0123456789"
  74. /* 62 and 63: */ "+/";
  75. #define MOD4(x) ((x) & 3)
  76. __inline BOOL
  77. _IsBase64WhiteSpace(
  78. IN TCHAR const ch)
  79. {
  80. return(
  81. ch == TEXT(' ') ||
  82. ch == TEXT('\t') ||
  83. ch == TEXT('\r') ||
  84. ch == TEXT('\n'));
  85. }
  86. DWORD
  87. Base64DecodeA(
  88. IN TCHAR const *pchIn,
  89. IN DWORD cchIn,
  90. OPTIONAL OUT BYTE *pbOut,
  91. IN OUT DWORD *pcbOut)
  92. {
  93. DWORD dwErr;
  94. DWORD cchInDecode, cbOutDecode;
  95. TCHAR const *pchInEnd;
  96. TCHAR const *pchInT;
  97. BYTE *pbOutT;
  98. // Count the translatable characters, skipping whitespace & CR-LF chars.
  99. cchInDecode = 0;
  100. pchInEnd = &pchIn[cchIn];
  101. dwErr = ERROR_INVALID_DATA;
  102. for (pchInT = pchIn; pchInT < pchInEnd; pchInT++)
  103. {
  104. if (sizeof(abDecode) < (unsigned) *pchInT || abDecode[*pchInT] > 63)
  105. {
  106. // Found a non-base64 character. Decide what to do.
  107. DWORD cch;
  108. if (_IsBase64WhiteSpace(*pchInT))
  109. {
  110. continue; // skip all whitespace
  111. }
  112. // The length calculation may stop in the middle of the last
  113. // translation quantum, because the equal sign padding characters
  114. // are treated as invalid input. If the last translation quantum
  115. // is not 4 bytes long, there must be 3, 2 or 1 equal sign(s).
  116. if (0 != cchInDecode)
  117. {
  118. cch = MOD4(cchInDecode);
  119. if (0 != cch)
  120. {
  121. cch = 4 - cch;
  122. while (0 != cch && pchInT < pchInEnd && '=' == *pchInT)
  123. {
  124. pchInT++;
  125. cch--;
  126. }
  127. }
  128. //#ifdef BASE64_STRICT
  129. if (0 == cch)
  130. //#endif
  131. {
  132. break;
  133. }
  134. }
  135. #if DBG
  136. DbgPrintf(
  137. DBG_SS_TRACE,
  138. "Bad base64 data: \"%.*" szFMTTSTR "...\"\n",
  139. min(16, SAFE_SUBTRACT_POINTERS(pchInEnd, pchInT)),
  140. pchInT);
  141. #endif //DBG
  142. goto BadBase64Data;
  143. }
  144. cchInDecode++; // only count valid base64 chars
  145. }
  146. assert(pchInT <= pchInEnd);
  147. #ifdef BASE64_STRICT
  148. if (pchInT < pchInEnd)
  149. {
  150. TCHAR const *pch;
  151. DWORD cchEqual = 0;
  152. for (pch = pchInT; pch < pchInEnd; pch++)
  153. {
  154. if (!_IsBase64WhiteSpace(*pch))
  155. {
  156. // Allow up to 3 extra trailing equal signs.
  157. if (TEXT('=') == *pch && 3 > cchEqual)
  158. {
  159. cchEqual++;
  160. continue;
  161. }
  162. #if DBG
  163. DbgPrintf(DBG_SS_TRACE,
  164. "Bad trailing base64 data: \"%.*" szFMTTSTR "...\"\n",
  165. min(16, SAFE_SUBTRACT_POINTERS(pchInEnd, pch)),
  166. pch);
  167. #endif //DBG
  168. goto BadTrailingBase64Data;
  169. }
  170. }
  171. #if DBG
  172. if (0 != cchEqual)
  173. {
  174. DbgPrintf(DBG_SS_TRACE,
  175. "Ignored trailing base64 data: \"%.*" szFMTTSTR "\"\n",
  176. cchEqual,
  177. TEXT("==="));
  178. }
  179. #endif //DBG
  180. }
  181. #endif
  182. pchInEnd = pchInT; // don't process any trailing stuff again
  183. // We know how many translatable characters are in the input buffer, so now
  184. // set the output buffer size to three bytes for every four (or fraction of
  185. // four) input bytes. Compensate for a fractional translation quantum.
  186. cbOutDecode = ((cchInDecode + 3) >> 2) * 3;
  187. switch (cchInDecode % 4)
  188. {
  189. case 1:
  190. case 2:
  191. cbOutDecode -= 2;
  192. break;
  193. case 3:
  194. cbOutDecode--;
  195. break;
  196. }
  197. pbOutT = pbOut;
  198. if (NULL == pbOut)
  199. {
  200. pbOutT += cbOutDecode;
  201. }
  202. else
  203. {
  204. // Decode one quantum at a time: 4 bytes ==> 3 bytes
  205. //assert(cbOutDecode <= *pcbOut);
  206. if (cbOutDecode > *pcbOut)
  207. {
  208. *pcbOut = cbOutDecode;
  209. dwErr = ERROR_MORE_DATA;
  210. goto MoreDataError;
  211. }
  212. pchInT = pchIn;
  213. while (cchInDecode > 0)
  214. {
  215. DWORD i;
  216. BYTE ab4[4];
  217. ZeroMemory(ab4, sizeof(ab4));
  218. for (i = 0; i < min(sizeof(ab4)/sizeof(ab4[0]), cchInDecode); i++)
  219. {
  220. while (
  221. sizeof(abDecode) > (unsigned) *pchInT &&
  222. 63 < abDecode[*pchInT])
  223. {
  224. pchInT++;
  225. }
  226. assert(pchInT < pchInEnd);
  227. ab4[i] = (BYTE) *pchInT++;
  228. }
  229. // Translate 4 input characters into 6 bits each, and deposit the
  230. // resulting 24 bits into 3 output bytes by shifting as appropriate.
  231. // out[0] = in[0]:in[1] 6:2
  232. // out[1] = in[1]:in[2] 4:4
  233. // out[2] = in[2]:in[3] 2:6
  234. *pbOutT++ =
  235. (BYTE) ((abDecode[ab4[0]] << 2) | (abDecode[ab4[1]] >> 4));
  236. if (i > 2)
  237. {
  238. *pbOutT++ =
  239. (BYTE) ((abDecode[ab4[1]] << 4) | (abDecode[ab4[2]] >> 2));
  240. }
  241. if (i > 3)
  242. {
  243. *pbOutT++ = (BYTE) ((abDecode[ab4[2]] << 6) | abDecode[ab4[3]]);
  244. }
  245. cchInDecode -= i;
  246. }
  247. assert((DWORD) (pbOutT - pbOut) <= cbOutDecode);
  248. }
  249. *pcbOut = SAFE_SUBTRACT_POINTERS(pbOutT, pbOut);
  250. dwErr = ERROR_SUCCESS;
  251. ErrorReturn:
  252. return dwErr;
  253. SET_ERROR(MoreDataError, dwErr)
  254. SET_ERROR(BadBase64Data, dwErr)
  255. #ifdef BASE64_STRICT
  256. SET_ERROR(BadTrailingBase64Data, dwErr)
  257. #endif
  258. }
  259. // Encode a BYTE array into a Base64 text string.
  260. // Use CR-LF pairs for line breaks, unless CRYPT_STRING_NOCR is set.
  261. // Do not '\0' terminate the text string -- that's handled by the caller.
  262. // Do not add -----BEGIN/END headers -- that's also handled by the caller.
  263. DWORD
  264. Base64EncodeA(
  265. IN BYTE const *pbIn,
  266. IN DWORD cbIn,
  267. IN DWORD Flags,
  268. OPTIONAL OUT TCHAR *pchOut,
  269. IN OUT DWORD *pcchOut)
  270. {
  271. DWORD dwErr;
  272. TCHAR *pchOutT;
  273. DWORD cchOutEncode;
  274. BOOL fNoCR = 0 != (CRYPT_STRING_NOCR & Flags);
  275. // Allocate enough memory for full final translation quantum.
  276. cchOutEncode = ((cbIn + 2) / 3) * 4;
  277. // and enough for CR-LF pairs for every CB_BASE64LINEMAX character line.
  278. cchOutEncode +=
  279. (fNoCR? 1 : 2) *
  280. ((cchOutEncode + CB_BASE64LINEMAX - 1) / CB_BASE64LINEMAX);
  281. pchOutT = pchOut;
  282. if (NULL == pchOut)
  283. {
  284. pchOutT += cchOutEncode;
  285. //printf("cchOut: =%x Computed=%x\n", (DWORD) (pchOutT - pchOut), cchOutEncode);
  286. }
  287. else
  288. {
  289. DWORD cCol;
  290. if (cchOutEncode > *pcchOut)
  291. {
  292. *pcchOut = cchOutEncode;
  293. dwErr = ERROR_MORE_DATA;
  294. goto MoreDataError;
  295. }
  296. cCol = 0;
  297. while ((long) cbIn > 0) // signed comparison -- cbIn can wrap
  298. {
  299. BYTE ab3[3];
  300. if (cCol == CB_BASE64LINEMAX/4)
  301. {
  302. cCol = 0;
  303. if (!fNoCR)
  304. {
  305. *pchOutT++ = '\r';
  306. }
  307. *pchOutT++ = '\n';
  308. }
  309. cCol++;
  310. ZeroMemory(ab3, sizeof(ab3));
  311. ab3[0] = *pbIn++;
  312. if (cbIn > 1)
  313. {
  314. ab3[1] = *pbIn++;
  315. if (cbIn > 2)
  316. {
  317. ab3[2] = *pbIn++;
  318. }
  319. }
  320. *pchOutT++ = abEncode[ab3[0] >> 2];
  321. *pchOutT++ = abEncode[((ab3[0] << 4) | (ab3[1] >> 4)) & 0x3f];
  322. *pchOutT++ = (cbIn > 1)?
  323. abEncode[((ab3[1] << 2) | (ab3[2] >> 6)) & 0x3f] : '=';
  324. *pchOutT++ = (cbIn > 2)? abEncode[ab3[2] & 0x3f] : '=';
  325. cbIn -= 3;
  326. }
  327. // Append CR-LF only if there was input data
  328. if (pchOutT != pchOut)
  329. {
  330. if (!fNoCR)
  331. {
  332. *pchOutT++ = '\r';
  333. }
  334. *pchOutT++ = '\n';
  335. }
  336. //printf("cchOut: Actual=%x Computed=%x Buffer=%x\n", (DWORD) (pchOutT - pchOut), cchOutEncode, *pcchOut);
  337. assert((DWORD) (pchOutT - pchOut) == cchOutEncode);
  338. }
  339. *pcchOut = SAFE_SUBTRACT_POINTERS(pchOutT, pchOut);
  340. dwErr = ERROR_SUCCESS;
  341. ErrorReturn:
  342. return dwErr;
  343. SET_ERROR(MoreDataError, dwErr)
  344. }
  345. DWORD
  346. Base64EncodeW(
  347. IN BYTE const *pbIn,
  348. IN DWORD cbIn,
  349. IN DWORD Flags,
  350. OUT WCHAR *wszOut,
  351. OUT DWORD *pcchOut)
  352. {
  353. DWORD cchOut;
  354. CHAR *pch = NULL;
  355. DWORD cch;
  356. DWORD err;
  357. assert(pcchOut != NULL);
  358. // only want to know how much to allocate
  359. // we know all base64 char map 1-1 with unicode
  360. if (wszOut == NULL)
  361. {
  362. // get the number of characters
  363. *pcchOut = 0;
  364. err = Base64EncodeA(pbIn, cbIn, Flags, NULL, pcchOut);
  365. }
  366. // otherwise we have an output buffer
  367. else {
  368. // char count is the same be it ascii or unicode,
  369. cchOut = *pcchOut;
  370. cch = 0;
  371. err = ERROR_OUTOFMEMORY;
  372. pch = (CHAR *) malloc(cchOut);
  373. if (NULL != pch)
  374. {
  375. err = Base64EncodeA(pbIn, cbIn, Flags, pch, &cchOut);
  376. if (ERROR_SUCCESS == err)
  377. {
  378. // should not fail!
  379. cch = MultiByteToWideChar(0, 0, pch, cchOut, wszOut, *pcchOut);
  380. // check to make sure we did not fail
  381. assert(*pcchOut == 0 || cch != 0);
  382. }
  383. }
  384. }
  385. if(pch != NULL)
  386. free(pch);
  387. return(err);
  388. }
  389. DWORD
  390. Base64DecodeW(
  391. IN const WCHAR * wszIn,
  392. IN DWORD cch,
  393. OUT BYTE *pbOut,
  394. OUT DWORD *pcbOut)
  395. {
  396. CHAR *pch;
  397. DWORD err = ERROR_SUCCESS;
  398. // in all cases we need to convert to an ascii string
  399. // we know the ascii string is less
  400. if ((pch = (CHAR *) malloc(cch)) == NULL)
  401. {
  402. err = ERROR_OUTOFMEMORY;
  403. }
  404. // we know no base64 wide char map to more than 1 ascii char
  405. else if (WideCharToMultiByte(0, 0, wszIn, cch, pch, cch, NULL, NULL) == 0)
  406. {
  407. err = ERROR_NO_DATA;
  408. }
  409. // get the length of the buffer
  410. else if (pbOut == NULL)
  411. {
  412. *pcbOut = 0;
  413. err = Base64Decode(pch, cch, NULL, pcbOut);
  414. }
  415. // otherwise fill in the buffer
  416. else {
  417. err = Base64Decode(pch, cch, pbOut, pcbOut);
  418. }
  419. if(pch != NULL)
  420. free(pch);
  421. return(err);
  422. }