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.

1036 lines
23 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // File: RC4CWRAP.C
  4. //
  5. // Contents: CryptoSystem wrapper functions for RC4
  6. //
  7. //
  8. // History: 25 Feb 92 RichardW Created
  9. //
  10. //------------------------------------------------------------------------
  11. #ifndef KERNEL_MODE
  12. #include <nt.h>
  13. #include <ntrtl.h>
  14. #include <nturtl.h>
  15. #include <windows.h>
  16. #else
  17. #include <ntifs.h>
  18. #endif
  19. #include <string.h>
  20. #include <malloc.h>
  21. #include <kerbcon.h>
  22. #include <security.h>
  23. #include <cryptdll.h>
  24. #include <rc4.h>
  25. #include <md4.h>
  26. #include <md5.h>
  27. //#define DONT_SUPPORT_OLD_ETYPES 1
  28. typedef struct RC4_KEYSTRUCT RC4KEY;
  29. #define RC4_LEGAL_KEYSIZE 8
  30. #define RC4_CONFOUNDER_LEN 8
  31. typedef struct _RC4_MDx_HEADER {
  32. UCHAR Confounder[RC4_CONFOUNDER_LEN];
  33. UCHAR Checksum[MD4_LEN];
  34. } RC4_MDx_HEADER, *PRC4_MDx_HEADER;
  35. typedef struct _RC4_STATE_BUFFER {
  36. PCHECKSUM_FUNCTION ChecksumFunction;
  37. PCHECKSUM_BUFFER ChecksumBuffer;
  38. RC4KEY Key;
  39. } RC4_STATE_BUFFER, *PRC4_STATE_BUFFER;
  40. typedef struct _RC4_HMAC_STATE_BUFFER {
  41. UCHAR Key[MD5_LEN];
  42. BOOLEAN IncludeHmac;
  43. } RC4_HMAC_STATE_BUFFER, *PRC4_HMAC_STATE_BUFFER;
  44. NTSTATUS NTAPI rc4Md4Initialize(PUCHAR, ULONG, ULONG, PCRYPT_STATE_BUFFER *);
  45. NTSTATUS NTAPI rc4LmInitialize(PUCHAR, ULONG, ULONG, PCRYPT_STATE_BUFFER *);
  46. #ifndef DONT_SUPPORT_OLD_ETYPES
  47. NTSTATUS NTAPI rc4Plain2Initialize(PUCHAR, ULONG, ULONG, PCRYPT_STATE_BUFFER *);
  48. NTSTATUS NTAPI rc4LmHashPassword(PSECURITY_STRING, PUCHAR);
  49. #endif
  50. NTSTATUS NTAPI rc4Encrypt(PCRYPT_STATE_BUFFER, PUCHAR, ULONG, PUCHAR, PULONG);
  51. NTSTATUS NTAPI rc4Decrypt(PCRYPT_STATE_BUFFER, PUCHAR, ULONG, PUCHAR, PULONG);
  52. NTSTATUS NTAPI rc4Finish(PCRYPT_STATE_BUFFER *);
  53. NTSTATUS NTAPI rc4Md4HashPassword(PSECURITY_STRING, PUCHAR);
  54. NTSTATUS NTAPI rc4Md4RandomKey(PUCHAR, ULONG, PUCHAR);
  55. NTSTATUS NTAPI rc4Control(ULONG, PCRYPT_STATE_BUFFER, PUCHAR, ULONG);
  56. NTSTATUS NTAPI rc4PlainInitializeOld(PUCHAR, ULONG, ULONG, PCRYPT_STATE_BUFFER *);
  57. NTSTATUS NTAPI rc4PlainExpInitializeOld(PUCHAR, ULONG, ULONG, PCRYPT_STATE_BUFFER *);
  58. NTSTATUS NTAPI rc4HmacInitializeOld(PUCHAR, ULONG, ULONG, PCRYPT_STATE_BUFFER *);
  59. NTSTATUS NTAPI rc4HmacExpInitializeOld(PUCHAR, ULONG, ULONG, PCRYPT_STATE_BUFFER *);
  60. NTSTATUS NTAPI rc4HmacEncryptOld(PCRYPT_STATE_BUFFER, PUCHAR, ULONG, PUCHAR, PULONG);
  61. NTSTATUS NTAPI rc4HmacDecryptOld(PCRYPT_STATE_BUFFER, PUCHAR, ULONG, PUCHAR, PULONG);
  62. NTSTATUS NTAPI rc4HmacFinishOld(PCRYPT_STATE_BUFFER *);
  63. NTSTATUS NTAPI rc4HmacControlOld(ULONG, PCRYPT_STATE_BUFFER, PUCHAR, ULONG);
  64. NTSTATUS NTAPI rc4HmacRandomKeyOld(PUCHAR, ULONG, PUCHAR);
  65. #ifdef KERNEL_MODE
  66. #pragma alloc_text( PAGEMSG, rc4Md4Initialize )
  67. #pragma alloc_text( PAGEMSG, rc4LmInitialize )
  68. #pragma alloc_text( PAGEMSG, rc4Encrypt )
  69. #pragma alloc_text( PAGEMSG, rc4Decrypt )
  70. #pragma alloc_text( PAGEMSG, rc4Finish )
  71. #pragma alloc_text( PAGEMSG, rc4Md4HashPassword )
  72. #pragma alloc_text( PAGEMSG, rc4Md4RandomKey )
  73. #pragma alloc_text( PAGEMSG, rc4Control )
  74. #pragma alloc_text( PAGEMSG, rc4PlainInitializeOld )
  75. #pragma alloc_text( PAGEMSG, rc4PlainExpInitializeOld )
  76. #pragma alloc_text( PAGEMSG, rc4HmacInitializeOld )
  77. #pragma alloc_text( PAGEMSG, rc4HmacExpInitializeOld )
  78. #pragma alloc_text( PAGEMSG, rc4HmacDecryptOld )
  79. #pragma alloc_text( PAGEMSG, rc4HmacEncryptOld )
  80. #pragma alloc_text( PAGEMSG, rc4HmacFinishOld )
  81. #pragma alloc_text( PAGEMSG, rc4HmacControlOld )
  82. #pragma alloc_text( PAGEMSG, rc4HmacRandomKeyOld )
  83. #endif
  84. CRYPTO_SYSTEM csRC4_MD4 = {
  85. KERB_ETYPE_RC4_MD4, // Etype
  86. 1, // Blocksize (stream)
  87. 0, // no exportable version
  88. MD4_LEN, // Key size, in bytes
  89. sizeof(RC4_MDx_HEADER), // header size
  90. KERB_CHECKSUM_MD4, // Preferred Checksum
  91. CSYSTEM_INTEGRITY_PROTECTED, // attributes
  92. L"RSADSI RC4-MD4", // Text name
  93. rc4Md4Initialize,
  94. rc4Encrypt,
  95. rc4Decrypt,
  96. rc4Finish,
  97. rc4Md4HashPassword,
  98. rc4Md4RandomKey,
  99. rc4Control
  100. };
  101. #ifndef DONT_SUPPORT_OLD_ETYPES
  102. CRYPTO_SYSTEM csRC4_LM = {
  103. KERB_ETYPE_RC4_LM, // Etype
  104. 1, // Blocksize (stream)
  105. 0, // no exportable version
  106. MD4_LEN, // State buffer size
  107. sizeof(RC4_MDx_HEADER), // header size
  108. KERB_CHECKSUM_LM, // Preferred Checksum
  109. CSYSTEM_INTEGRITY_PROTECTED, // attributes
  110. L"RSADSI RC4-LM", // Text name
  111. rc4LmInitialize,
  112. rc4Encrypt,
  113. rc4Decrypt,
  114. rc4Finish,
  115. rc4LmHashPassword,
  116. rc4Md4RandomKey,
  117. rc4Control
  118. };
  119. CRYPTO_SYSTEM csRC4_PLAIN2 = {
  120. KERB_ETYPE_RC4_PLAIN2, // Etype
  121. 1, // Blocksize (stream)
  122. 0, // no exportable version
  123. MD4_LEN, // Key size, in bytes
  124. 0, // header size
  125. KERB_CHECKSUM_MD4, // Preferred Checksum
  126. 0, // no attributes
  127. L"RSADSI RC4-PLAIN", // Text name
  128. rc4Plain2Initialize,
  129. rc4Encrypt,
  130. rc4Decrypt,
  131. rc4Finish,
  132. rc4Md4HashPassword,
  133. rc4Md4RandomKey,
  134. rc4Control
  135. };
  136. #endif
  137. CRYPTO_SYSTEM csRC4_HMAC_OLD = {
  138. KERB_ETYPE_RC4_HMAC_OLD, // Etype
  139. 1, // Blocksize (stream)
  140. KERB_ETYPE_RC4_HMAC_OLD_EXP,// Exportable version
  141. MD4_LEN, // Key size, in bytes
  142. sizeof(RC4_MDx_HEADER), // header size
  143. KERB_CHECKSUM_MD4, // Preferred Checksum
  144. CSYSTEM_INTEGRITY_PROTECTED, // attributes
  145. L"RSADSI RC4-HMAC", // Text name
  146. rc4HmacInitializeOld,
  147. rc4HmacEncryptOld,
  148. rc4HmacDecryptOld,
  149. rc4HmacFinishOld,
  150. rc4Md4HashPassword,
  151. rc4HmacRandomKeyOld,
  152. rc4HmacControlOld
  153. };
  154. CRYPTO_SYSTEM csRC4_HMAC_OLD_EXP = {
  155. KERB_ETYPE_RC4_HMAC_OLD_EXP, // Etype
  156. 1, // Blocksize (stream)
  157. KERB_ETYPE_RC4_HMAC_OLD_EXP, // Exportable version
  158. MD4_LEN, // Key size, in bytes
  159. sizeof(RC4_MDx_HEADER), // header size
  160. KERB_CHECKSUM_MD4, // Preferred Checksum
  161. CSYSTEM_INTEGRITY_PROTECTED | CSYSTEM_EXPORT_STRENGTH, // attributes
  162. L"RSADSI RC4-HMAC", // Text name
  163. rc4HmacInitializeOld,
  164. rc4HmacEncryptOld,
  165. rc4HmacDecryptOld,
  166. rc4HmacFinishOld,
  167. rc4Md4HashPassword,
  168. rc4HmacRandomKeyOld,
  169. rc4HmacControlOld
  170. };
  171. CRYPTO_SYSTEM csRC4_PLAIN_OLD = {
  172. KERB_ETYPE_RC4_PLAIN_OLD, // Etype
  173. 1, // Blocksize (stream)
  174. KERB_ETYPE_RC4_PLAIN_OLD_EXP, // exportable version
  175. MD4_LEN, // Key size, in bytes
  176. 0, // header size
  177. KERB_CHECKSUM_MD4, // Preferred Checksum
  178. 0, // no attributes
  179. L"RSADSI RC4", // Text name
  180. rc4PlainInitializeOld,
  181. rc4HmacEncryptOld,
  182. rc4HmacDecryptOld,
  183. rc4HmacFinishOld,
  184. rc4Md4HashPassword,
  185. rc4HmacRandomKeyOld,
  186. rc4HmacControlOld
  187. };
  188. CRYPTO_SYSTEM csRC4_PLAIN_OLD_EXP = {
  189. KERB_ETYPE_RC4_PLAIN_OLD_EXP, // Etype
  190. 1, // Blocksize (stream)
  191. KERB_ETYPE_RC4_PLAIN_OLD_EXP, // exportable version
  192. MD4_LEN, // Key size, in bytes
  193. 0, // header size
  194. KERB_CHECKSUM_MD4, // Preferred Checksum
  195. CSYSTEM_EXPORT_STRENGTH, // no attributes
  196. L"RSADSI RC4-EXP", // Text name
  197. rc4PlainExpInitializeOld,
  198. rc4HmacEncryptOld,
  199. rc4HmacDecryptOld,
  200. rc4HmacFinishOld,
  201. rc4Md4HashPassword,
  202. rc4HmacRandomKeyOld,
  203. rc4HmacControlOld
  204. };
  205. NTSTATUS NTAPI
  206. rc4Initialize( PUCHAR pbKey,
  207. ULONG KeySize,
  208. ULONG MessageType,
  209. ULONG ChecksumFunction,
  210. PCRYPT_STATE_BUFFER * psbBuffer)
  211. {
  212. NTSTATUS Status;
  213. PRC4_STATE_BUFFER pRC4Key;
  214. PCHECKSUM_FUNCTION Checksum = NULL;
  215. //
  216. // Get the appropriate checksum here.
  217. //
  218. if (ChecksumFunction != 0)
  219. {
  220. Status = CDLocateCheckSum(
  221. ChecksumFunction,
  222. &Checksum
  223. );
  224. if (!NT_SUCCESS(Status))
  225. {
  226. return(Status);
  227. }
  228. }
  229. //
  230. // if the key is too short, fail here.
  231. //
  232. if (KeySize < RC4_LEGAL_KEYSIZE)
  233. {
  234. return(SEC_E_ETYPE_NOT_SUPP);
  235. }
  236. #ifdef KERNEL_MODE
  237. pRC4Key = ExAllocatePool(NonPagedPool, sizeof(RC4_STATE_BUFFER));
  238. #else
  239. pRC4Key = LocalAlloc(0, sizeof(RC4_STATE_BUFFER));
  240. #endif
  241. if (pRC4Key == NULL)
  242. {
  243. return(STATUS_INSUFFICIENT_RESOURCES);
  244. }
  245. rc4_key(&pRC4Key->Key, RC4_LEGAL_KEYSIZE, pbKey);
  246. //
  247. // Initialize the checksum function, if we have one.
  248. //
  249. pRC4Key->ChecksumFunction = Checksum;
  250. if (Checksum != NULL)
  251. {
  252. Status = Checksum->Initialize(
  253. 0,
  254. &pRC4Key->ChecksumBuffer
  255. );
  256. if (!NT_SUCCESS(Status))
  257. {
  258. #ifdef KERNEL_MODE
  259. ExFreePool(pRC4Key);
  260. #else
  261. LocalFree(pRC4Key);
  262. #endif
  263. return(Status);
  264. }
  265. }
  266. *psbBuffer = (PCRYPT_STATE_BUFFER) pRC4Key;
  267. return(STATUS_SUCCESS);
  268. }
  269. NTSTATUS NTAPI
  270. rc4Md4Initialize(
  271. IN PUCHAR pbKey,
  272. IN ULONG KeySize,
  273. IN ULONG MessageType,
  274. OUT PCRYPT_STATE_BUFFER * psbBuffer
  275. )
  276. {
  277. return(rc4Initialize(
  278. pbKey,
  279. KeySize,
  280. MessageType,
  281. KERB_CHECKSUM_MD4,
  282. psbBuffer
  283. ));
  284. }
  285. NTSTATUS NTAPI
  286. rc4LmInitialize(
  287. IN PUCHAR pbKey,
  288. IN ULONG KeySize,
  289. IN ULONG MessageType,
  290. OUT PCRYPT_STATE_BUFFER * psbBuffer
  291. )
  292. {
  293. return(rc4Initialize(
  294. pbKey,
  295. KeySize,
  296. MessageType,
  297. KERB_CHECKSUM_LM,
  298. psbBuffer
  299. ));
  300. }
  301. #ifndef DONT_SUPPORT_OLD_ETYPES
  302. NTSTATUS NTAPI
  303. rc4Plain2Initialize(
  304. IN PUCHAR pbKey,
  305. IN ULONG KeySize,
  306. IN ULONG MessageType,
  307. OUT PCRYPT_STATE_BUFFER * psbBuffer
  308. )
  309. {
  310. return(rc4Initialize(
  311. pbKey,
  312. KeySize,
  313. MessageType,
  314. 0, // no checksum
  315. psbBuffer
  316. ));
  317. }
  318. #endif
  319. NTSTATUS NTAPI
  320. rc4Encrypt(
  321. IN PCRYPT_STATE_BUFFER psbBuffer,
  322. IN PUCHAR pbInput,
  323. IN ULONG cbInput,
  324. OUT PUCHAR pbOutput,
  325. OUT PULONG cbOutput
  326. )
  327. {
  328. PRC4_STATE_BUFFER StateBuffer = (PRC4_STATE_BUFFER) psbBuffer;
  329. PRC4_MDx_HEADER CryptHeader = (PRC4_MDx_HEADER) pbOutput;
  330. ULONG Offset = 0;
  331. if (StateBuffer->ChecksumFunction != NULL)
  332. {
  333. Offset = sizeof(RC4_MDx_HEADER);
  334. }
  335. RtlMoveMemory(
  336. pbOutput + Offset,
  337. pbInput,
  338. cbInput
  339. );
  340. *cbOutput = cbInput + Offset;
  341. RtlZeroMemory(
  342. CryptHeader,
  343. Offset
  344. );
  345. rc4(&StateBuffer->Key, *cbOutput, pbOutput);
  346. return( STATUS_SUCCESS );
  347. }
  348. NTSTATUS NTAPI
  349. rc4Decrypt( PCRYPT_STATE_BUFFER psbBuffer,
  350. PUCHAR pbInput,
  351. ULONG cbInput,
  352. PUCHAR pbOutput,
  353. PULONG cbOutput)
  354. {
  355. PRC4_STATE_BUFFER StateBuffer = (PRC4_STATE_BUFFER) psbBuffer;
  356. RC4_MDx_HEADER TempHeader;
  357. ULONG Offset = 0;
  358. if (*cbOutput < cbInput)
  359. {
  360. *cbOutput = cbInput;
  361. return(STATUS_BUFFER_TOO_SMALL);
  362. }
  363. RtlCopyMemory(
  364. pbOutput,
  365. pbInput,
  366. cbInput
  367. );
  368. rc4(&StateBuffer->Key, cbInput, pbOutput);
  369. if (StateBuffer->ChecksumFunction != NULL)
  370. {
  371. Offset = sizeof(RC4_MDx_HEADER);
  372. }
  373. RtlZeroMemory(
  374. &TempHeader,
  375. Offset
  376. );
  377. if (RtlEqualMemory(
  378. &TempHeader,
  379. pbOutput,
  380. Offset
  381. ) != TRUE)
  382. {
  383. return(STATUS_UNSUCCESSFUL);
  384. }
  385. *cbOutput = cbInput - Offset;
  386. RtlMoveMemory(
  387. pbOutput,
  388. pbOutput + Offset,
  389. *cbOutput
  390. );
  391. return( STATUS_SUCCESS );
  392. }
  393. NTSTATUS NTAPI
  394. rc4Finish( PCRYPT_STATE_BUFFER * psbBuffer)
  395. {
  396. PRC4_STATE_BUFFER StateBuffer = (PRC4_STATE_BUFFER) *psbBuffer;
  397. if (StateBuffer->ChecksumFunction != NULL)
  398. {
  399. StateBuffer->ChecksumFunction->Finish(&StateBuffer->ChecksumBuffer);
  400. }
  401. #ifdef KERNEL_MODE
  402. ExFreePool(*psbBuffer);
  403. #else
  404. LocalFree(*psbBuffer);
  405. #endif
  406. *psbBuffer = NULL;
  407. return(STATUS_SUCCESS);
  408. }
  409. NTSTATUS NTAPI
  410. rc4HashPassword(
  411. IN PSECURITY_STRING Password,
  412. IN ULONG Checksum,
  413. OUT PUCHAR Key
  414. )
  415. {
  416. PCHECKSUM_FUNCTION SumFunction;
  417. PCHECKSUM_BUFFER Buffer;
  418. NTSTATUS Status;
  419. Status = CDLocateCheckSum(Checksum, &SumFunction);
  420. if (!NT_SUCCESS(Status))
  421. {
  422. return(SEC_E_CHECKSUM_NOT_SUPP);
  423. }
  424. Status = SumFunction->Initialize(0, &Buffer);
  425. if (!NT_SUCCESS(Status))
  426. {
  427. return(Status);
  428. }
  429. (void) SumFunction->Sum(Buffer, Password->Length, (PUCHAR) Password->Buffer);
  430. (void) SumFunction->Finalize(Buffer, Key);
  431. (void) SumFunction->Finish(&Buffer);
  432. return(STATUS_SUCCESS);
  433. }
  434. NTSTATUS NTAPI
  435. rc4Md4HashPassword(
  436. PSECURITY_STRING pbPassword,
  437. PUCHAR pbKey)
  438. {
  439. return(rc4HashPassword( pbPassword, KERB_CHECKSUM_MD4, pbKey));
  440. }
  441. NTSTATUS NTAPI
  442. rc4LmHashPassword(
  443. PSECURITY_STRING pbPassword,
  444. PUCHAR pbKey)
  445. {
  446. return(rc4HashPassword( pbPassword, KERB_CHECKSUM_LM, pbKey));
  447. }
  448. NTSTATUS NTAPI
  449. rc4RandomKey(
  450. IN ULONG KeyLength,
  451. OUT PUCHAR pbKey
  452. )
  453. {
  454. CDGenerateRandomBits(pbKey,KeyLength);
  455. return(STATUS_SUCCESS);
  456. }
  457. NTSTATUS NTAPI
  458. rc4Md4RandomKey(
  459. IN OPTIONAL PUCHAR Seed,
  460. IN ULONG SeedLength,
  461. OUT PUCHAR pbKey
  462. )
  463. {
  464. memset(
  465. pbKey,
  466. 0xab,
  467. MD4_LEN
  468. );
  469. return(rc4RandomKey(5,pbKey));
  470. }
  471. NTSTATUS NTAPI
  472. rc4Control(
  473. IN ULONG Function,
  474. IN PCRYPT_STATE_BUFFER StateBuffer,
  475. IN PUCHAR InputBuffer,
  476. IN ULONG InputBufferSize
  477. )
  478. {
  479. UCHAR TempBuffer[128];
  480. PRC4_STATE_BUFFER Rc4StateBuffer = (PRC4_STATE_BUFFER) StateBuffer;
  481. if (Function != CRYPT_CONTROL_SET_INIT_VECT)
  482. {
  483. return(STATUS_INVALID_PARAMETER);
  484. }
  485. if (InputBufferSize > sizeof(TempBuffer))
  486. {
  487. return(STATUS_INVALID_PARAMETER);
  488. }
  489. //
  490. // We set the IV by encrypting the supplied buffer and leaving the
  491. // keystate changed.
  492. //
  493. memcpy(
  494. TempBuffer,
  495. InputBuffer,
  496. InputBufferSize
  497. );
  498. rc4(&Rc4StateBuffer->Key, InputBufferSize, TempBuffer );
  499. return(STATUS_SUCCESS);
  500. }
  501. //////////////////////////////////////////////////////////////////////////
  502. //
  503. // RC4 HMAC crypt type
  504. //
  505. //////////////////////////////////////////////////////////////////////////
  506. BOOLEAN
  507. md5Hmac(
  508. IN PUCHAR pbKeyMaterial,
  509. IN ULONG cbKeyMaterial,
  510. IN PUCHAR pbData,
  511. IN ULONG cbData,
  512. IN PUCHAR pbData2,
  513. IN ULONG cbData2,
  514. OUT PUCHAR HmacData
  515. )
  516. {
  517. BOOLEAN fRet = FALSE;
  518. #define HMAC_K_PADSIZE 64
  519. UCHAR Kipad[HMAC_K_PADSIZE];
  520. UCHAR Kopad[HMAC_K_PADSIZE];
  521. UCHAR HMACTmp[HMAC_K_PADSIZE+MD5_LEN];
  522. ULONG dwBlock;
  523. MD5_CTX Md5Hash;
  524. // truncate
  525. if (cbKeyMaterial > HMAC_K_PADSIZE)
  526. cbKeyMaterial = HMAC_K_PADSIZE;
  527. RtlZeroMemory(Kipad, HMAC_K_PADSIZE);
  528. RtlCopyMemory(Kipad, pbKeyMaterial, cbKeyMaterial);
  529. RtlZeroMemory(Kopad, HMAC_K_PADSIZE);
  530. RtlCopyMemory(Kopad, pbKeyMaterial, cbKeyMaterial);
  531. //
  532. // Kipad, Kopad are padded sMacKey. Now XOR across...
  533. //
  534. for(dwBlock=0; dwBlock<HMAC_K_PADSIZE/sizeof(ULONG); dwBlock++)
  535. {
  536. ((ULONG*)Kipad)[dwBlock] ^= 0x36363636;
  537. ((ULONG*)Kopad)[dwBlock] ^= 0x5C5C5C5C;
  538. }
  539. //
  540. // prepend Kipad to data, Hash to get H1
  541. //
  542. MD5Init(&Md5Hash);
  543. MD5Update(&Md5Hash, Kipad, HMAC_K_PADSIZE);
  544. if (cbData != 0)
  545. {
  546. MD5Update(&Md5Hash, pbData, cbData);
  547. }
  548. if (cbData2 != 0)
  549. {
  550. MD5Update(&Md5Hash, pbData2, cbData2);
  551. }
  552. // Finish off the hash
  553. MD5Final(&Md5Hash);
  554. // prepend Kopad to H1, hash to get HMAC
  555. RtlCopyMemory(HMACTmp, Kopad, HMAC_K_PADSIZE);
  556. RtlCopyMemory(HMACTmp+HMAC_K_PADSIZE, Md5Hash.digest, MD5_LEN);
  557. // final hash: output value into passed-in buffer
  558. MD5Init(&Md5Hash);
  559. MD5Update(&Md5Hash,HMACTmp, sizeof(HMACTmp));
  560. MD5Final(&Md5Hash);
  561. RtlCopyMemory(
  562. HmacData,
  563. Md5Hash.digest,
  564. MD5_LEN
  565. );
  566. return TRUE;
  567. }
  568. NTSTATUS NTAPI
  569. rc4HmacBaseInitializeOld(
  570. IN PUCHAR pbKey,
  571. IN ULONG KeySize,
  572. IN ULONG MessageType,
  573. IN BOOLEAN IncludeHmac,
  574. IN BOOLEAN Exportable,
  575. OUT PCRYPT_STATE_BUFFER * psbBuffer
  576. )
  577. {
  578. PRC4_HMAC_STATE_BUFFER StateBuffer = NULL;
  579. LPSTR Direction = NULL;
  580. ULONG DirectionSize = 0;
  581. LPSTR Usage = NULL;
  582. ULONG UsageSize = 0;
  583. ULONG LocalKeySize = 0;
  584. //
  585. // Compute the HMAC pad
  586. //
  587. #ifdef KERNEL_MODE
  588. StateBuffer = ExAllocatePool(NonPagedPool, sizeof(RC4_HMAC_STATE_BUFFER));
  589. #else
  590. StateBuffer = LocalAlloc(0, sizeof(RC4_HMAC_STATE_BUFFER));
  591. #endif
  592. if (StateBuffer == NULL)
  593. {
  594. return(STATUS_INSUFFICIENT_RESOURCES);
  595. }
  596. //
  597. // If the key is not exportable, shrink it first
  598. //
  599. if (!Exportable)
  600. {
  601. md5Hmac(
  602. pbKey,
  603. KeySize,
  604. (PUCHAR) &MessageType,
  605. sizeof(ULONG),
  606. NULL,
  607. 0,
  608. StateBuffer->Key
  609. );
  610. LocalKeySize = MD5_LEN;
  611. }
  612. else
  613. {
  614. md5Hmac(
  615. pbKey,
  616. KeySize,
  617. "fortybits",
  618. sizeof("fortybits"),
  619. (PUCHAR) &MessageType,
  620. sizeof(ULONG),
  621. StateBuffer->Key
  622. );
  623. LocalKeySize = 5; // 40 bits
  624. }
  625. //
  626. // Pad exportable keys with 0xababab
  627. //
  628. memset(
  629. StateBuffer->Key+LocalKeySize,
  630. 0xab,
  631. MD5_LEN-LocalKeySize
  632. );
  633. StateBuffer->IncludeHmac = IncludeHmac;
  634. *psbBuffer = StateBuffer;
  635. return(STATUS_SUCCESS);
  636. }
  637. NTSTATUS NTAPI
  638. rc4HmacInitializeOld(
  639. IN PUCHAR pbKey,
  640. IN ULONG KeySize,
  641. IN ULONG MessageType,
  642. OUT PCRYPT_STATE_BUFFER * psbBuffer
  643. )
  644. {
  645. return(rc4HmacBaseInitializeOld(
  646. pbKey,
  647. KeySize,
  648. MessageType,
  649. TRUE, // include hmac
  650. FALSE, // not exportable
  651. psbBuffer
  652. ));
  653. }
  654. NTSTATUS NTAPI
  655. rc4PlainInitializeOld(
  656. IN PUCHAR pbKey,
  657. IN ULONG KeySize,
  658. IN ULONG MessageType,
  659. OUT PCRYPT_STATE_BUFFER * psbBuffer
  660. )
  661. {
  662. return(rc4HmacBaseInitializeOld(
  663. pbKey,
  664. KeySize,
  665. MessageType,
  666. FALSE, // no hmac
  667. FALSE, // not exportable
  668. psbBuffer
  669. ));
  670. }
  671. NTSTATUS NTAPI
  672. rc4PlainExpInitializeOld(
  673. IN PUCHAR pbKey,
  674. IN ULONG KeySize,
  675. IN ULONG MessageType,
  676. OUT PCRYPT_STATE_BUFFER * psbBuffer
  677. )
  678. {
  679. return(rc4HmacBaseInitializeOld(
  680. pbKey,
  681. KeySize, // only use 40 bites
  682. MessageType,
  683. FALSE, // no hmac
  684. TRUE, // exportable
  685. psbBuffer
  686. ));
  687. }
  688. NTSTATUS NTAPI
  689. rc4HmacControlOld(
  690. IN ULONG Function,
  691. IN PCRYPT_STATE_BUFFER StateBuffer,
  692. IN PUCHAR InputBuffer,
  693. IN ULONG InputBufferSize
  694. )
  695. {
  696. PRC4_HMAC_STATE_BUFFER HmacStateBuffer = (PRC4_HMAC_STATE_BUFFER) StateBuffer;
  697. if (Function == CRYPT_CONTROL_SET_INIT_VECT)
  698. {
  699. md5Hmac(
  700. HmacStateBuffer->Key,
  701. MD5_LEN,
  702. InputBuffer,
  703. InputBufferSize,
  704. NULL,
  705. 0,
  706. HmacStateBuffer->Key
  707. );
  708. }
  709. else
  710. {
  711. return(STATUS_INVALID_PARAMETER);
  712. }
  713. return(STATUS_SUCCESS);
  714. }
  715. NTSTATUS NTAPI
  716. rc4HmacEncryptOld(
  717. IN PCRYPT_STATE_BUFFER psbBuffer,
  718. IN PUCHAR pbInput,
  719. IN ULONG cbInput,
  720. OUT PUCHAR pbOutput,
  721. OUT PULONG cbOutput
  722. )
  723. {
  724. PRC4_HMAC_STATE_BUFFER StateBuffer = (PRC4_HMAC_STATE_BUFFER) psbBuffer;
  725. PRC4_MDx_HEADER CryptHeader = (PRC4_MDx_HEADER) pbOutput;
  726. ULONG Offset = 0;
  727. RC4KEY Rc4Key;
  728. if (StateBuffer->IncludeHmac)
  729. {
  730. Offset = sizeof(RC4_MDx_HEADER);
  731. }
  732. else
  733. {
  734. Offset = 0;
  735. }
  736. RtlMoveMemory(
  737. pbOutput + Offset,
  738. pbInput,
  739. cbInput
  740. );
  741. *cbOutput = cbInput + Offset;
  742. //
  743. // Create the header - the confounder & checksum
  744. //
  745. if (Offset != 0)
  746. {
  747. RtlZeroMemory(
  748. CryptHeader->Checksum,
  749. MD4_LEN
  750. );
  751. CDGenerateRandomBits(
  752. CryptHeader->Confounder,
  753. RC4_CONFOUNDER_LEN
  754. );
  755. md5Hmac(
  756. StateBuffer->Key,
  757. MD5_LEN,
  758. pbOutput,
  759. *cbOutput,
  760. NULL,
  761. 0,
  762. CryptHeader->Checksum
  763. );
  764. }
  765. rc4_key(
  766. &Rc4Key,
  767. MD5_LEN,
  768. StateBuffer->Key
  769. );
  770. rc4(&Rc4Key, *cbOutput, pbOutput);
  771. return(STATUS_SUCCESS);
  772. }
  773. NTSTATUS NTAPI
  774. rc4HmacDecryptOld( PCRYPT_STATE_BUFFER psbBuffer,
  775. PUCHAR pbInput,
  776. ULONG cbInput,
  777. PUCHAR pbOutput,
  778. PULONG cbOutput)
  779. {
  780. PRC4_HMAC_STATE_BUFFER StateBuffer = (PRC4_HMAC_STATE_BUFFER) psbBuffer;
  781. RC4_MDx_HEADER TempHeader;
  782. UCHAR TempChecksum[MD5_LEN];
  783. ULONG Offset = sizeof(RC4_MDx_HEADER);
  784. RC4KEY Rc4Key;
  785. if (!StateBuffer->IncludeHmac)
  786. {
  787. Offset = 0;
  788. }
  789. if (cbInput < Offset)
  790. {
  791. return(STATUS_INVALID_PARAMETER);
  792. }
  793. rc4_key(
  794. &Rc4Key,
  795. MD5_LEN,
  796. StateBuffer->Key
  797. );
  798. //
  799. // Copy the input to the output before decrypting
  800. //
  801. RtlCopyMemory(
  802. &TempHeader,
  803. pbInput,
  804. Offset
  805. );
  806. *cbOutput = cbInput - Offset;
  807. RtlMoveMemory(
  808. pbOutput,
  809. pbInput + Offset,
  810. *cbOutput
  811. );
  812. //
  813. // Now decrypt the two buffers
  814. //
  815. if (Offset != 0)
  816. {
  817. rc4(
  818. &Rc4Key,
  819. Offset,
  820. (PUCHAR) &TempHeader
  821. );
  822. }
  823. rc4(
  824. &Rc4Key,
  825. *cbOutput,
  826. pbOutput
  827. );
  828. //
  829. // Now verify the checksum. First copy it out of the way, zero the
  830. // header
  831. //
  832. if (Offset != 0)
  833. {
  834. RtlCopyMemory(
  835. TempChecksum,
  836. TempHeader.Checksum,
  837. MD5_LEN
  838. );
  839. RtlZeroMemory(
  840. TempHeader.Checksum,
  841. MD5_LEN
  842. );
  843. md5Hmac(
  844. StateBuffer->Key,
  845. MD5_LEN,
  846. (PUCHAR) &TempHeader,
  847. Offset,
  848. pbOutput,
  849. *cbOutput,
  850. TempHeader.Checksum
  851. );
  852. if (RtlEqualMemory(
  853. TempHeader.Checksum,
  854. TempChecksum,
  855. MD5_LEN
  856. ) != TRUE)
  857. {
  858. return(STATUS_UNSUCCESSFUL);
  859. }
  860. }
  861. return(STATUS_SUCCESS);
  862. }
  863. NTSTATUS NTAPI
  864. rc4HmacFinishOld( PCRYPT_STATE_BUFFER * psbBuffer)
  865. {
  866. #ifdef KERNEL_MODE
  867. ExFreePool(*psbBuffer);
  868. #else
  869. LocalFree(*psbBuffer);
  870. #endif
  871. *psbBuffer = NULL;
  872. return(STATUS_SUCCESS);
  873. }
  874. NTSTATUS NTAPI
  875. rc4HmacRandomKeyOld(
  876. IN OPTIONAL PUCHAR Seed,
  877. IN ULONG SeedLength,
  878. OUT PUCHAR pbKey
  879. )
  880. {
  881. return(rc4RandomKey(MD5_LEN,pbKey));
  882. }