Source code of Windows XP (NT5)
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.

454 lines
12 KiB

  1. //+--------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996-1996
  5. //
  6. // File: base64.cpp
  7. //
  8. // Contents: base64 encode/decode implementation
  9. //
  10. // History: 25-Jul-96 vich created
  11. //
  12. //---------------------------------------------------------------------------
  13. // 3-Mar-98 tompop took and modified it. Building
  14. // both Ansi and Wchar versions of Encode/Decode
  15. // base 64 for CertWizard, that is in IIS5's UI.
  16. // We merged the examples from NT5's base64.cpp
  17. // and ubase64.cpp files into this single file.
  18. // 5-Aug-98 Sergei Antonov removed above mentioned stuff after tompop
  19. //---------------------------------------------------------------------------
  20. #include "stdafx.h"
  21. #include <malloc.h>
  22. #include <windows.h>
  23. #include "base64.h"
  24. // The following table translates an ascii subset to 6 bit values as follows
  25. // (see rfc 1521):
  26. //
  27. // input hex (decimal)
  28. // 'A' --> 0x00 (0)
  29. // 'B' --> 0x01 (1)
  30. // ...
  31. // 'Z' --> 0x19 (25)
  32. // 'a' --> 0x1a (26)
  33. // 'b' --> 0x1b (27)
  34. // ...
  35. // 'z' --> 0x33 (51)
  36. // '0' --> 0x34 (52)
  37. // ...
  38. // '9' --> 0x3d (61)
  39. // '+' --> 0x3e (62)
  40. // '/' --> 0x3f (63)
  41. //
  42. // Encoded lines must be no longer than 76 characters.
  43. // The final "quantum" is handled as follows: The translation output shall
  44. // always consist of 4 characters. 'x', below, means a translated character,
  45. // and '=' means an equal sign. 0, 1 or 2 equal signs padding out a four byte
  46. // translation quantum means decoding the four bytes would result in 3, 2 or 1
  47. // unencoded bytes, respectively.
  48. //
  49. // unencoded size encoded data
  50. // -------------- ------------
  51. // 1 byte "xx=="
  52. // 2 bytes "xxx="
  53. // 3 bytes "xxxx"
  54. #define CB_BASE64LINEMAX 64 // others use 64 -- could be up to 76
  55. // Any other (invalid) input character value translates to 0x40 (64)
  56. const BYTE abDecode[256] =
  57. {
  58. /* 00: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  59. /* 10: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  60. /* 20: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
  61. /* 30: */ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
  62. /* 40: */ 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
  63. /* 50: */ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
  64. /* 60: */ 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
  65. /* 70: */ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
  66. /* 80: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  67. /* 90: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  68. /* a0: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  69. /* b0: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  70. /* c0: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  71. /* d0: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  72. /* e0: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  73. /* f0: */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  74. };
  75. const UCHAR abEncode[] =
  76. /* 0 thru 25: */ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  77. /* 26 thru 51: */ "abcdefghijklmnopqrstuvwxyz"
  78. /* 52 thru 61: */ "0123456789"
  79. /* 62 and 63: */ "+/";
  80. DWORD
  81. Base64DecodeA(const char * pchIn, DWORD cchIn, BYTE * pbOut, DWORD * pcbOut)
  82. {
  83. DWORD err = ERROR_SUCCESS;
  84. DWORD cchInDecode, cbOutDecode;
  85. CHAR const *pchInEnd;
  86. CHAR const *pchInT;
  87. BYTE *pbOutT;
  88. // Count the translatable characters, skipping whitespace & CR-LF chars.
  89. cchInDecode = 0;
  90. pchInEnd = &pchIn[cchIn];
  91. for (pchInT = pchIn; pchInT < pchInEnd; pchInT++)
  92. {
  93. if (sizeof(abDecode) < (unsigned) *pchInT || abDecode[*pchInT] > 63)
  94. {
  95. // skip all whitespace
  96. if ( *pchInT == ' '
  97. || *pchInT == '\t'
  98. || *pchInT == '\r'
  99. || *pchInT == '\n'
  100. )
  101. {
  102. continue;
  103. }
  104. if (0 != cchInDecode)
  105. {
  106. if ((cchInDecode % 4) == 0)
  107. {
  108. break; // ends on quantum boundary
  109. }
  110. // The length calculation may stop in the middle of the last
  111. // translation quantum, because the equal sign padding
  112. // characters are treated as invalid input. If the last
  113. // translation quantum is not 4 bytes long, it must be 2 or 3
  114. // bytes long.
  115. if (*pchInT == '=' && (cchInDecode % 4) != 1)
  116. {
  117. break; // normal termination
  118. }
  119. }
  120. err = ERROR_INVALID_DATA;
  121. goto error;
  122. }
  123. cchInDecode++;
  124. }
  125. ATLASSERT(pchInT <= pchInEnd);
  126. pchInEnd = pchInT; // don't process any trailing stuff again
  127. // We know how many translatable characters are in the input buffer, so now
  128. // set the output buffer size to three bytes for every four (or fraction of
  129. // four) input bytes.
  130. cbOutDecode = ((cchInDecode + 3) / 4) * 3;
  131. pbOutT = pbOut;
  132. if (NULL == pbOut)
  133. {
  134. pbOutT += cbOutDecode;
  135. }
  136. else
  137. {
  138. // Decode one quantum at a time: 4 bytes ==> 3 bytes
  139. ATLASSERT(cbOutDecode <= *pcbOut);
  140. pchInT = pchIn;
  141. while (cchInDecode > 0)
  142. {
  143. DWORD i;
  144. BYTE ab4[4];
  145. memset(ab4, 0, sizeof(ab4));
  146. for (i = 0; i < min(sizeof(ab4)/sizeof(ab4[0]), cchInDecode); i++)
  147. {
  148. while (
  149. sizeof(abDecode) > (unsigned) *pchInT &&
  150. 63 < abDecode[*pchInT])
  151. {
  152. pchInT++;
  153. }
  154. ATLASSERT(pchInT < pchInEnd);
  155. ab4[i] = (BYTE) *pchInT++;
  156. }
  157. // Translate 4 input characters into 6 bits each, and deposit the
  158. // resulting 24 bits into 3 output bytes by shifting as appropriate.
  159. // out[0] = in[0]:in[1] 6:2
  160. // out[1] = in[1]:in[2] 4:4
  161. // out[2] = in[2]:in[3] 2:6
  162. *pbOutT++ =
  163. (BYTE) ((abDecode[ab4[0]] << 2) | (abDecode[ab4[1]] >> 4));
  164. if (i > 2)
  165. {
  166. *pbOutT++ =
  167. (BYTE) ((abDecode[ab4[1]] << 4) | (abDecode[ab4[2]] >> 2));
  168. }
  169. if (i > 3)
  170. {
  171. *pbOutT++ = (BYTE) ((abDecode[ab4[2]] << 6) | abDecode[ab4[3]]);
  172. }
  173. cchInDecode -= i;
  174. }
  175. ATLASSERT((DWORD) (pbOutT - pbOut) <= cbOutDecode);
  176. }
  177. *pcbOut = (DWORD)(pbOutT - pbOut);
  178. error:
  179. return(err);
  180. }
  181. // Base64EncodeA
  182. //
  183. // RETURNS 0 (i.e. ERROR_SUCCESS) on success
  184. //
  185. DWORD
  186. Base64EncodeA(
  187. IN BYTE const *pbIn,
  188. IN DWORD cbIn,
  189. OUT CHAR *pchOut,
  190. OUT DWORD *pcchOut)
  191. {
  192. CHAR *pchOutT;
  193. DWORD cchOutEncode;
  194. // Allocate enough memory for full final translation quantum.
  195. cchOutEncode = ((cbIn + 2) / 3) * 4;
  196. // and enough for CR-LF pairs for every CB_BASE64LINEMAX character line.
  197. cchOutEncode +=
  198. 2 * ((cchOutEncode + CB_BASE64LINEMAX - 1) / CB_BASE64LINEMAX);
  199. pchOutT = pchOut;
  200. if (NULL == pchOut)
  201. {
  202. pchOutT += cchOutEncode;
  203. }
  204. else
  205. {
  206. DWORD cCol;
  207. ATLASSERT(cchOutEncode <= *pcchOut);
  208. cCol = 0;
  209. while ((long) cbIn > 0) // signed comparison -- cbIn can wrap
  210. {
  211. BYTE ab3[3];
  212. if (cCol == CB_BASE64LINEMAX/4)
  213. {
  214. cCol = 0;
  215. *pchOutT++ = '\r';
  216. *pchOutT++ = '\n';
  217. }
  218. cCol++;
  219. memset(ab3, 0, sizeof(ab3));
  220. ab3[0] = *pbIn++;
  221. if (cbIn > 1)
  222. {
  223. ab3[1] = *pbIn++;
  224. if (cbIn > 2)
  225. {
  226. ab3[2] = *pbIn++;
  227. }
  228. }
  229. *pchOutT++ = abEncode[ab3[0] >> 2];
  230. *pchOutT++ = abEncode[((ab3[0] << 4) | (ab3[1] >> 4)) & 0x3f];
  231. *pchOutT++ = (cbIn > 1)?
  232. abEncode[((ab3[1] << 2) | (ab3[2] >> 6)) & 0x3f] : '=';
  233. *pchOutT++ = (cbIn > 2)? abEncode[ab3[2] & 0x3f] : '=';
  234. cbIn -= 3;
  235. }
  236. *pchOutT++ = '\r';
  237. *pchOutT++ = '\n';
  238. ATLASSERT((DWORD) (pchOutT - pchOut) <= cchOutEncode);
  239. }
  240. *pcchOut = (DWORD)(pchOutT - pchOut);
  241. return(ERROR_SUCCESS);
  242. }
  243. // Base64EncodeW
  244. //
  245. // RETURNS 0 (i.e. ERROR_SUCCESS) on success
  246. //
  247. DWORD Base64EncodeW(
  248. BYTE const *pbIn,
  249. DWORD cbIn,
  250. WCHAR *wszOut,
  251. DWORD *pcchOut)
  252. {
  253. DWORD cchOut;
  254. char *pch = NULL;
  255. DWORD cch;
  256. DWORD err;
  257. ATLASSERT(pcchOut != NULL);
  258. // only want to know how much to allocate
  259. // we know all base64 char map 1-1 with unicode
  260. if( wszOut == NULL ) {
  261. // get the number of characters
  262. *pcchOut = 0;
  263. err = Base64EncodeA(
  264. pbIn,
  265. cbIn,
  266. NULL,
  267. pcchOut);
  268. }
  269. // otherwise we have an output buffer
  270. else {
  271. // char count is the same be it ascii or unicode,
  272. cchOut = *pcchOut;
  273. cch = 0;
  274. err = ERROR_OUTOFMEMORY;
  275. if( (pch = (char *) malloc(cchOut)) != NULL &&
  276. (err = Base64EncodeA(
  277. pbIn,
  278. cbIn,
  279. pch,
  280. &cchOut)) == ERROR_SUCCESS ) {
  281. // should not fail!
  282. cch = MultiByteToWideChar(0,
  283. 0,
  284. pch,
  285. cchOut,
  286. wszOut,
  287. *pcchOut);
  288. // check to make sure we did not fail
  289. ATLASSERT(*pcchOut == 0 || cch != 0);
  290. }
  291. }
  292. if(pch != NULL)
  293. free(pch);
  294. return(err);
  295. }
  296. // Base64DecodeW
  297. //
  298. // RETURNS 0 (i.e. ERROR_SUCCESS) on success
  299. //
  300. DWORD Base64DecodeW(
  301. const WCHAR * wszIn,
  302. DWORD cch,
  303. BYTE *pbOut,
  304. DWORD *pcbOut)
  305. {
  306. char *pch;
  307. DWORD err = ERROR_SUCCESS;
  308. if( (pch = (char *) malloc(cch)) == NULL )
  309. {
  310. err = ERROR_OUTOFMEMORY;
  311. }
  312. else if( WideCharToMultiByte(0, 0, wszIn, cch, pch, cch,
  313. NULL, NULL) == 0 )
  314. {
  315. err = ERROR_NO_DATA;
  316. }
  317. else if( pbOut == NULL )
  318. {
  319. *pcbOut = 0;
  320. err = Base64DecodeA(pch, cch, NULL, pcbOut);
  321. }
  322. else
  323. {
  324. err = Base64DecodeA(pch, cch, pbOut, pcbOut);
  325. }
  326. if(pch != NULL)
  327. free(pch);
  328. return(err);
  329. }
  330. #if 0
  331. // sanity tests... Lets make sure that the encode and decode
  332. // works...
  333. BOOL test_Base64EncodeW()
  334. {
  335. BYTE pbIn[120]; // for the test we just use the random stack data
  336. DWORD cbIn = sizeof( pbIn );
  337. WCHAR *wszB64Out;
  338. DWORD pcchB64Out;
  339. DWORD err;
  340. // BASE64 encode pkcs 10
  341. if( (err = Base64EncodeW(
  342. pbIn,
  343. cbIn,
  344. NULL,
  345. &pcchB64Out)) != ERROR_SUCCESS ||
  346. (wszB64Out = (WCHAR *) _alloca(pcchB64Out * sizeof(WCHAR))) == NULL ||
  347. (err = Base64EncodeW(
  348. pbIn,
  349. cbIn,
  350. wszB64Out,
  351. &pcchB64Out)) != ERROR_SUCCESS )
  352. {
  353. SetLastError(err);
  354. return FALSE; //goto ErrorBase64Encode;
  355. }
  356. // well the encode worked lets test the decode
  357. //
  358. // pcchB64Out holds the B64 data length
  359. // wszB64Out holds the actual data
  360. DWORD blob_cbData; // we store in these variables what
  361. BYTE* blob_pbData; // we read in..
  362. // They should match the stuff stored in:
  363. // BYTE pbIn[120];
  364. // DWORD cbIn = sizeof( pbIn );
  365. // This we be tested after the decode.
  366. // base64 decode
  367. if( (err = Base64DecodeW(
  368. wszB64Out,
  369. pcchB64Out,
  370. NULL,
  371. &blob_cbData)) != ERROR_SUCCESS ||
  372. (blob_pbData = (BYTE *) _alloca(blob_cbData)) == NULL ||
  373. (err = Base64DecodeW(
  374. wszB64Out,
  375. pcchB64Out,
  376. blob_pbData,
  377. &blob_cbData)) != ERROR_SUCCESS )
  378. {
  379. SetLastError(err);
  380. return(FALSE); //goto ErrorBase64Decode;
  381. }
  382. //do compare
  383. return( (blob_cbData==cbIn)
  384. && (memcmp(blob_pbData, pbIn,cbIn)==0) );
  385. }
  386. #endif