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.

616 lines
15 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. base64.cxx
  5. Abstract:
  6. base64
  7. Author:
  8. Larry Zhu (LZhu) December 1, 2001 Created
  9. Environment:
  10. User Mode
  11. Revision History:
  12. --*/
  13. #include "precomp.hxx"
  14. #pragma hdrstop
  15. #include "base64.h"
  16. //#define BASE64_STRICT // enforce syntax check on input data
  17. #undef BASE64_STRICT // enforce syntax check on input data
  18. // The following table translates an ascii subset to 6 bit values as follows
  19. // (see RFC 1421 and/or RFC 1521):
  20. //
  21. // input hex (decimal)
  22. // 'A' --> 0x00 (0)
  23. // 'B' --> 0x01 (1)
  24. // ...
  25. // 'Z' --> 0x19 (25)
  26. // 'a' --> 0x1a (26)
  27. // 'b' --> 0x1b (27)
  28. // ...
  29. // 'z' --> 0x33 (51)
  30. // '0' --> 0x34 (52)
  31. // ...
  32. // '9' --> 0x3d (61)
  33. // '+' --> 0x3e (62)
  34. // '/' --> 0x3f (63)
  35. //
  36. // Encoded lines must be no longer than 76 characters.
  37. // The final "quantum" is handled as follows: The translation output shall
  38. // always consist of 4 characters. 'x', below, means a translated character,
  39. // and '=' means an equal sign. 0, 1 or 2 equal signs padding out a four byte
  40. // translation quantum means decoding the four bytes would result in 3, 2 or 1
  41. // unencoded bytes, respectively.
  42. //
  43. // unencoded size encoded data
  44. // -------------- ------------
  45. // 1 byte "xx=="
  46. // 2 bytes "xxx="
  47. // 3 bytes "xxxx"
  48. #define CB_BASE64LINEMAX 64 // others use 64 -- could be up to 76
  49. // Any other (invalid) input character value translates to 0x40 (64)
  50. const BYTE abDecode[256] =
  51. {
  52. /* 00: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  53. /* 10: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  54. /* 20: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
  55. /* 30: */ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
  56. /* 40: */ 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
  57. /* 50: */ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
  58. /* 60: */ 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
  59. /* 70: */ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
  60. /* 80: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  61. /* 90: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  62. /* a0: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  63. /* b0: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  64. /* c0: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  65. /* d0: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  66. /* e0: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  67. /* f0: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  68. };
  69. const UCHAR abEncode[] =
  70. /* 0 thru 25: */ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  71. /* 26 thru 51: */ "abcdefghijklmnopqrstuvwxyz"
  72. /* 52 thru 61: */ "0123456789"
  73. /* 62 and 63: */ "+/";
  74. #define MOD4(x) ((x) & 3)
  75. __inline BOOL
  76. _IsBase64WhiteSpace(
  77. IN TCHAR const ch
  78. )
  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 CHAR const *pchIn,
  89. IN DWORD cchIn,
  90. OPTIONAL OUT BYTE *pbOut,
  91. IN OUT DWORD *pcbOut
  92. )
  93. {
  94. DWORD dwErr;
  95. DWORD cchInDecode, cbOutDecode;
  96. CHAR const *pchInEnd;
  97. CHAR const *pchInT;
  98. BYTE *pbOutT;
  99. // Count the translatable characters, skipping whitespace & CR-LF chars.
  100. cchInDecode = 0;
  101. pchInEnd = &pchIn[cchIn];
  102. dwErr = ERROR_INVALID_DATA;
  103. for (pchInT = pchIn; pchInT < pchInEnd; pchInT++)
  104. {
  105. if (sizeof(abDecode) < (unsigned) *pchInT || abDecode[*pchInT] > 63)
  106. {
  107. // Found a non-base64 character. Decide what to do.
  108. DWORD cch;
  109. if (_IsBase64WhiteSpace(*pchInT))
  110. {
  111. continue; // skip all whitespace
  112. }
  113. // The length calculation may stop in the middle of the last
  114. // translation quantum, because the equal sign padding characters
  115. // are treated as invalid input. If the last translation quantum
  116. // is not 4 bytes long, there must be 3, 2 or 1 equal sign(s).
  117. if (0 != cchInDecode)
  118. {
  119. cch = MOD4(cchInDecode);
  120. if (0 != cch)
  121. {
  122. cch = 4 - cch;
  123. while (0 != cch && pchInT < pchInEnd && '=' == *pchInT)
  124. {
  125. pchInT++;
  126. cch--;
  127. }
  128. }
  129. //#ifdef BASE64_STRICT
  130. if (0 == cch)
  131. //#endif
  132. {
  133. break;
  134. }
  135. }
  136. goto ErrorReturn;
  137. }
  138. cchInDecode++; // only count valid base64 chars
  139. }
  140. assert(pchInT <= pchInEnd);
  141. #ifdef BASE64_STRICT
  142. if (pchInT < pchInEnd)
  143. {
  144. CHAR const *pch;
  145. DWORD cchEqual = 0;
  146. for (pch = pchInT; pch < pchInEnd; pch++)
  147. {
  148. if (!_IsBase64WhiteSpace(*pch))
  149. {
  150. // Allow up to 3 extra trailing equal signs.
  151. if (TEXT('=') == *pch && 3 > cchEqual)
  152. {
  153. cchEqual++;
  154. continue;
  155. }
  156. goto BadTrailingBase64Data;
  157. }
  158. }
  159. }
  160. #endif
  161. pchInEnd = pchInT; // don't process any trailing stuff again
  162. // We know how many translatable characters are in the input buffer, so now
  163. // set the output buffer size to three bytes for every four (or fraction of
  164. // four) input bytes. Compensate for a fractional translation quantum.
  165. cbOutDecode = ((cchInDecode + 3) >> 2) * 3;
  166. switch (cchInDecode % 4)
  167. {
  168. case 1:
  169. case 2:
  170. cbOutDecode -= 2;
  171. break;
  172. case 3:
  173. cbOutDecode--;
  174. break;
  175. }
  176. pbOutT = pbOut;
  177. if (NULL == pbOut)
  178. {
  179. pbOutT += cbOutDecode;
  180. }
  181. else
  182. {
  183. // Decode one quantum at a time: 4 bytes ==> 3 bytes
  184. //assert(cbOutDecode <= *pcbOut);
  185. if (cbOutDecode > *pcbOut)
  186. {
  187. *pcbOut = cbOutDecode;
  188. dwErr = ERROR_MORE_DATA;
  189. goto ErrorReturn;
  190. }
  191. pchInT = pchIn;
  192. while (cchInDecode > 0)
  193. {
  194. DWORD i;
  195. BYTE ab4[4];
  196. ZeroMemory(ab4, sizeof(ab4));
  197. for (i = 0; i < min(sizeof(ab4)/sizeof(ab4[0]), cchInDecode); i++)
  198. {
  199. while (
  200. sizeof(abDecode) > (unsigned) *pchInT &&
  201. 63 < abDecode[*pchInT])
  202. {
  203. pchInT++;
  204. }
  205. assert(pchInT < pchInEnd);
  206. ab4[i] = (BYTE) *pchInT++;
  207. }
  208. // Translate 4 input characters into 6 bits each, and deposit the
  209. // resulting 24 bits into 3 output bytes by shifting as appropriate.
  210. // out[0] = in[0]:in[1] 6:2
  211. // out[1] = in[1]:in[2] 4:4
  212. // out[2] = in[2]:in[3] 2:6
  213. *pbOutT++ =
  214. (BYTE) ((abDecode[ab4[0]] << 2) | (abDecode[ab4[1]] >> 4));
  215. if (i > 2)
  216. {
  217. *pbOutT++ =
  218. (BYTE) ((abDecode[ab4[1]] << 4) | (abDecode[ab4[2]] >> 2));
  219. }
  220. if (i > 3)
  221. {
  222. *pbOutT++ = (BYTE) ((abDecode[ab4[2]] << 6) | abDecode[ab4[3]]);
  223. }
  224. cchInDecode -= i;
  225. }
  226. assert((DWORD) (pbOutT - pbOut) <= cbOutDecode);
  227. }
  228. *pcbOut = SAFE_SUBTRACT_POINTERS(pbOutT, pbOut);
  229. dwErr = ERROR_SUCCESS;
  230. ErrorReturn:
  231. return dwErr;
  232. }
  233. // Encode a BYTE array into a Base64 text string.
  234. // Use CR-LF pairs for line breaks, unless CRYPT_STRING_NOCR is set.
  235. // Do not '\0' terminate the text string -- that's handled by the caller.
  236. // Do not add -----BEGIN/END headers -- that's also handled by the caller.
  237. DWORD
  238. Base64EncodeA(
  239. IN BYTE const *pbIn,
  240. IN DWORD cbIn,
  241. IN DWORD Flags,
  242. OPTIONAL OUT CHAR *pchOut,
  243. IN OUT DWORD *pcchOut
  244. )
  245. {
  246. DWORD dwErr;
  247. CHAR *pchOutT;
  248. DWORD cchOutEncode;
  249. BOOL fNoCR = 0 != (CRYPT_STRING_NOCR & Flags);
  250. // Allocate enough memory for full final translation quantum.
  251. cchOutEncode = ((cbIn + 2) / 3) * 4;
  252. // and enough for CR-LF pairs for every CB_BASE64LINEMAX character line.
  253. cchOutEncode +=
  254. (fNoCR? 1 : 2) *
  255. ((cchOutEncode + CB_BASE64LINEMAX - 1) / CB_BASE64LINEMAX);
  256. pchOutT = pchOut;
  257. if (NULL == pchOut)
  258. {
  259. pchOutT += cchOutEncode;
  260. //printf("cchOut: =%x Computed=%x\n", (DWORD) (pchOutT - pchOut), cchOutEncode);
  261. }
  262. else
  263. {
  264. DWORD cCol;
  265. if (cchOutEncode > *pcchOut)
  266. {
  267. *pcchOut = cchOutEncode;
  268. dwErr = ERROR_MORE_DATA;
  269. goto ErrorReturn;
  270. }
  271. cCol = 0;
  272. while ((long) cbIn > 0) // signed comparison -- cbIn can wrap
  273. {
  274. BYTE ab3[3];
  275. if (cCol == CB_BASE64LINEMAX/4)
  276. {
  277. cCol = 0;
  278. if (!fNoCR)
  279. {
  280. *pchOutT++ = '\r';
  281. }
  282. *pchOutT++ = '\n';
  283. }
  284. cCol++;
  285. ZeroMemory(ab3, sizeof(ab3));
  286. ab3[0] = *pbIn++;
  287. if (cbIn > 1)
  288. {
  289. ab3[1] = *pbIn++;
  290. if (cbIn > 2)
  291. {
  292. ab3[2] = *pbIn++;
  293. }
  294. }
  295. *pchOutT++ = abEncode[ab3[0] >> 2];
  296. *pchOutT++ = abEncode[((ab3[0] << 4) | (ab3[1] >> 4)) & 0x3f];
  297. *pchOutT++ = (cbIn > 1)?
  298. abEncode[((ab3[1] << 2) | (ab3[2] >> 6)) & 0x3f] : '=';
  299. *pchOutT++ = (cbIn > 2)? abEncode[ab3[2] & 0x3f] : '=';
  300. cbIn -= 3;
  301. }
  302. // Append CR-LF only if there was input data
  303. if (pchOutT != pchOut)
  304. {
  305. if (!fNoCR)
  306. {
  307. *pchOutT++ = '\r';
  308. }
  309. *pchOutT++ = '\n';
  310. }
  311. //printf("cchOut: Actual=%x Computed=%x Buffer=%x\n", (DWORD) (pchOutT - pchOut), cchOutEncode, *pcchOut);
  312. assert((DWORD) (pchOutT - pchOut) == cchOutEncode);
  313. }
  314. *pcchOut = SAFE_SUBTRACT_POINTERS(pchOutT, pchOut);
  315. dwErr = ERROR_SUCCESS;
  316. ErrorReturn:
  317. return dwErr;
  318. }
  319. DWORD
  320. Base64EncodeW(
  321. IN BYTE const *pbIn,
  322. IN DWORD cbIn,
  323. IN DWORD Flags,
  324. OUT WCHAR *wszOut,
  325. OUT DWORD *pcchOut
  326. )
  327. {
  328. DWORD cchOut;
  329. CHAR *pch = NULL;
  330. DWORD cch;
  331. DWORD err;
  332. assert(pcchOut != NULL);
  333. // only want to know how much to allocate
  334. // we know all base64 char map 1-1 with unicode
  335. if (wszOut == NULL)
  336. {
  337. // get the number of characters
  338. *pcchOut = 0;
  339. err = Base64EncodeA(pbIn, cbIn, Flags, NULL, pcchOut);
  340. }
  341. // otherwise we have an output buffer
  342. else {
  343. // char count is the same be it ascii or unicode,
  344. cchOut = *pcchOut;
  345. cch = 0;
  346. err = ERROR_OUTOFMEMORY;
  347. pch = (CHAR *) malloc(cchOut);
  348. if (NULL != pch)
  349. {
  350. err = Base64EncodeA(pbIn, cbIn, Flags, pch, &cchOut);
  351. if (ERROR_SUCCESS == err)
  352. {
  353. // should not fail!
  354. cch = MultiByteToWideChar(0, 0, pch, cchOut, wszOut, *pcchOut);
  355. // check to make sure we did not fail
  356. assert(*pcchOut == 0 || cch != 0);
  357. }
  358. }
  359. }
  360. if(pch != NULL)
  361. free(pch);
  362. return(err);
  363. }
  364. DWORD
  365. Base64DecodeW(
  366. IN const WCHAR * wszIn,
  367. IN DWORD cch,
  368. OUT BYTE *pbOut,
  369. OUT DWORD *pcbOut
  370. )
  371. {
  372. CHAR *pch;
  373. DWORD err = ERROR_SUCCESS;
  374. // in all cases we need to convert to an ascii string
  375. // we know the ascii string is less
  376. if ((pch = (CHAR *) malloc(cch)) == NULL)
  377. {
  378. err = ERROR_OUTOFMEMORY;
  379. }
  380. // we know no base64 wide char map to more than 1 ascii char
  381. else if (WideCharToMultiByte(0, 0, wszIn, cch, pch, cch, NULL, NULL) == 0)
  382. {
  383. err = ERROR_NO_DATA;
  384. }
  385. // get the length of the buffer
  386. else if (pbOut == NULL)
  387. {
  388. *pcbOut = 0;
  389. err = Base64DecodeA(pch, cch, NULL, pcbOut);
  390. }
  391. // otherwise fill in the buffer
  392. else {
  393. err = Base64DecodeA(pch, cch, pbOut, pcbOut);
  394. }
  395. if(pch != NULL)
  396. free(pch);
  397. return(err);
  398. }
  399. //
  400. // some helper functions to facilitate debugging
  401. //
  402. HRESULT
  403. ReadBytes(
  404. IN PCSTR pszFileName,
  405. OUT BYTE** ppBuffer,
  406. OUT ULONG* pcbBuffer
  407. )
  408. {
  409. THResult hRetval = S_OK;
  410. ULONG temp = 0;
  411. BYTE* pBuffer = NULL;
  412. ULONG cbBuffer = 0;
  413. FILE* file = NULL;
  414. *pcbBuffer = 0;
  415. *ppBuffer = NULL;
  416. DebugPrintf(SSPI_LOG, "ReadBytes from file %s\n", pszFileName);
  417. file = fopen(pszFileName, "r");
  418. hRetval DBGCHK = file ? S_OK : GetLastErrorAsHResult();
  419. if (SUCCEEDED(hRetval))
  420. {
  421. while (EOF != (temp = getc(file)))
  422. {
  423. if (!_IsBase64WhiteSpace(static_cast<CHAR>(temp)))
  424. {
  425. cbBuffer++;
  426. }
  427. }
  428. rewind(file);
  429. pBuffer = new BYTE[cbBuffer + 2];
  430. hRetval DBGCHK = pBuffer ? S_OK : E_OUTOFMEMORY;
  431. }
  432. if (SUCCEEDED(hRetval))
  433. {
  434. RtlZeroMemory(pBuffer, cbBuffer + 2);
  435. for ( UCHAR* p = (UCHAR*) pBuffer;
  436. (p < pBuffer + cbBuffer) && (EOF != (temp = getc(file)));
  437. /* p++ */ )
  438. {
  439. if (_IsBase64WhiteSpace(static_cast<CHAR>(temp)))
  440. {
  441. continue;
  442. }
  443. *p++ = static_cast<CHAR>(temp);
  444. }
  445. *ppBuffer = pBuffer;
  446. pBuffer = NULL;
  447. *pcbBuffer = cbBuffer;
  448. }
  449. if (pBuffer)
  450. {
  451. delete [] pBuffer;
  452. }
  453. return hRetval;
  454. }
  455. INT
  456. __cdecl
  457. main(
  458. IN INT argc,
  459. IN PSTR argv[]
  460. )
  461. {
  462. THResult hRetval = E_FAIL;
  463. BYTE* pBuffer = NULL;
  464. ULONG cbBuffer = 0;
  465. BYTE* pResult = NULL;
  466. ULONG cbResult = 0;
  467. if (argc != 2)
  468. {
  469. DebugPrintf(SSPI_ERROR, "Usage: %s <file name>\n", argv[0]);
  470. exit(-1);
  471. }
  472. hRetval DBGCHK = ReadBytes(argv[1], &pBuffer, &cbBuffer);
  473. if (SUCCEEDED(hRetval))
  474. {
  475. hRetval DBGCHK = HResultFromWin32(Base64DecodeA(reinterpret_cast<PCSTR>(pBuffer), cbBuffer, NULL, &cbResult));
  476. }
  477. if (SUCCEEDED(hRetval))
  478. {
  479. pResult = new BYTE[cbResult];
  480. hRetval DBGCHK = pResult ? S_OK : E_OUTOFMEMORY;
  481. }
  482. if (SUCCEEDED(hRetval))
  483. {
  484. hRetval DBGCHK = HResultFromWin32(Base64DecodeA(reinterpret_cast<PCSTR>(pBuffer), cbBuffer, pResult, &cbResult));
  485. }
  486. if (SUCCEEDED(hRetval))
  487. {
  488. DebugPrintf(SSPI_LOG, "Decoded buffer and length: %#x %#x\n", pResult, cbResult);
  489. //
  490. // pause here
  491. //
  492. ASSERT(FALSE);
  493. }
  494. if (pResult)
  495. {
  496. delete [] pResult;
  497. }
  498. if (pBuffer)
  499. {
  500. delete [] pBuffer;
  501. }
  502. return 0;
  503. }