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.

328 lines
7.3 KiB

  1. // CoCrypt.cpp: implementation of the CCoCrypt class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "stdafx.h"
  5. #include "CoCrypt.h"
  6. #include "hmac.h"
  7. #include "BstrDebug.h"
  8. #include <winsock2.h> // ntohl, htonl
  9. #include <time.h>
  10. #include <crypt.h>
  11. #define PASSPORT_MAC_LEN 10
  12. BOOL
  13. GenTextIV(unsigned char *pIV) // makes the assumption that IV is 8 bytes long
  14. // since the below code uses 3DES this is OK for now
  15. {
  16. int i;
  17. BOOL fResult;
  18. // generate a random IV
  19. fResult = RtlGenRandom(pIV, 8);
  20. if (!fResult)
  21. return FALSE;
  22. // castrate the random IV into base 64 characters (makes the IV only have
  23. // ~48 bits of entropy instead of 64 but that should be fine
  24. for (i = 0; i < 8; i++)
  25. {
  26. // mod the character to make sure its less than 62
  27. pIV[i] = pIV[i] % 62;
  28. // add the appropriate character value to make it a base 64 character
  29. if (pIV[i] <= 9)
  30. pIV[i] = pIV[i] + '0';
  31. else if (pIV[i] <= 35)
  32. pIV[i] = pIV[i] + 'a' - 10 ;
  33. else
  34. pIV[i] = pIV[i] + 'A' - 36 ;
  35. }
  36. return TRUE;
  37. }
  38. //////////////////////////////////////////////////////////////////////
  39. // Construction/Destruction
  40. //////////////////////////////////////////////////////////////////////
  41. CBinHex CCoCrypt::m_binhex;
  42. CCoCrypt::CCoCrypt() : m_ok(FALSE)
  43. {
  44. }
  45. CCoCrypt::~CCoCrypt()
  46. {
  47. }
  48. BOOL CCoCrypt::Decrypt(LPWSTR rawData,
  49. UINT dataSize,
  50. BSTR *ppUnencrypted)
  51. {
  52. unsigned char *pb = NULL;
  53. unsigned char ivec[9];
  54. ULONG lSize, i;
  55. unsigned char pad;
  56. unsigned char hmac[10];
  57. HRESULT hr;
  58. BOOL fResult = FALSE;
  59. *ppUnencrypted = NULL;
  60. // must be kv + ivec + bh(hmac) long at LEAST
  61. if (sizeof(hmac) + sizeof(ivec) + 4 > dataSize)
  62. {
  63. goto Cleanup;
  64. }
  65. lSize = dataSize - sizeof(WCHAR);
  66. // allocate a buffer for the resulting data
  67. pb = new unsigned char[lSize];
  68. if (NULL == pb)
  69. {
  70. goto Cleanup;
  71. }
  72. // decode from base 64
  73. hr = m_binhex.PartFromWideBase64(rawData + 1 + 9, pb, &lSize);
  74. if (S_OK != hr)
  75. {
  76. goto Cleanup;
  77. }
  78. for (i = 0; i < 9; i++)
  79. ivec[i] = (unsigned char) rawData[i + 1];
  80. pad = ivec[8];
  81. // Now lsize holds the # of bytes outputted, which after hmac should be %8=0
  82. if ((lSize - sizeof(hmac)) % 8 || lSize <= sizeof(hmac))
  83. {
  84. goto Cleanup;
  85. }
  86. for (i = 0; i < lSize - sizeof(hmac); i+=8)
  87. {
  88. CBC(tripledes,
  89. DES_BLOCKLEN,
  90. pb + sizeof(hmac) + i,
  91. pb + sizeof(hmac) + i,
  92. &ks,
  93. DECRYPT,
  94. (BYTE*)ivec);
  95. }
  96. // Padding must be >0 and <8
  97. //if (rawData[8]-65 > 7 || rawData[8] < 65)
  98. if((pad - 65) > 7 || pad < 65)
  99. {
  100. goto Cleanup;
  101. }
  102. // Now check hmac
  103. hmac_sha(m_keyMaterial,
  104. DES3_KEYSIZE,
  105. pb + sizeof(hmac),
  106. lSize - sizeof(hmac),
  107. hmac, sizeof(hmac));
  108. if (memcmp(hmac, pb, sizeof(hmac)) != 0)
  109. {
  110. goto Cleanup;
  111. }
  112. // do a BSTR type allocation to accomodate calling code
  113. *ppUnencrypted = ALLOC_AND_GIVEAWAY_BSTR_BYTE_LEN((char*)(pb+sizeof(hmac)), lSize - sizeof(hmac) - (pad - 65));
  114. if (NULL == *ppUnencrypted)
  115. {
  116. goto Cleanup;
  117. }
  118. fResult = TRUE;
  119. Cleanup:
  120. if (pb)
  121. {
  122. delete[] pb;
  123. }
  124. return fResult;
  125. }
  126. BOOL CCoCrypt::Encrypt(int keyVersion,
  127. LPSTR rawData,
  128. UINT dataSize,
  129. BSTR *ppEncrypted)
  130. {
  131. int cbPadding = 0;
  132. char ivec[9];
  133. BOOL fResult;
  134. *ppEncrypted = NULL;
  135. // Find out how big the encrypted blob needs to be:
  136. // The final pack is:
  137. // <KeyVersion><IVEC><PADCOUNT>BINHEX(HMAC+3DES(DATA+PAD))
  138. //
  139. // So, we're concerned with the size of HMAC+3DES(DATA+PAD)
  140. // because BinHex will handle the rest
  141. if (dataSize % DES_BLOCKLEN)
  142. {
  143. cbPadding = (DES_BLOCKLEN - (dataSize % DES_BLOCKLEN)); // + PAD, if necessary
  144. }
  145. // gen the IV
  146. fResult = GenTextIV((unsigned char*)ivec);
  147. if (!fResult)
  148. {
  149. goto Cleanup;
  150. }
  151. encrypt(ivec, cbPadding, keyVersion, rawData, dataSize, ppEncrypted);
  152. fResult = TRUE;
  153. Cleanup:
  154. return fResult;
  155. }
  156. BOOL CCoCrypt::encrypt(char ivec[9],
  157. int cbPadding,
  158. int keyVersion,
  159. LPSTR rawData,
  160. UINT cbData,
  161. BSTR *ppEncrypted)
  162. {
  163. unsigned char *pb = NULL;
  164. char ivec2[8];
  165. HRESULT hr;
  166. BOOL fResult = FALSE;
  167. // Compute HMAC+3DES(DATA+PAD)
  168. ivec[8] = (char) cbPadding + 65;
  169. // allocate a buffer for the resulting data
  170. // length of data + length of padding + size of HMAC + size of IV
  171. pb = new unsigned char[cbData + cbPadding + 10 + 8];
  172. if (NULL == pb)
  173. {
  174. goto Cleanup;
  175. }
  176. memcpy(ivec2, ivec, DES_BLOCKLEN);
  177. memcpy(pb + PASSPORT_MAC_LEN, rawData, cbData); // copy data after the HMAC
  178. //randomize padding
  179. fResult = RtlGenRandom(pb + PASSPORT_MAC_LEN + cbData, cbPadding);
  180. if (!fResult)
  181. {
  182. fResult = FALSE;
  183. goto Cleanup;
  184. }
  185. // Compute HMAC
  186. hmac_sha(m_keyMaterial, DES3_KEYSIZE, pb + PASSPORT_MAC_LEN, cbData + cbPadding, pb, PASSPORT_MAC_LEN);
  187. for (int i = 0; i < (int)cbData + cbPadding; i+=8)
  188. {
  189. CBC(tripledes, DES_BLOCKLEN, pb + PASSPORT_MAC_LEN + i, pb + PASSPORT_MAC_LEN + i, &ks, ENCRYPT, (BYTE*)ivec2);
  190. }
  191. // Now we've got a buffer of blockSize ready to be binhexed, and have the key
  192. // version prepended
  193. keyVersion = keyVersion % 36; // 0 - 9 & A - Z
  194. char v = (char) ((keyVersion > 9) ? (55+keyVersion) : (48+keyVersion));
  195. hr = m_binhex.ToBase64(pb, cbData + cbPadding + PASSPORT_MAC_LEN, v, ivec, ppEncrypted);
  196. if (S_OK != hr)
  197. {
  198. fResult = FALSE;
  199. goto Cleanup;
  200. }
  201. fResult = TRUE;
  202. Cleanup:
  203. if (NULL != pb)
  204. {
  205. delete[] pb;
  206. }
  207. return fResult;
  208. }
  209. void CCoCrypt::setKeyMaterial(BSTR newVal)
  210. {
  211. if (SysStringByteLen(newVal) != 24)
  212. {
  213. m_ok = FALSE;
  214. return;
  215. }
  216. memcpy(m_keyMaterial, (LPSTR)newVal, 24);
  217. tripledes3key(&ks, (BYTE*) m_keyMaterial);
  218. m_ok = TRUE;
  219. }
  220. unsigned char *CCoCrypt::getKeyMaterial(DWORD *pdwLen)
  221. {
  222. if (pdwLen)
  223. *pdwLen = 24;
  224. return m_keyMaterial;
  225. }
  226. int CCoCrypt::getKeyVersion(BSTR encrypted)
  227. {
  228. char c = (char) encrypted[0];
  229. if (isdigit(c))
  230. return (c-48);
  231. if(isalpha(c)) // Key version can be 0 - 9 & A - Z (36)
  232. {
  233. if(c > 'Z') //convert to uppert case w/o using rt lib.
  234. c -= ('a' - 'A');
  235. return c - 65 + 10;
  236. //return (toupper(c)-65+10);
  237. }
  238. return -1;
  239. }
  240. int CCoCrypt::getKeyVersion(BYTE *encrypted)
  241. {
  242. char c = (char) encrypted[0];
  243. if (isdigit(c))
  244. return (c-48);
  245. if(isalpha(c)) // Key version can be 0 - 9 & A - Z (36)
  246. {
  247. if(c > 'Z') //convert to uppert case w/o using rt lib.
  248. c -= ('a' - 'A');
  249. return c - 65 + 10;
  250. //return (toupper(c)-65+10);
  251. }
  252. return -1;
  253. }
  254. void CCoCrypt::setWideMaterial(BSTR kvalue)
  255. {
  256. m_bstrWideMaterial = kvalue;
  257. }
  258. BSTR CCoCrypt::getWideMaterial()
  259. {
  260. return m_bstrWideMaterial;
  261. }