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.

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