764 lines
18 KiB
C
764 lines
18 KiB
C
/*++
|
||
|
||
Copyright (c) 1989 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
data.c
|
||
|
||
Abstract:
|
||
|
||
Arbitrary length data encryption functions implementation :
|
||
|
||
RtlEncryptData
|
||
RtlDecryptData
|
||
|
||
|
||
Author:
|
||
|
||
David Chalmers (Davidc) 12-16-91
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include <nt.h>
|
||
#include <ntrtl.h>
|
||
#include <crypt.h>
|
||
#include <engine.h>
|
||
|
||
//
|
||
// Version number of encrypted data
|
||
// Update this number if the method used encrypt the data changes
|
||
//
|
||
#define DATA_ENCRYPTION_VERSION 1
|
||
|
||
//
|
||
// Private data types
|
||
//
|
||
typedef struct _CRYPTP_BUFFER {
|
||
ULONG Length; // Number of valid bytes in buffer
|
||
ULONG MaximumLength; // Number of bytes pointed to by buffer
|
||
PCHAR Buffer;
|
||
PCHAR Pointer; // Points into buffer
|
||
} CRYPTP_BUFFER;
|
||
typedef CRYPTP_BUFFER *PCRYPTP_BUFFER;
|
||
|
||
//
|
||
// Internal helper macros
|
||
#define AdvanceCypherData(p) ((PCYPHER_BLOCK)(((PCRYPTP_BUFFER)p)->Pointer)) ++
|
||
#define AdvanceClearData(p) ((PCLEAR_BLOCK)(((PCRYPTP_BUFFER)p)->Pointer)) ++
|
||
|
||
|
||
//
|
||
// Private routines
|
||
//
|
||
|
||
VOID
|
||
InitializeBuffer(
|
||
OUT PCRYPTP_BUFFER PrivateBuffer,
|
||
IN PCRYPT_BUFFER PublicBuffer
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Internal helper routine
|
||
|
||
Copies fields from public buffer into private buffer.
|
||
Sets the Pointer field of the private buffer to the
|
||
base of the buffer.
|
||
|
||
Arguments:
|
||
|
||
PrivateBuffer - out internal buffer we want to represent the public structure.
|
||
|
||
PublicBuffer - the buffer the caller passed us
|
||
|
||
Return Values:
|
||
|
||
None
|
||
--*/
|
||
{
|
||
PrivateBuffer->Length = PublicBuffer->Length;
|
||
PrivateBuffer->MaximumLength = PublicBuffer->MaximumLength;
|
||
PrivateBuffer->Buffer = PublicBuffer->Buffer;
|
||
PrivateBuffer->Pointer = PublicBuffer->Buffer;
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
ValidateDataKey(
|
||
IN PCRYPTP_BUFFER DataKey,
|
||
IN PBLOCK_KEY BlockKey
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Internal helper routine
|
||
|
||
Checks the validity of the data key and constructs a minimum length
|
||
key in the passed blockkey if the datakey is not long enough.
|
||
|
||
Arguments:
|
||
|
||
DataKey - The data key
|
||
|
||
Return Values:
|
||
|
||
TRUE if the key is valid, otherwise FALSE
|
||
|
||
--*/
|
||
{
|
||
if ( ( DataKey->Length == 0 ) ||
|
||
( DataKey->Buffer == NULL ) ) {
|
||
|
||
return(FALSE);
|
||
}
|
||
|
||
if (DataKey->Length < BLOCK_KEY_LENGTH) {
|
||
|
||
// Make up a minimum length key from the small data key we were
|
||
// given. Store it in the passed blockkey variable and point
|
||
// the datakey buffer at this temporary storage.
|
||
|
||
ULONG DataIndex, BlockIndex;
|
||
|
||
DataIndex = 0;
|
||
for (BlockIndex = 0; BlockIndex < BLOCK_KEY_LENGTH; BlockIndex ++) {
|
||
((PCHAR)BlockKey)[BlockIndex] = DataKey->Buffer[DataIndex];
|
||
DataIndex ++;
|
||
if (DataIndex >= DataKey->Length) {
|
||
DataIndex = 0;
|
||
}
|
||
}
|
||
|
||
// Point the buffer at our constructed block key
|
||
DataKey->Buffer = (PCHAR)BlockKey;
|
||
DataKey->Pointer = (PCHAR)BlockKey;
|
||
DataKey->Length = BLOCK_KEY_LENGTH;
|
||
DataKey->MaximumLength = BLOCK_KEY_LENGTH;
|
||
}
|
||
|
||
return(TRUE);
|
||
}
|
||
|
||
|
||
VOID
|
||
AdvanceDataKey(
|
||
IN PCRYPTP_BUFFER DataKey
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Internal helper routine
|
||
|
||
Moves the data key pointer on to point at the key to use to encrypt
|
||
the next data block. Wraps round at end of key data.
|
||
|
||
Arguments:
|
||
|
||
DataKey - The data key
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS - No problems
|
||
|
||
--*/
|
||
{
|
||
if (DataKey->Length > BLOCK_KEY_LENGTH) {
|
||
|
||
PCHAR EndPointer;
|
||
|
||
// Advance pointer and wrap
|
||
DataKey->Pointer += BLOCK_KEY_LENGTH;
|
||
EndPointer = DataKey->Pointer + BLOCK_KEY_LENGTH;
|
||
|
||
if (EndPointer > &(DataKey->Buffer[DataKey->Length])) {
|
||
|
||
ULONG_PTR Overrun;
|
||
|
||
Overrun = EndPointer - &(DataKey->Buffer[DataKey->Length]);
|
||
|
||
DataKey->Pointer = DataKey->Buffer + (BLOCK_KEY_LENGTH - Overrun);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
ULONG
|
||
CalculateCypherDataLength(
|
||
IN PCRYPTP_BUFFER ClearData
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Internal helper routine
|
||
|
||
Returns the number of bytes required to encrypt the specified number
|
||
of clear data bytes.
|
||
|
||
Arguments:
|
||
|
||
ClearData - The clear data
|
||
|
||
Return Values:
|
||
|
||
Number of cypher bytes required.
|
||
--*/
|
||
{
|
||
ULONG CypherDataLength;
|
||
ULONG BlockExcess;
|
||
|
||
// We always store the length of the clear data as a whole block.
|
||
CypherDataLength = CYPHER_BLOCK_LENGTH + ClearData->Length;
|
||
|
||
// Round up to the next block
|
||
BlockExcess = CypherDataLength % CYPHER_BLOCK_LENGTH;
|
||
if (BlockExcess > 0) {
|
||
CypherDataLength += CYPHER_BLOCK_LENGTH - BlockExcess;
|
||
}
|
||
|
||
return(CypherDataLength);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
EncryptDataLength(
|
||
IN PCRYPTP_BUFFER Data,
|
||
IN PCRYPTP_BUFFER DataKey,
|
||
OUT PCRYPTP_BUFFER CypherData
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Internal helper routine
|
||
|
||
Encrypts the clear data length and puts the encrypted value in the
|
||
cypherdatabuffer. Advances the cypherdata buffer and datakey buffer pointers
|
||
|
||
Arguments:
|
||
|
||
Data - The buffer whose length is to be encrypted
|
||
|
||
DataKey - key to use to encrypt data
|
||
|
||
CypherData - Place to store encrypted data
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS - Success.
|
||
|
||
STATUS_UNSUCCESSFUL - Something failed.
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
CLEAR_BLOCK ClearBlock;
|
||
|
||
// Fill the clear block with the data value and a version number
|
||
((ULONG *)&ClearBlock)[0] = Data->Length;
|
||
((ULONG *)&ClearBlock)[1] = DATA_ENCRYPTION_VERSION;
|
||
|
||
Status = RtlEncryptBlock(&ClearBlock,
|
||
(PBLOCK_KEY)(DataKey->Pointer),
|
||
(PCYPHER_BLOCK)(CypherData->Pointer));
|
||
|
||
// Advance pointers
|
||
AdvanceCypherData(CypherData);
|
||
AdvanceDataKey(DataKey);
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
EncryptFullBlock(
|
||
IN OUT PCRYPTP_BUFFER ClearData,
|
||
IN OUT PCRYPTP_BUFFER DataKey,
|
||
IN OUT PCRYPTP_BUFFER CypherData
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Internal helper routine
|
||
|
||
Encrypts a full block of data from ClearData and puts the encrypted
|
||
data in CypherData.
|
||
Both cleardata, datakey and cypherdata pointers are advanced.
|
||
|
||
Arguments:
|
||
|
||
ClearData - Pointer to the cleardata buffer
|
||
|
||
DataKey - key to use to encrypt data
|
||
|
||
CypherData - Pointer to cypherdata buffer.
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS - Success.
|
||
|
||
STATUS_UNSUCCESSFUL - Something failed.
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
Status = RtlEncryptBlock((PCLEAR_BLOCK)(ClearData->Pointer),
|
||
(PBLOCK_KEY)(DataKey->Pointer),
|
||
(PCYPHER_BLOCK)(CypherData->Pointer));
|
||
|
||
// Advance pointers
|
||
AdvanceClearData(ClearData);
|
||
AdvanceCypherData(CypherData);
|
||
AdvanceDataKey(DataKey);
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
EncryptPartialBlock(
|
||
IN OUT PCRYPTP_BUFFER ClearData,
|
||
IN OUT PCRYPTP_BUFFER DataKey,
|
||
IN OUT PCRYPTP_BUFFER CypherData,
|
||
IN ULONG Remaining
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Internal helper routine
|
||
|
||
Encrypts a partial block of data from ClearData and puts the full
|
||
encrypted data block in cypherdata.
|
||
Both cleardata, datakey and cypherdata pointers are advanced.
|
||
|
||
Arguments:
|
||
|
||
ClearData - Pointer to the cleardata buffer
|
||
|
||
DataKey - key to use to encrypt data
|
||
|
||
CypherData - Pointer to cypherdata buffer.
|
||
|
||
Remaining - the number of bytes remaining in cleardata buffer
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS - Success.
|
||
|
||
STATUS_UNSUCCESSFUL - Something failed.
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
CLEAR_BLOCK ClearBlockBuffer;
|
||
PCLEAR_BLOCK ClearBlock = &ClearBlockBuffer;
|
||
|
||
ASSERTMSG("EncryptPartialBlock called with a block or more", Remaining < CLEAR_BLOCK_LENGTH);
|
||
|
||
// Copy the remaining bytes into a clear block buffer
|
||
while (Remaining > 0) {
|
||
|
||
*((PCHAR)ClearBlock) ++ = *(ClearData->Pointer) ++;
|
||
Remaining --;
|
||
}
|
||
|
||
// Zero pad
|
||
while (ClearBlock < &((&ClearBlockBuffer)[1])) {
|
||
|
||
*((PCHAR)ClearBlock) ++ = 0;
|
||
}
|
||
|
||
Status = RtlEncryptBlock(&ClearBlockBuffer,
|
||
(PBLOCK_KEY)(DataKey->Pointer),
|
||
(PCYPHER_BLOCK)(CypherData->Pointer));
|
||
|
||
// Advance pointers
|
||
AdvanceClearData(ClearData);
|
||
AdvanceCypherData(CypherData);
|
||
AdvanceDataKey(DataKey);
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
DecryptDataLength(
|
||
IN PCRYPTP_BUFFER CypherData,
|
||
IN PCRYPTP_BUFFER DataKey,
|
||
OUT PCRYPTP_BUFFER Data
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Internal helper routine
|
||
|
||
Decrypts the data length pointed to by the cypherdata buffer and puts the
|
||
decrypted value in the length field of the data structure.
|
||
Advances the cypherdata buffer and datakey buffer pointers
|
||
|
||
Arguments:
|
||
|
||
CypherData - The buffer containing the encrypted length
|
||
|
||
DataKey - key to use to decrypt data
|
||
|
||
Data - Decrypted length field is stored in the length field of this struct.
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS - Success.
|
||
|
||
STATUS_UNSUCCESSFUL - Something failed.
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
CLEAR_BLOCK ClearBlock;
|
||
ULONG Version;
|
||
|
||
Status = RtlDecryptBlock((PCYPHER_BLOCK)(CypherData->Pointer),
|
||
(PBLOCK_KEY)(DataKey->Pointer),
|
||
&ClearBlock);
|
||
if (!NT_SUCCESS(Status)) {
|
||
return(Status);
|
||
}
|
||
|
||
// Advance pointers
|
||
AdvanceCypherData(CypherData);
|
||
AdvanceDataKey(DataKey);
|
||
|
||
// Copy the decrypted length into the data structure.
|
||
Data->Length = ((ULONG *)&ClearBlock)[0];
|
||
|
||
// Check the version
|
||
Version = ((ULONG *)&ClearBlock)[1];
|
||
if (Version != DATA_ENCRYPTION_VERSION) {
|
||
return(STATUS_UNKNOWN_REVISION);
|
||
}
|
||
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
DecryptFullBlock(
|
||
IN OUT PCRYPTP_BUFFER CypherData,
|
||
IN OUT PCRYPTP_BUFFER DataKey,
|
||
IN OUT PCRYPTP_BUFFER ClearData
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Internal helper routine
|
||
|
||
Decrypts a full block of data from CypherData and puts the encrypted
|
||
data in ClearData.
|
||
Both cleardata, datakey and cypherdata pointers are advanced.
|
||
|
||
Arguments:
|
||
|
||
CypherData - Pointer to cypherdata buffer.
|
||
|
||
ClearData - Pointer to the cleardata buffer
|
||
|
||
DataKey - key to use to encrypt data
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS - Success.
|
||
|
||
STATUS_UNSUCCESSFUL - Something failed.
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
Status = RtlDecryptBlock((PCYPHER_BLOCK)(CypherData->Pointer),
|
||
(PBLOCK_KEY)(DataKey->Pointer),
|
||
(PCLEAR_BLOCK)(ClearData->Pointer));
|
||
|
||
// Advance pointers
|
||
AdvanceClearData(ClearData);
|
||
AdvanceCypherData(CypherData);
|
||
AdvanceDataKey(DataKey);
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
DecryptPartialBlock(
|
||
IN OUT PCRYPTP_BUFFER CypherData,
|
||
IN OUT PCRYPTP_BUFFER DataKey,
|
||
IN OUT PCRYPTP_BUFFER ClearData,
|
||
IN ULONG Remaining
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Internal helper routine
|
||
|
||
Decrypts a full block of data from CypherData and puts the partial
|
||
decrypted data block in cleardata.
|
||
Both cleardata, datakey and cypherdata pointers are advanced.
|
||
|
||
Arguments:
|
||
|
||
CypherData - Pointer to cypherdata buffer.
|
||
|
||
ClearData - Pointer to the cleardata buffer
|
||
|
||
DataKey - key to use to encrypt data
|
||
|
||
Remaining - the number of bytes remaining in cleardata buffer
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS - Success.
|
||
|
||
STATUS_UNSUCCESSFUL - Something failed.
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
CLEAR_BLOCK ClearBlockBuffer;
|
||
PCLEAR_BLOCK ClearBlock = &ClearBlockBuffer;
|
||
|
||
ASSERTMSG("DecryptPartialBlock called with a block or more", Remaining < CLEAR_BLOCK_LENGTH);
|
||
|
||
// Decrypt the block into a local clear block
|
||
Status = RtlDecryptBlock((PCYPHER_BLOCK)(CypherData->Pointer),
|
||
(PBLOCK_KEY)(DataKey->Pointer),
|
||
&ClearBlockBuffer);
|
||
if (!NT_SUCCESS(Status)) {
|
||
return(Status);
|
||
}
|
||
|
||
// Copy the decrypted bytes into the cleardata buffer.
|
||
while (Remaining > 0) {
|
||
|
||
*(ClearData->Pointer) ++ = *((PCHAR)ClearBlock) ++;
|
||
Remaining --;
|
||
}
|
||
|
||
// Advance pointers
|
||
AdvanceClearData(ClearData);
|
||
AdvanceCypherData(CypherData);
|
||
AdvanceDataKey(DataKey);
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
//
|
||
// Public functions
|
||
//
|
||
|
||
|
||
NTSTATUS
|
||
RtlEncryptData(
|
||
IN PCLEAR_DATA ClearData,
|
||
IN PDATA_KEY DataKey,
|
||
OUT PCYPHER_DATA CypherData
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Takes an arbitrary length block of data and encrypts it with a
|
||
data key producing an encrypted block of data.
|
||
|
||
Arguments:
|
||
|
||
ClearData - The data to be encrypted.
|
||
|
||
DataKey - The key to use to encrypt the data
|
||
|
||
CypherData - Encrypted data is returned here
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS - The data was encrypted successfully. The encrypted
|
||
data is in CypherData. The length of the encrypted
|
||
data is is CypherData->Length.
|
||
|
||
STATUS_BUFFER_TOO_SMALL - CypherData.MaximumLength is too small to
|
||
contain the encrypted data.
|
||
CypherData->Length contains the number of bytes required.
|
||
|
||
STATUS_INVALID_PARAMETER_2 - Block key is invalid
|
||
|
||
STATUS_UNSUCCESSFUL - Something failed.
|
||
The CypherData is undefined.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
ULONG CypherDataLength;
|
||
ULONG Remaining = ClearData->Length;
|
||
CRYPTP_BUFFER CypherDataBuffer;
|
||
CRYPTP_BUFFER ClearDataBuffer;
|
||
CRYPTP_BUFFER DataKeyBuffer;
|
||
BLOCK_KEY BlockKey; // Only used if datakey less than a block long
|
||
|
||
InitializeBuffer(&ClearDataBuffer, (PCRYPT_BUFFER)ClearData);
|
||
InitializeBuffer(&CypherDataBuffer, (PCRYPT_BUFFER)CypherData);
|
||
InitializeBuffer(&DataKeyBuffer, (PCRYPT_BUFFER)DataKey);
|
||
|
||
// Check the key is OK
|
||
if (!ValidateDataKey(&DataKeyBuffer, &BlockKey)) {
|
||
return(STATUS_INVALID_PARAMETER_2);
|
||
}
|
||
|
||
// Find out how big we need the cypherdata buffer to be
|
||
CypherDataLength = CalculateCypherDataLength(&ClearDataBuffer);
|
||
|
||
// Fail if cypher data buffer too small
|
||
if (CypherData->MaximumLength < CypherDataLength) {
|
||
CypherData->Length = CypherDataLength;
|
||
return(STATUS_BUFFER_TOO_SMALL);
|
||
}
|
||
|
||
//
|
||
// Encrypt the clear data length into the start of the cypher data.
|
||
//
|
||
Status = EncryptDataLength(&ClearDataBuffer, &DataKeyBuffer, &CypherDataBuffer);
|
||
if (!NT_SUCCESS(Status)) {
|
||
return(Status);
|
||
}
|
||
|
||
//
|
||
// Encrypt the clear data a block at a time.
|
||
//
|
||
while (Remaining >= CLEAR_BLOCK_LENGTH) {
|
||
|
||
Status = EncryptFullBlock(&ClearDataBuffer, &DataKeyBuffer, &CypherDataBuffer);
|
||
if (!NT_SUCCESS(Status)) {
|
||
return(Status);
|
||
}
|
||
Remaining -= CLEAR_BLOCK_LENGTH;
|
||
}
|
||
|
||
//
|
||
// Encrypt any partial block that remains
|
||
//
|
||
if (Remaining > 0) {
|
||
Status = EncryptPartialBlock(&ClearDataBuffer, &DataKeyBuffer, &CypherDataBuffer, Remaining);
|
||
if (!NT_SUCCESS(Status)) {
|
||
return(Status);
|
||
}
|
||
}
|
||
|
||
// Return the encrypted data length
|
||
CypherData->Length = CypherDataLength;
|
||
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
RtlDecryptData(
|
||
IN PCYPHER_DATA CypherData,
|
||
IN PDATA_KEY DataKey,
|
||
OUT PCLEAR_DATA ClearData
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Takes an arbitrary block of encrypted data and decrypts it with a
|
||
key producing the original clear block of data.
|
||
|
||
Arguments:
|
||
|
||
CypherData - The data to be decrypted
|
||
|
||
DataKey - The key to use to decrypt data
|
||
|
||
ClearData - The decrpted data of data is returned here
|
||
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS - The data was decrypted successfully. The decrypted
|
||
data is in ClearData.
|
||
|
||
STATUS_BUFFER_TOO_SMALL - ClearData->MaximumLength is too small to
|
||
contain the decrypted data.
|
||
ClearData->Length contains the number of bytes required.
|
||
|
||
STATUS_INVALID_PARAMETER_2 - Block key is invalid
|
||
|
||
STATUS_UNSUCCESSFUL - Something failed.
|
||
The ClearData is undefined.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
ULONG Remaining;
|
||
CRYPTP_BUFFER CypherDataBuffer;
|
||
CRYPTP_BUFFER ClearDataBuffer;
|
||
CRYPTP_BUFFER DataKeyBuffer;
|
||
BLOCK_KEY BlockKey; // Only used if datakey less than a block long
|
||
|
||
InitializeBuffer(&ClearDataBuffer, (PCRYPT_BUFFER)ClearData);
|
||
InitializeBuffer(&CypherDataBuffer, (PCRYPT_BUFFER)CypherData);
|
||
InitializeBuffer(&DataKeyBuffer, (PCRYPT_BUFFER)DataKey);
|
||
|
||
// Check the key is OK
|
||
if (!ValidateDataKey(&DataKeyBuffer, &BlockKey)) {
|
||
return(STATUS_INVALID_PARAMETER_2);
|
||
}
|
||
|
||
//
|
||
// Decrypt the clear data length from the start of the cypher data.
|
||
//
|
||
Status = DecryptDataLength(&CypherDataBuffer, &DataKeyBuffer, &ClearDataBuffer);
|
||
if (!NT_SUCCESS(Status)) {
|
||
return(Status);
|
||
}
|
||
|
||
// Fail if clear data buffer too small
|
||
if (ClearData->MaximumLength < ClearDataBuffer.Length) {
|
||
ClearData->Length = ClearDataBuffer.Length;
|
||
return(STATUS_BUFFER_TOO_SMALL);
|
||
}
|
||
|
||
//
|
||
// Decrypt the clear data a block at a time.
|
||
//
|
||
Remaining = ClearDataBuffer.Length;
|
||
while (Remaining >= CLEAR_BLOCK_LENGTH) {
|
||
|
||
Status = DecryptFullBlock(&CypherDataBuffer, &DataKeyBuffer, &ClearDataBuffer);
|
||
if (!NT_SUCCESS(Status)) {
|
||
return(Status);
|
||
}
|
||
Remaining -= CLEAR_BLOCK_LENGTH;
|
||
}
|
||
|
||
//
|
||
// Decrypt any partial block that remains
|
||
//
|
||
if (Remaining > 0) {
|
||
Status = DecryptPartialBlock(&CypherDataBuffer, &DataKeyBuffer, &ClearDataBuffer, Remaining);
|
||
if (!NT_SUCCESS(Status)) {
|
||
return(Status);
|
||
}
|
||
}
|
||
|
||
// Return the length of the decrypted data
|
||
ClearData->Length = ClearDataBuffer.Length;
|
||
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|