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.

665 lines
18 KiB

  1. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2. Microsoft Windows
  3. Copyright (C) Microsoft Corporation, 1995 - 1999.
  4. File: Base64.cpp
  5. Contents: Implementation of Base64 routines.
  6. Functions: Encode
  7. Decode
  8. History: 11-15-99 dsie created
  9. ------------------------------------------------------------------------------*/
  10. #include "StdAfx.h"
  11. #include "CAPICOM.h"
  12. #include "Base64.h"
  13. #include "Convert.h"
  14. #if (0) //DSIE: 10/29/2001
  15. #ifdef CAPICOM_BASE64_STRICT
  16. #define BASE64_STRICT // enforce syntax check on input data
  17. #else
  18. #undef BASE64_STRICT // enforce syntax check on input data
  19. #endif
  20. // The following table translates an ascii subset to 6 bit values as follows
  21. // (see RFC 1421 and/or RFC 1521):
  22. //
  23. // input hex (decimal)
  24. // 'A' --> 0x00 (0)
  25. // 'B' --> 0x01 (1)
  26. // ...
  27. // 'Z' --> 0x19 (25)
  28. // 'a' --> 0x1a (26)
  29. // 'b' --> 0x1b (27)
  30. // ...
  31. // 'z' --> 0x33 (51)
  32. // '0' --> 0x34 (52)
  33. // ...
  34. // '9' --> 0x3d (61)
  35. // '+' --> 0x3e (62)
  36. // '/' --> 0x3f (63)
  37. //
  38. // Encoded lines must be no longer than 76 characters.
  39. // The final "quantum" is handled as follows: The translation output shall
  40. // always consist of 4 characters. 'x', below, means a translated character,
  41. // and '=' means an equal sign. 0, 1 or 2 equal signs padding out a four byte
  42. // translation quantum means decoding the four bytes would result in 3, 2 or 1
  43. // unencoded bytes, respectively.
  44. //
  45. // unencoded size encoded data
  46. // -------------- ------------
  47. // 1 byte "xx=="
  48. // 2 bytes "xxx="
  49. // 3 bytes "xxxx"
  50. #define CB_BASE64LINEMAX 64 // others use 64 -- could be up to 76
  51. // Any other (invalid) input character value translates to 0x40 (64)
  52. const BYTE abDecode[256] =
  53. {
  54. /* 00: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  55. /* 10: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  56. /* 20: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
  57. /* 30: */ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
  58. /* 40: */ 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
  59. /* 50: */ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
  60. /* 60: */ 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
  61. /* 70: */ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
  62. /* 80: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  63. /* 90: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  64. /* a0: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  65. /* b0: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  66. /* c0: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  67. /* d0: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  68. /* e0: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  69. /* f0: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  70. };
  71. const UCHAR abEncode[] =
  72. /* 0 thru 25: */ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  73. /* 26 thru 51: */ "abcdefghijklmnopqrstuvwxyz"
  74. /* 52 thru 61: */ "0123456789"
  75. /* 62 and 63: */ "+/";
  76. #define MOD4(x) ((x) & 3)
  77. __inline BOOL _IsBase64WhiteSpace(IN TCHAR const ch)
  78. {
  79. return(ch == TEXT(' ') ||
  80. ch == TEXT('\t') ||
  81. ch == TEXT('\r') ||
  82. ch == TEXT('\n'));
  83. }
  84. DWORD Base64DecodeA(IN TCHAR const * pchIn,
  85. IN DWORD cchIn,
  86. OPTIONAL OUT BYTE * pbOut,
  87. IN OUT DWORD * pcbOut)
  88. {
  89. DWORD dwErr;
  90. DWORD cchInDecode, cbOutDecode;
  91. TCHAR const *pchInEnd;
  92. TCHAR const *pchInT;
  93. BYTE *pbOutT;
  94. //
  95. // Count the translatable characters, skipping whitespace & CR-LF chars.
  96. //
  97. cchInDecode = 0;
  98. pchInEnd = &pchIn[cchIn];
  99. dwErr = ERROR_INVALID_DATA;
  100. for (pchInT = pchIn; pchInT < pchInEnd; pchInT++)
  101. {
  102. if (sizeof(abDecode) < (unsigned) *pchInT || abDecode[*pchInT] > 63)
  103. {
  104. //
  105. // Found a non-base64 character. Decide what to do.
  106. //
  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. if (0 == cch)
  129. {
  130. break;
  131. }
  132. }
  133. DebugTrace("Error: %c is an invlaid base64 data.\n", *pchInT);
  134. goto ErrorExit;
  135. }
  136. cchInDecode++; // only count valid base64 chars
  137. }
  138. ATLASSERT(pchInT <= pchInEnd);
  139. #ifdef BASE64_STRICT
  140. if (pchInT < pchInEnd)
  141. {
  142. TCHAR const *pch;
  143. DWORD cchEqual = 0;
  144. for (pch = pchInT; pch < pchInEnd; pch++)
  145. {
  146. if (!_IsBase64WhiteSpace(*pch))
  147. {
  148. // Allow up to 3 extra trailing equal signs.
  149. if (TEXT('=') == *pch && 3 > cchEqual)
  150. {
  151. cchEqual++;
  152. continue;
  153. }
  154. DebugTrace("Error: %c is an invalid trailing base64 data.\n", pch);
  155. goto ErrorExit;
  156. }
  157. }
  158. #if _DEBUG
  159. if (0 != cchEqual)
  160. {
  161. DebugTrace("Info: Ignoring trailing base64 data ===.\n");
  162. }
  163. #endif // _DEBUG
  164. }
  165. #endif // BASE64_STRICT
  166. pchInEnd = pchInT; // don't process any trailing stuff again
  167. // We know how many translatable characters are in the input buffer, so now
  168. // set the output buffer size to three bytes for every four (or fraction of
  169. // four) input bytes. Compensate for a fractional translation quantum.
  170. cbOutDecode = ((cchInDecode + 3) >> 2) * 3;
  171. switch (cchInDecode % 4)
  172. {
  173. case 1:
  174. case 2:
  175. cbOutDecode -= 2;
  176. break;
  177. case 3:
  178. cbOutDecode--;
  179. break;
  180. }
  181. pbOutT = pbOut;
  182. if (NULL == pbOut)
  183. {
  184. pbOutT += cbOutDecode;
  185. }
  186. else
  187. {
  188. // Decode one quantum at a time: 4 bytes ==> 3 bytes
  189. if (cbOutDecode > *pcbOut)
  190. {
  191. *pcbOut = cbOutDecode;
  192. dwErr = ERROR_MORE_DATA;
  193. goto ErrorExit;
  194. }
  195. pchInT = pchIn;
  196. while (cchInDecode > 0)
  197. {
  198. DWORD i;
  199. BYTE ab4[4];
  200. ZeroMemory(ab4, sizeof(ab4));
  201. for (i = 0; i < min(sizeof(ab4)/sizeof(ab4[0]), cchInDecode); i++)
  202. {
  203. while (sizeof(abDecode) > (unsigned) *pchInT &&
  204. 63 < abDecode[*pchInT])
  205. {
  206. pchInT++;
  207. }
  208. ATLASSERT(pchInT < pchInEnd);
  209. ab4[i] = (BYTE) *pchInT++;
  210. }
  211. // Translate 4 input characters into 6 bits each, and deposit the
  212. // resulting 24 bits into 3 output bytes by shifting as appropriate.
  213. // out[0] = in[0]:in[1] 6:2
  214. // out[1] = in[1]:in[2] 4:4
  215. // out[2] = in[2]:in[3] 2:6
  216. *pbOutT++ = (BYTE) ((abDecode[ab4[0]] << 2) | (abDecode[ab4[1]] >> 4));
  217. if (i > 2)
  218. {
  219. *pbOutT++ = (BYTE) ((abDecode[ab4[1]] << 4) | (abDecode[ab4[2]] >> 2));
  220. }
  221. if (i > 3)
  222. {
  223. *pbOutT++ = (BYTE) ((abDecode[ab4[2]] << 6) | abDecode[ab4[3]]);
  224. }
  225. cchInDecode -= i;
  226. }
  227. ATLASSERT((DWORD) (pbOutT - pbOut) <= cbOutDecode);
  228. }
  229. *pcbOut = SAFE_SUBTRACT_POINTERS(pbOutT, pbOut);
  230. dwErr = ERROR_SUCCESS;
  231. CommonExit:
  232. return dwErr;
  233. ErrorExit:
  234. //
  235. // Sanity check.
  236. //
  237. ATLASSERT(ERROR_SUCCESS != dwErr);
  238. goto CommonExit;
  239. }
  240. // Encode a BYTE array into a Base64 text string.
  241. // Use CR-LF pairs for line breaks, unless CRYPT_STRING_NOCR is set.
  242. // Do not '\0' terminate the text string -- that's handled by the caller.
  243. // Do not add -----BEGIN/END headers -- that's also handled by the caller.
  244. DWORD Base64EncodeA(IN BYTE const * pbIn,
  245. IN DWORD cbIn,
  246. IN DWORD Flags,
  247. OPTIONAL OUT TCHAR * pchOut,
  248. IN OUT DWORD * pcchOut)
  249. {
  250. DWORD dwErr;
  251. TCHAR *pchOutT;
  252. DWORD cchOutEncode;
  253. BOOL fNoCR = 0 != (CRYPT_STRING_NOCR & Flags);
  254. // Allocate enough memory for full final translation quantum.
  255. cchOutEncode = ((cbIn + 2) / 3) * 4;
  256. // and enough for CR-LF pairs for every CB_BASE64LINEMAX character line.
  257. cchOutEncode += (fNoCR? 1 : 2) * ((cchOutEncode + CB_BASE64LINEMAX - 1) / CB_BASE64LINEMAX);
  258. pchOutT = pchOut;
  259. if (NULL == pchOut)
  260. {
  261. pchOutT += cchOutEncode;
  262. }
  263. else
  264. {
  265. DWORD cCol;
  266. if (cchOutEncode > *pcchOut)
  267. {
  268. *pcchOut = cchOutEncode;
  269. dwErr = ERROR_MORE_DATA;
  270. goto ErrorExit;
  271. }
  272. cCol = 0;
  273. while ((long) cbIn > 0) // signed comparison -- cbIn can wrap
  274. {
  275. BYTE ab3[3];
  276. if (cCol == CB_BASE64LINEMAX/4)
  277. {
  278. cCol = 0;
  279. if (!fNoCR)
  280. {
  281. *pchOutT++ = '\r';
  282. }
  283. *pchOutT++ = '\n';
  284. }
  285. cCol++;
  286. ZeroMemory(ab3, sizeof(ab3));
  287. ab3[0] = *pbIn++;
  288. if (cbIn > 1)
  289. {
  290. ab3[1] = *pbIn++;
  291. if (cbIn > 2)
  292. {
  293. ab3[2] = *pbIn++;
  294. }
  295. }
  296. *pchOutT++ = abEncode[ab3[0] >> 2];
  297. *pchOutT++ = abEncode[((ab3[0] << 4) | (ab3[1] >> 4)) & 0x3f];
  298. *pchOutT++ = (cbIn > 1)? 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. ATLASSERT((DWORD) (pchOutT - pchOut) == cchOutEncode);
  312. }
  313. *pcchOut = SAFE_SUBTRACT_POINTERS(pchOutT, pchOut);
  314. dwErr = ERROR_SUCCESS;
  315. CommonExit:
  316. return dwErr;
  317. ErrorExit:
  318. ATLASSERT(ERROR_SUCCESS != dwErr);
  319. goto CommonExit;
  320. }
  321. DWORD Base64EncodeW(IN BYTE const * pbIn,
  322. IN DWORD cbIn,
  323. IN DWORD Flags,
  324. OUT WCHAR * wszOut,
  325. OUT DWORD * pcchOut)
  326. {
  327. DWORD cchOut;
  328. CHAR *pch = NULL;
  329. DWORD cch;
  330. DWORD dwErr;
  331. ATLASSERT(pcchOut != NULL);
  332. // only want to know how much to allocate
  333. // we know all base64 char map 1-1 with unicode
  334. if (wszOut == NULL)
  335. {
  336. // get the number of characters
  337. *pcchOut = 0;
  338. dwErr = Base64EncodeA(pbIn, cbIn, Flags, NULL, pcchOut);
  339. }
  340. else // otherwise we have an output buffer
  341. {
  342. // char count is the same be it ascii or unicode,
  343. cchOut = *pcchOut;
  344. cch = 0;
  345. dwErr = ERROR_OUTOFMEMORY;
  346. pch = (CHAR *) malloc(cchOut);
  347. if (NULL != pch)
  348. {
  349. dwErr = Base64EncodeA(pbIn, cbIn, Flags, pch, &cchOut);
  350. if (ERROR_SUCCESS == dwErr)
  351. {
  352. // should not fail!
  353. cch = MultiByteToWideChar(0, 0, pch, cchOut, wszOut, *pcchOut);
  354. // check to make sure we did not fail
  355. ATLASSERT(*pcchOut == 0 || cch != 0);
  356. }
  357. }
  358. }
  359. if(pch != NULL)
  360. {
  361. free(pch);
  362. }
  363. return(dwErr);
  364. }
  365. DWORD Base64DecodeW(IN const WCHAR * wszIn,
  366. IN DWORD cch,
  367. OUT BYTE * pbOut,
  368. OUT DWORD * pcbOut)
  369. {
  370. CHAR *pch;
  371. DWORD dwErr = ERROR_SUCCESS;
  372. // in all cases we need to convert to an ascii string
  373. // we know the ascii string is less
  374. if ((pch = (CHAR *) malloc(cch)) == NULL)
  375. {
  376. dwErr = ERROR_OUTOFMEMORY;
  377. }
  378. // we know no base64 wide char map to more than 1 ascii char
  379. else if (WideCharToMultiByte(0, 0, wszIn, cch, pch, cch, NULL, NULL) == 0)
  380. {
  381. dwErr = ERROR_NO_DATA;
  382. }
  383. // get the length of the buffer
  384. else if (pbOut == NULL)
  385. {
  386. *pcbOut = 0;
  387. dwErr = Base64DecodeA(pch, cch, NULL, pcbOut);
  388. }
  389. // otherwise fill in the buffer
  390. else
  391. {
  392. dwErr = Base64DecodeA(pch, cch, pbOut, pcbOut);
  393. }
  394. if(pch != NULL)
  395. {
  396. free(pch);
  397. }
  398. return(dwErr);
  399. }
  400. #endif
  401. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  402. Function : Base64Encode
  403. Synopsis : Base64 encode the blob.
  404. Parameter: DATA_BLOB DataBlob - DATA_BLOB to be base64 encoded.
  405. BSTR * pbstrEncoded - Pointer to BSTR to receive the base64
  406. encoded blob.
  407. Remark :
  408. ------------------------------------------------------------------------------*/
  409. HRESULT Base64Encode (DATA_BLOB DataBlob,
  410. BSTR * pbstrEncoded)
  411. {
  412. HRESULT hr = S_OK;
  413. DWORD dwEncodedSize = 0;
  414. BSTR bstrEncoded = NULL;
  415. DebugTrace("Entering Base64Encode()\n");
  416. //
  417. // Sanity check.
  418. //
  419. ATLASSERT(pbstrEncoded);
  420. try
  421. {
  422. //
  423. // Make sure parameters are valid.
  424. //
  425. if (!DataBlob.cbData || !DataBlob.pbData)
  426. {
  427. hr = E_INVALIDARG;
  428. DebugTrace("Error: base64 encoding of empty data not allowed.\n");
  429. goto ErrorExit;
  430. }
  431. //
  432. // Convert to base64.
  433. //
  434. if (FAILED(hr = ::BinaryToString(DataBlob.pbData,
  435. DataBlob.cbData,
  436. CRYPT_STRING_BASE64,
  437. &bstrEncoded,
  438. &dwEncodedSize)))
  439. {
  440. DebugTrace("Error [%#x]: BinaryToString() failed.\n", hr);
  441. goto ErrorExit;
  442. }
  443. //
  444. // Return base64 encoded BSTR to caller.
  445. //
  446. *pbstrEncoded = bstrEncoded;
  447. }
  448. catch(...)
  449. {
  450. hr = E_POINTER;
  451. DebugTrace("Exception: invalid parameter.\n");
  452. goto ErrorExit;
  453. }
  454. CommonExit:
  455. DebugTrace("Leaving Base64Encode()\n");
  456. return hr;
  457. ErrorExit:
  458. //
  459. // Sanity check.
  460. //
  461. ATLASSERT(FAILED(hr));
  462. //
  463. // Free resource.
  464. //
  465. if (bstrEncoded)
  466. {
  467. ::SysFreeString(bstrEncoded);
  468. }
  469. goto CommonExit;
  470. }
  471. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  472. Function : Base64Decode
  473. Synopsis : Decode the base64 encoded blob.
  474. Parameter: BSTR bstrEncoded - BSTR of base64 encoded blob to decode.
  475. DATA_BLOB * pDataBlob - Pointer to DATA_BLOB to receive decoded
  476. data blob.
  477. Remark :
  478. ------------------------------------------------------------------------------*/
  479. HRESULT Base64Decode (BSTR bstrEncoded,
  480. DATA_BLOB * pDataBlob)
  481. {
  482. HRESULT hr = S_OK;
  483. DWORD dwEncodedSize = 0;
  484. DATA_BLOB DataBlob = {0, NULL};
  485. DebugTrace("Entering Base64Decode()\n");
  486. //
  487. // Sanity check.
  488. //
  489. ATLASSERT(bstrEncoded);
  490. ATLASSERT(pDataBlob);
  491. try
  492. {
  493. //
  494. // Make sure parameters are valid.
  495. //
  496. if (0 == (dwEncodedSize = ::SysStringLen(bstrEncoded)))
  497. {
  498. hr = E_INVALIDARG;
  499. DebugTrace("Error: invalid parameter, empty base64 encoded data not allowed.\n");
  500. goto ErrorExit;
  501. }
  502. //
  503. // Base64 decode.
  504. //
  505. if (FAILED(hr = ::StringToBinary(bstrEncoded,
  506. dwEncodedSize,
  507. CRYPT_STRING_BASE64_ANY,
  508. &DataBlob.pbData,
  509. &DataBlob.cbData)))
  510. {
  511. DebugTrace("Error [%#x]: StringToBinary() failed.\n", hr);
  512. goto ErrorExit;
  513. }
  514. //
  515. // Return base64 decoded blob to caller.
  516. //
  517. *pDataBlob = DataBlob;
  518. }
  519. catch(...)
  520. {
  521. hr = E_POINTER;
  522. DebugTrace("Exception: invalid parameter.\n");
  523. goto ErrorExit;
  524. }
  525. CommonExit:
  526. DebugTrace("Leaving Base64Decode()\n");
  527. return hr;
  528. ErrorExit:
  529. //
  530. // Sanity check.
  531. //
  532. ATLASSERT(FAILED(hr));
  533. //
  534. // Free resource.
  535. //
  536. if (DataBlob.pbData)
  537. {
  538. ::CoTaskMemFree(DataBlob.pbData);
  539. }
  540. goto CommonExit;
  541. }