/*++ Copyright (c) 1991 Microsoft Corporation Module Name: cr.c Abstract: Local Security Authority - Cipher Routines common to Client and Server These routines interface the LSA client or server sides with the Cipher Routines. They perform RPC-style memory allocation. Author: Scott Birrell (ScottBi) December 13, 1991 Environment: Revision History: --*/ #include VOID LsapCrFreeMemoryValue( IN PVOID MemoryValue ) /*++ Routine Description: This function frees the memory allocated for an Cipher Value. Arguments: None. Return Value: --*/ { // // The memory is currently a counted string contained in a UNICODE // STRING structure in which the buffer follows the structure. A // single MIDL_user_free will therefore do the trick. // MIDL_user_free(MemoryValue); } NTSTATUS LsapCrEncryptValue( IN OPTIONAL PLSAP_CR_CLEAR_VALUE ClearValue, IN PLSAP_CR_CIPHER_KEY CipherKey, OUT PLSAP_CR_CIPHER_VALUE *CipherValue ) /*++ Routine Description: This function two-way encrypts a Value with the given Cipher Key and allocates memory for the output. The memory must be freed after use by calling LsapCrFreeMemoryValue(). Arguments: ClearValue - Pointer to structure referencing value to be encrypted. A NULL pointer may be specified. CipherKey - Pointer to structure referencing the Cipher Key CipherValue - Receives a pointer to a structure referencing the encrypted value or NULL. Return Value: --*/ { NTSTATUS Status; LSAP_CR_CIPHER_VALUE TempCipherValue; PLSAP_CR_CIPHER_VALUE OutputCipherValue = NULL; ULONG CipherValueBufferLength; LSAP_CR_CLEAR_VALUE LocalFake = { 0 }; // // If NULL is specified for input, return NULL for output. // if (!ARGUMENT_PRESENT(ClearValue)) { *CipherValue = NULL; ClearValue = &LocalFake ; } // // Obtain the length of the encrypted value buffer that will be // required by calling the encryption routine in 'query' mode // by passing a pointer to a return Cipher Value structure containing // a MaximumLength of 0. // TempCipherValue.MaximumLength = 0; TempCipherValue.Length = 0; TempCipherValue.Buffer = NULL; Status = LsapCrRtlEncryptData( ClearValue, CipherKey, &TempCipherValue ); if (Status != STATUS_BUFFER_TOO_SMALL) { goto EncryptValueError; } // // Allocate memory for the output structure followed by buffer. // CipherValueBufferLength = TempCipherValue.Length; Status = STATUS_INSUFFICIENT_RESOURCES; OutputCipherValue = MIDL_user_allocate( sizeof (LSAP_CR_CIPHER_VALUE) + CipherValueBufferLength ); if (OutputCipherValue == NULL) { goto EncryptValueError; } // // Initialize Cipher Value structure. The Buffer pointer is set to // to point to the byte following the structure header. // OutputCipherValue->Buffer = (PCHAR)(OutputCipherValue + 1); OutputCipherValue->MaximumLength = CipherValueBufferLength; OutputCipherValue->Length = CipherValueBufferLength; // // Now call the two-way encryption routine. // Status = LsapCrRtlEncryptData( ClearValue, CipherKey, OutputCipherValue ); if (NT_SUCCESS(Status)) { *CipherValue = OutputCipherValue; return(Status); } EncryptValueError: // // If necessary, free the memory allocated for the output encrypted value. // if (OutputCipherValue != NULL) { MIDL_user_free(OutputCipherValue); } *CipherValue = NULL; return(Status); } NTSTATUS LsapCrDecryptValue( IN OPTIONAL PLSAP_CR_CIPHER_VALUE CipherValue, IN PLSAP_CR_CIPHER_KEY CipherKey, OUT PLSAP_CR_CLEAR_VALUE *ClearValue ) /*++ Routine Description: This function decrypts a Value that has been two-way Cipher with the given Cipher Key and allocates memory for the output. The memory must be freed after use by calling LsapCrFreeMemoryValue(); Arguments: CipherValue - Pointer to structure referencing encrypted Value. CipherKey - Pointer to structure referencing the Cipher Key ClearValue - Receives a pointer to a structure referencing the Decrypted Value. Return Value: --*/ { NTSTATUS Status; LSAP_CR_CLEAR_VALUE TempClearValue; PLSAP_CR_CLEAR_VALUE OutputClearValue = NULL; ULONG ClearValueBufferLength; // // If NULL is specified for input, return NULL for output. // if (!ARGUMENT_PRESENT(CipherValue)) { *ClearValue = NULL; } else { if ( CipherValue->MaximumLength < CipherValue->Length || ( CipherValue->Length != 0 && CipherValue->Buffer == NULL ) ) { return STATUS_INVALID_PARAMETER; } } // // Obtain the length of the decrypted (clear) value buffer that will be // required by calling the decryption routine in 'query' mode // by passing a pointer to a return Clear Value structure containing // a MaximumLength of 0. // TempClearValue.MaximumLength = 0; TempClearValue.Length = 0; TempClearValue.Buffer = NULL; Status = LsapCrRtlDecryptData( CipherValue, CipherKey, &TempClearValue ); // // Since we supplied a buffer length of 0, we would normally expect // to receive STATUS_BUFFER_TOO_SMALL back plus the buffer size required. // There is one exceptional case and that is where the original // unencrypted data had length 0. In this case, we expect // STATUS_SUCCESS and a length required equal to 0 returned. // if (Status != STATUS_BUFFER_TOO_SMALL) { if (!(Status == STATUS_SUCCESS && TempClearValue.Length == 0)) { goto DecryptValueError; } } // // Allocate memory for the output structure followed by buffer. // ClearValueBufferLength = TempClearValue.Length; Status = STATUS_INSUFFICIENT_RESOURCES; OutputClearValue = MIDL_user_allocate( sizeof (LSAP_CR_CLEAR_VALUE) + ClearValueBufferLength ); if (OutputClearValue == NULL) { goto DecryptValueError; } // // Initialize Clear Value structure. The Buffer pointer is set to // to point to the byte following the structure header. // OutputClearValue->Buffer = (PCHAR)(OutputClearValue + 1); OutputClearValue->MaximumLength = ClearValueBufferLength; OutputClearValue->Length = ClearValueBufferLength; // // Now call the two-way decryption routine. // Status = LsapCrRtlDecryptData( CipherValue, CipherKey, OutputClearValue ); if (NT_SUCCESS(Status)) { *ClearValue = OutputClearValue; return(Status); } DecryptValueError: // // If necessary, free the memory allocated for the output decrypted value. // if (OutputClearValue != NULL) { MIDL_user_free(OutputClearValue); } *ClearValue = NULL; return(Status); } VOID LsapCrUnicodeToClearValue( IN OPTIONAL PUNICODE_STRING UnicodeString, OUT PLSAP_CR_CLEAR_VALUE ClearValue ) /*++ Routine Description: This function converts a Unicode structure to a Clear Value structure. Arguments: UnicodeString - Optional pointer to Unicode string. If NULL, the output Clear Value structure is initialized to have zero length and Maximum length, and with a NULL buffer pointer. ClearValue - Pointer to Clear Value structure. Return Value: None. --*/ { UNICODE_STRING IntermediateUnicodeString; if (ARGUMENT_PRESENT(UnicodeString)) { IntermediateUnicodeString = *UnicodeString; ClearValue->Length = (ULONG) IntermediateUnicodeString.Length; ClearValue->MaximumLength = (ULONG) IntermediateUnicodeString.MaximumLength; ClearValue->Buffer = (PUCHAR) IntermediateUnicodeString.Buffer; return; } ClearValue->Length = ClearValue->MaximumLength = 0; ClearValue->Buffer = NULL; } VOID LsapCrClearValueToUnicode( IN OPTIONAL PLSAP_CR_CLEAR_VALUE ClearValue, OUT PUNICODE_STRING UnicodeString ) /*++ Routine Description: This function converts a Clear Value to a Unicode String. The Clear Value structure must have valid syntax - no checking will be done. Arguments: ClearValue - Optional pointer to Clear Value to be converted. If NULL is specified, the output Unicode String structure will be initialized to point to the NULL string. UnicodeString - Pointer to target Unicode String structure. Return Value: None. --*/ { LSAP_CR_CLEAR_VALUE IntermediateClearValue; if (ARGUMENT_PRESENT(ClearValue)) { IntermediateClearValue = *ClearValue; UnicodeString->Length = (USHORT) IntermediateClearValue.Length; UnicodeString->MaximumLength = (USHORT) IntermediateClearValue.MaximumLength; UnicodeString->Buffer = (PWSTR) IntermediateClearValue.Buffer; return; } UnicodeString->Length = UnicodeString->MaximumLength = 0; UnicodeString->Buffer = NULL; }