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.

763 lines
18 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. data.c
  5. Abstract:
  6. Arbitrary length data encryption functions implementation :
  7. RtlEncryptData
  8. RtlDecryptData
  9. Author:
  10. David Chalmers (Davidc) 12-16-91
  11. Revision History:
  12. --*/
  13. #include <nt.h>
  14. #include <ntrtl.h>
  15. #include <crypt.h>
  16. #include <engine.h>
  17. //
  18. // Version number of encrypted data
  19. // Update this number if the method used encrypt the data changes
  20. //
  21. #define DATA_ENCRYPTION_VERSION 1
  22. //
  23. // Private data types
  24. //
  25. typedef struct _CRYPTP_BUFFER {
  26. ULONG Length; // Number of valid bytes in buffer
  27. ULONG MaximumLength; // Number of bytes pointed to by buffer
  28. PCHAR Buffer;
  29. PCHAR Pointer; // Points into buffer
  30. } CRYPTP_BUFFER;
  31. typedef CRYPTP_BUFFER *PCRYPTP_BUFFER;
  32. //
  33. // Internal helper macros
  34. #define AdvanceCypherData(p) ((PCYPHER_BLOCK)(((PCRYPTP_BUFFER)p)->Pointer)) ++
  35. #define AdvanceClearData(p) ((PCLEAR_BLOCK)(((PCRYPTP_BUFFER)p)->Pointer)) ++
  36. //
  37. // Private routines
  38. //
  39. VOID
  40. InitializeBuffer(
  41. OUT PCRYPTP_BUFFER PrivateBuffer,
  42. IN PCRYPT_BUFFER PublicBuffer
  43. )
  44. /*++
  45. Routine Description:
  46. Internal helper routine
  47. Copies fields from public buffer into private buffer.
  48. Sets the Pointer field of the private buffer to the
  49. base of the buffer.
  50. Arguments:
  51. PrivateBuffer - out internal buffer we want to represent the public structure.
  52. PublicBuffer - the buffer the caller passed us
  53. Return Values:
  54. None
  55. --*/
  56. {
  57. PrivateBuffer->Length = PublicBuffer->Length;
  58. PrivateBuffer->MaximumLength = PublicBuffer->MaximumLength;
  59. PrivateBuffer->Buffer = PublicBuffer->Buffer;
  60. PrivateBuffer->Pointer = PublicBuffer->Buffer;
  61. }
  62. BOOLEAN
  63. ValidateDataKey(
  64. IN PCRYPTP_BUFFER DataKey,
  65. IN PBLOCK_KEY BlockKey
  66. )
  67. /*++
  68. Routine Description:
  69. Internal helper routine
  70. Checks the validity of the data key and constructs a minimum length
  71. key in the passed blockkey if the datakey is not long enough.
  72. Arguments:
  73. DataKey - The data key
  74. Return Values:
  75. TRUE if the key is valid, otherwise FALSE
  76. --*/
  77. {
  78. if ( ( DataKey->Length == 0 ) ||
  79. ( DataKey->Buffer == NULL ) ) {
  80. return(FALSE);
  81. }
  82. if (DataKey->Length < BLOCK_KEY_LENGTH) {
  83. // Make up a minimum length key from the small data key we were
  84. // given. Store it in the passed blockkey variable and point
  85. // the datakey buffer at this temporary storage.
  86. ULONG DataIndex, BlockIndex;
  87. DataIndex = 0;
  88. for (BlockIndex = 0; BlockIndex < BLOCK_KEY_LENGTH; BlockIndex ++) {
  89. ((PCHAR)BlockKey)[BlockIndex] = DataKey->Buffer[DataIndex];
  90. DataIndex ++;
  91. if (DataIndex >= DataKey->Length) {
  92. DataIndex = 0;
  93. }
  94. }
  95. // Point the buffer at our constructed block key
  96. DataKey->Buffer = (PCHAR)BlockKey;
  97. DataKey->Pointer = (PCHAR)BlockKey;
  98. DataKey->Length = BLOCK_KEY_LENGTH;
  99. DataKey->MaximumLength = BLOCK_KEY_LENGTH;
  100. }
  101. return(TRUE);
  102. }
  103. VOID
  104. AdvanceDataKey(
  105. IN PCRYPTP_BUFFER DataKey
  106. )
  107. /*++
  108. Routine Description:
  109. Internal helper routine
  110. Moves the data key pointer on to point at the key to use to encrypt
  111. the next data block. Wraps round at end of key data.
  112. Arguments:
  113. DataKey - The data key
  114. Return Values:
  115. STATUS_SUCCESS - No problems
  116. --*/
  117. {
  118. if (DataKey->Length > BLOCK_KEY_LENGTH) {
  119. PCHAR EndPointer;
  120. // Advance pointer and wrap
  121. DataKey->Pointer += BLOCK_KEY_LENGTH;
  122. EndPointer = DataKey->Pointer + BLOCK_KEY_LENGTH;
  123. if (EndPointer > &(DataKey->Buffer[DataKey->Length])) {
  124. ULONG_PTR Overrun;
  125. Overrun = EndPointer - &(DataKey->Buffer[DataKey->Length]);
  126. DataKey->Pointer = DataKey->Buffer + (BLOCK_KEY_LENGTH - Overrun);
  127. }
  128. }
  129. }
  130. ULONG
  131. CalculateCypherDataLength(
  132. IN PCRYPTP_BUFFER ClearData
  133. )
  134. /*++
  135. Routine Description:
  136. Internal helper routine
  137. Returns the number of bytes required to encrypt the specified number
  138. of clear data bytes.
  139. Arguments:
  140. ClearData - The clear data
  141. Return Values:
  142. Number of cypher bytes required.
  143. --*/
  144. {
  145. ULONG CypherDataLength;
  146. ULONG BlockExcess;
  147. // We always store the length of the clear data as a whole block.
  148. CypherDataLength = CYPHER_BLOCK_LENGTH + ClearData->Length;
  149. // Round up to the next block
  150. BlockExcess = CypherDataLength % CYPHER_BLOCK_LENGTH;
  151. if (BlockExcess > 0) {
  152. CypherDataLength += CYPHER_BLOCK_LENGTH - BlockExcess;
  153. }
  154. return(CypherDataLength);
  155. }
  156. NTSTATUS
  157. EncryptDataLength(
  158. IN PCRYPTP_BUFFER Data,
  159. IN PCRYPTP_BUFFER DataKey,
  160. OUT PCRYPTP_BUFFER CypherData
  161. )
  162. /*++
  163. Routine Description:
  164. Internal helper routine
  165. Encrypts the clear data length and puts the encrypted value in the
  166. cypherdatabuffer. Advances the cypherdata buffer and datakey buffer pointers
  167. Arguments:
  168. Data - The buffer whose length is to be encrypted
  169. DataKey - key to use to encrypt data
  170. CypherData - Place to store encrypted data
  171. Return Values:
  172. STATUS_SUCCESS - Success.
  173. STATUS_UNSUCCESSFUL - Something failed.
  174. --*/
  175. {
  176. NTSTATUS Status;
  177. CLEAR_BLOCK ClearBlock;
  178. // Fill the clear block with the data value and a version number
  179. ((ULONG *)&ClearBlock)[0] = Data->Length;
  180. ((ULONG *)&ClearBlock)[1] = DATA_ENCRYPTION_VERSION;
  181. Status = RtlEncryptBlock(&ClearBlock,
  182. (PBLOCK_KEY)(DataKey->Pointer),
  183. (PCYPHER_BLOCK)(CypherData->Pointer));
  184. // Advance pointers
  185. AdvanceCypherData(CypherData);
  186. AdvanceDataKey(DataKey);
  187. return(Status);
  188. }
  189. NTSTATUS
  190. EncryptFullBlock(
  191. IN OUT PCRYPTP_BUFFER ClearData,
  192. IN OUT PCRYPTP_BUFFER DataKey,
  193. IN OUT PCRYPTP_BUFFER CypherData
  194. )
  195. /*++
  196. Routine Description:
  197. Internal helper routine
  198. Encrypts a full block of data from ClearData and puts the encrypted
  199. data in CypherData.
  200. Both cleardata, datakey and cypherdata pointers are advanced.
  201. Arguments:
  202. ClearData - Pointer to the cleardata buffer
  203. DataKey - key to use to encrypt data
  204. CypherData - Pointer to cypherdata buffer.
  205. Return Values:
  206. STATUS_SUCCESS - Success.
  207. STATUS_UNSUCCESSFUL - Something failed.
  208. --*/
  209. {
  210. NTSTATUS Status;
  211. Status = RtlEncryptBlock((PCLEAR_BLOCK)(ClearData->Pointer),
  212. (PBLOCK_KEY)(DataKey->Pointer),
  213. (PCYPHER_BLOCK)(CypherData->Pointer));
  214. // Advance pointers
  215. AdvanceClearData(ClearData);
  216. AdvanceCypherData(CypherData);
  217. AdvanceDataKey(DataKey);
  218. return(Status);
  219. }
  220. NTSTATUS
  221. EncryptPartialBlock(
  222. IN OUT PCRYPTP_BUFFER ClearData,
  223. IN OUT PCRYPTP_BUFFER DataKey,
  224. IN OUT PCRYPTP_BUFFER CypherData,
  225. IN ULONG Remaining
  226. )
  227. /*++
  228. Routine Description:
  229. Internal helper routine
  230. Encrypts a partial block of data from ClearData and puts the full
  231. encrypted data block in cypherdata.
  232. Both cleardata, datakey and cypherdata pointers are advanced.
  233. Arguments:
  234. ClearData - Pointer to the cleardata buffer
  235. DataKey - key to use to encrypt data
  236. CypherData - Pointer to cypherdata buffer.
  237. Remaining - the number of bytes remaining in cleardata buffer
  238. Return Values:
  239. STATUS_SUCCESS - Success.
  240. STATUS_UNSUCCESSFUL - Something failed.
  241. --*/
  242. {
  243. NTSTATUS Status;
  244. CLEAR_BLOCK ClearBlockBuffer;
  245. PCLEAR_BLOCK ClearBlock = &ClearBlockBuffer;
  246. ASSERTMSG("EncryptPartialBlock called with a block or more", Remaining < CLEAR_BLOCK_LENGTH);
  247. // Copy the remaining bytes into a clear block buffer
  248. while (Remaining > 0) {
  249. *((PCHAR)ClearBlock) ++ = *(ClearData->Pointer) ++;
  250. Remaining --;
  251. }
  252. // Zero pad
  253. while (ClearBlock < &((&ClearBlockBuffer)[1])) {
  254. *((PCHAR)ClearBlock) ++ = 0;
  255. }
  256. Status = RtlEncryptBlock(&ClearBlockBuffer,
  257. (PBLOCK_KEY)(DataKey->Pointer),
  258. (PCYPHER_BLOCK)(CypherData->Pointer));
  259. // Advance pointers
  260. AdvanceClearData(ClearData);
  261. AdvanceCypherData(CypherData);
  262. AdvanceDataKey(DataKey);
  263. return(Status);
  264. }
  265. NTSTATUS
  266. DecryptDataLength(
  267. IN PCRYPTP_BUFFER CypherData,
  268. IN PCRYPTP_BUFFER DataKey,
  269. OUT PCRYPTP_BUFFER Data
  270. )
  271. /*++
  272. Routine Description:
  273. Internal helper routine
  274. Decrypts the data length pointed to by the cypherdata buffer and puts the
  275. decrypted value in the length field of the data structure.
  276. Advances the cypherdata buffer and datakey buffer pointers
  277. Arguments:
  278. CypherData - The buffer containing the encrypted length
  279. DataKey - key to use to decrypt data
  280. Data - Decrypted length field is stored in the length field of this struct.
  281. Return Values:
  282. STATUS_SUCCESS - Success.
  283. STATUS_UNSUCCESSFUL - Something failed.
  284. --*/
  285. {
  286. NTSTATUS Status;
  287. CLEAR_BLOCK ClearBlock;
  288. ULONG Version;
  289. Status = RtlDecryptBlock((PCYPHER_BLOCK)(CypherData->Pointer),
  290. (PBLOCK_KEY)(DataKey->Pointer),
  291. &ClearBlock);
  292. if (!NT_SUCCESS(Status)) {
  293. return(Status);
  294. }
  295. // Advance pointers
  296. AdvanceCypherData(CypherData);
  297. AdvanceDataKey(DataKey);
  298. // Copy the decrypted length into the data structure.
  299. Data->Length = ((ULONG *)&ClearBlock)[0];
  300. // Check the version
  301. Version = ((ULONG *)&ClearBlock)[1];
  302. if (Version != DATA_ENCRYPTION_VERSION) {
  303. return(STATUS_UNKNOWN_REVISION);
  304. }
  305. return(STATUS_SUCCESS);
  306. }
  307. NTSTATUS
  308. DecryptFullBlock(
  309. IN OUT PCRYPTP_BUFFER CypherData,
  310. IN OUT PCRYPTP_BUFFER DataKey,
  311. IN OUT PCRYPTP_BUFFER ClearData
  312. )
  313. /*++
  314. Routine Description:
  315. Internal helper routine
  316. Decrypts a full block of data from CypherData and puts the encrypted
  317. data in ClearData.
  318. Both cleardata, datakey and cypherdata pointers are advanced.
  319. Arguments:
  320. CypherData - Pointer to cypherdata buffer.
  321. ClearData - Pointer to the cleardata buffer
  322. DataKey - key to use to encrypt data
  323. Return Values:
  324. STATUS_SUCCESS - Success.
  325. STATUS_UNSUCCESSFUL - Something failed.
  326. --*/
  327. {
  328. NTSTATUS Status;
  329. Status = RtlDecryptBlock((PCYPHER_BLOCK)(CypherData->Pointer),
  330. (PBLOCK_KEY)(DataKey->Pointer),
  331. (PCLEAR_BLOCK)(ClearData->Pointer));
  332. // Advance pointers
  333. AdvanceClearData(ClearData);
  334. AdvanceCypherData(CypherData);
  335. AdvanceDataKey(DataKey);
  336. return(Status);
  337. }
  338. NTSTATUS
  339. DecryptPartialBlock(
  340. IN OUT PCRYPTP_BUFFER CypherData,
  341. IN OUT PCRYPTP_BUFFER DataKey,
  342. IN OUT PCRYPTP_BUFFER ClearData,
  343. IN ULONG Remaining
  344. )
  345. /*++
  346. Routine Description:
  347. Internal helper routine
  348. Decrypts a full block of data from CypherData and puts the partial
  349. decrypted data block in cleardata.
  350. Both cleardata, datakey and cypherdata pointers are advanced.
  351. Arguments:
  352. CypherData - Pointer to cypherdata buffer.
  353. ClearData - Pointer to the cleardata buffer
  354. DataKey - key to use to encrypt data
  355. Remaining - the number of bytes remaining in cleardata buffer
  356. Return Values:
  357. STATUS_SUCCESS - Success.
  358. STATUS_UNSUCCESSFUL - Something failed.
  359. --*/
  360. {
  361. NTSTATUS Status;
  362. CLEAR_BLOCK ClearBlockBuffer;
  363. PCLEAR_BLOCK ClearBlock = &ClearBlockBuffer;
  364. ASSERTMSG("DecryptPartialBlock called with a block or more", Remaining < CLEAR_BLOCK_LENGTH);
  365. // Decrypt the block into a local clear block
  366. Status = RtlDecryptBlock((PCYPHER_BLOCK)(CypherData->Pointer),
  367. (PBLOCK_KEY)(DataKey->Pointer),
  368. &ClearBlockBuffer);
  369. if (!NT_SUCCESS(Status)) {
  370. return(Status);
  371. }
  372. // Copy the decrypted bytes into the cleardata buffer.
  373. while (Remaining > 0) {
  374. *(ClearData->Pointer) ++ = *((PCHAR)ClearBlock) ++;
  375. Remaining --;
  376. }
  377. // Advance pointers
  378. AdvanceClearData(ClearData);
  379. AdvanceCypherData(CypherData);
  380. AdvanceDataKey(DataKey);
  381. return(Status);
  382. }
  383. //
  384. // Public functions
  385. //
  386. NTSTATUS
  387. RtlEncryptData(
  388. IN PCLEAR_DATA ClearData,
  389. IN PDATA_KEY DataKey,
  390. OUT PCYPHER_DATA CypherData
  391. )
  392. /*++
  393. Routine Description:
  394. Takes an arbitrary length block of data and encrypts it with a
  395. data key producing an encrypted block of data.
  396. Arguments:
  397. ClearData - The data to be encrypted.
  398. DataKey - The key to use to encrypt the data
  399. CypherData - Encrypted data is returned here
  400. Return Values:
  401. STATUS_SUCCESS - The data was encrypted successfully. The encrypted
  402. data is in CypherData. The length of the encrypted
  403. data is is CypherData->Length.
  404. STATUS_BUFFER_TOO_SMALL - CypherData.MaximumLength is too small to
  405. contain the encrypted data.
  406. CypherData->Length contains the number of bytes required.
  407. STATUS_INVALID_PARAMETER_2 - Block key is invalid
  408. STATUS_UNSUCCESSFUL - Something failed.
  409. The CypherData is undefined.
  410. --*/
  411. {
  412. NTSTATUS Status;
  413. ULONG CypherDataLength;
  414. ULONG Remaining = ClearData->Length;
  415. CRYPTP_BUFFER CypherDataBuffer;
  416. CRYPTP_BUFFER ClearDataBuffer;
  417. CRYPTP_BUFFER DataKeyBuffer;
  418. BLOCK_KEY BlockKey; // Only used if datakey less than a block long
  419. InitializeBuffer(&ClearDataBuffer, (PCRYPT_BUFFER)ClearData);
  420. InitializeBuffer(&CypherDataBuffer, (PCRYPT_BUFFER)CypherData);
  421. InitializeBuffer(&DataKeyBuffer, (PCRYPT_BUFFER)DataKey);
  422. // Check the key is OK
  423. if (!ValidateDataKey(&DataKeyBuffer, &BlockKey)) {
  424. return(STATUS_INVALID_PARAMETER_2);
  425. }
  426. // Find out how big we need the cypherdata buffer to be
  427. CypherDataLength = CalculateCypherDataLength(&ClearDataBuffer);
  428. // Fail if cypher data buffer too small
  429. if (CypherData->MaximumLength < CypherDataLength) {
  430. CypherData->Length = CypherDataLength;
  431. return(STATUS_BUFFER_TOO_SMALL);
  432. }
  433. //
  434. // Encrypt the clear data length into the start of the cypher data.
  435. //
  436. Status = EncryptDataLength(&ClearDataBuffer, &DataKeyBuffer, &CypherDataBuffer);
  437. if (!NT_SUCCESS(Status)) {
  438. return(Status);
  439. }
  440. //
  441. // Encrypt the clear data a block at a time.
  442. //
  443. while (Remaining >= CLEAR_BLOCK_LENGTH) {
  444. Status = EncryptFullBlock(&ClearDataBuffer, &DataKeyBuffer, &CypherDataBuffer);
  445. if (!NT_SUCCESS(Status)) {
  446. return(Status);
  447. }
  448. Remaining -= CLEAR_BLOCK_LENGTH;
  449. }
  450. //
  451. // Encrypt any partial block that remains
  452. //
  453. if (Remaining > 0) {
  454. Status = EncryptPartialBlock(&ClearDataBuffer, &DataKeyBuffer, &CypherDataBuffer, Remaining);
  455. if (!NT_SUCCESS(Status)) {
  456. return(Status);
  457. }
  458. }
  459. // Return the encrypted data length
  460. CypherData->Length = CypherDataLength;
  461. return(STATUS_SUCCESS);
  462. }
  463. NTSTATUS
  464. RtlDecryptData(
  465. IN PCYPHER_DATA CypherData,
  466. IN PDATA_KEY DataKey,
  467. OUT PCLEAR_DATA ClearData
  468. )
  469. /*++
  470. Routine Description:
  471. Takes an arbitrary block of encrypted data and decrypts it with a
  472. key producing the original clear block of data.
  473. Arguments:
  474. CypherData - The data to be decrypted
  475. DataKey - The key to use to decrypt data
  476. ClearData - The decrpted data of data is returned here
  477. Return Values:
  478. STATUS_SUCCESS - The data was decrypted successfully. The decrypted
  479. data is in ClearData.
  480. STATUS_BUFFER_TOO_SMALL - ClearData->MaximumLength is too small to
  481. contain the decrypted data.
  482. ClearData->Length contains the number of bytes required.
  483. STATUS_INVALID_PARAMETER_2 - Block key is invalid
  484. STATUS_UNSUCCESSFUL - Something failed.
  485. The ClearData is undefined.
  486. --*/
  487. {
  488. NTSTATUS Status;
  489. ULONG Remaining;
  490. CRYPTP_BUFFER CypherDataBuffer;
  491. CRYPTP_BUFFER ClearDataBuffer;
  492. CRYPTP_BUFFER DataKeyBuffer;
  493. BLOCK_KEY BlockKey; // Only used if datakey less than a block long
  494. InitializeBuffer(&ClearDataBuffer, (PCRYPT_BUFFER)ClearData);
  495. InitializeBuffer(&CypherDataBuffer, (PCRYPT_BUFFER)CypherData);
  496. InitializeBuffer(&DataKeyBuffer, (PCRYPT_BUFFER)DataKey);
  497. // Check the key is OK
  498. if (!ValidateDataKey(&DataKeyBuffer, &BlockKey)) {
  499. return(STATUS_INVALID_PARAMETER_2);
  500. }
  501. //
  502. // Decrypt the clear data length from the start of the cypher data.
  503. //
  504. Status = DecryptDataLength(&CypherDataBuffer, &DataKeyBuffer, &ClearDataBuffer);
  505. if (!NT_SUCCESS(Status)) {
  506. return(Status);
  507. }
  508. // Fail if clear data buffer too small
  509. if (ClearData->MaximumLength < ClearDataBuffer.Length) {
  510. ClearData->Length = ClearDataBuffer.Length;
  511. return(STATUS_BUFFER_TOO_SMALL);
  512. }
  513. //
  514. // Decrypt the clear data a block at a time.
  515. //
  516. Remaining = ClearDataBuffer.Length;
  517. while (Remaining >= CLEAR_BLOCK_LENGTH) {
  518. Status = DecryptFullBlock(&CypherDataBuffer, &DataKeyBuffer, &ClearDataBuffer);
  519. if (!NT_SUCCESS(Status)) {
  520. return(Status);
  521. }
  522. Remaining -= CLEAR_BLOCK_LENGTH;
  523. }
  524. //
  525. // Decrypt any partial block that remains
  526. //
  527. if (Remaining > 0) {
  528. Status = DecryptPartialBlock(&CypherDataBuffer, &DataKeyBuffer, &ClearDataBuffer, Remaining);
  529. if (!NT_SUCCESS(Status)) {
  530. return(Status);
  531. }
  532. }
  533. // Return the length of the decrypted data
  534. ClearData->Length = ClearDataBuffer.Length;
  535. return(STATUS_SUCCESS);
  536. }