diff --git a/sdk/xtdk/rtltypes.h b/sdk/xtdk/rtltypes.h index 505f1e6..d01947f 100644 --- a/sdk/xtdk/rtltypes.h +++ b/sdk/xtdk/rtltypes.h @@ -49,6 +49,10 @@ #define PFL_DIGIT_PRECISION 0x00002000 #define PFL_THOUSANDS_GROUPING 0x00004000 +/* Cryptographic related definitions */ +#define SHA1_BLOCK_SIZE 64 +#define SHA1_DIGEST_SIZE 20 + /* Runtime Library routine callbacks */ typedef XTSTATUS (*PWRITE_CHARACTER)(IN CHAR Character); typedef XTSTATUS (*PWRITE_WIDE_CHARACTER)(IN WCHAR Character); @@ -95,4 +99,12 @@ typedef struct _RTL_PRINT_FORMAT_PROPERTIES LONG Flags; } RTL_PRINT_FORMAT_PROPERTIES, *PRTL_PRINT_FORMAT_PROPERTIES; +/* Runtime Library SHA-1 context structure definition */ +typedef struct _RTL_SHA1_CONTEXT +{ + ULONG State[5]; + ULONG Count[2]; + UCHAR Buffer[SHA1_BLOCK_SIZE]; +} RTL_SHA1_CONTEXT, *PRTL_SHA1_CONTEXT; + #endif /* __XTDK_RTLTYPES_H */ diff --git a/sdk/xtdk/xtdefs.h b/sdk/xtdk/xtdefs.h index 7faae86..a573847 100644 --- a/sdk/xtdk/xtdefs.h +++ b/sdk/xtdk/xtdefs.h @@ -80,6 +80,10 @@ /* Macro that returns offset of the virtual address */ #define PAGE_OFFSET(VirtualAddress) ((ULONG)((ULONG_PTR)VirtualAddress & MM_PAGE_MASK)) +/* Macros for bitwise rotating */ +#define ROTATE_LEFT(Value, Count) ((Value << Count) | (Value >> (32 - Count))) +#define ROTATE_RIGHT(Value, Count) ((Value >> Count) | (Value << (32 - Count))) + /* Macro for rounding down */ #define ROUND_DOWN(Value, Alignment) ((Value) & ~((Alignment) - 1)) @@ -104,7 +108,7 @@ /* Variadic ABI functions */ typedef __builtin_va_list VA_LIST, *PVA_LIST; -#define VA_ARG(Marker, Type) ((sizeof (Type) < sizeof(UINT_PTR)) ? \ +#define VA_ARG(Marker, Type) ((sizeof(Type) < sizeof(UINT_PTR)) ? \ (Type)(__builtin_va_arg(Marker, UINT_PTR)) : \ (Type)(__builtin_va_arg(Marker, Type))) #define VA_COPY(Dest, Start) __builtin_va_copy(Dest, Start) diff --git a/xtoskrnl/CMakeLists.txt b/xtoskrnl/CMakeLists.txt index dbfab46..3e378b2 100644 --- a/xtoskrnl/CMakeLists.txt +++ b/xtoskrnl/CMakeLists.txt @@ -79,6 +79,8 @@ list(APPEND XTOSKRNL_SOURCE ${XTOSKRNL_SOURCE_DIR}/rtl/llist.cc ${XTOSKRNL_SOURCE_DIR}/rtl/math.cc ${XTOSKRNL_SOURCE_DIR}/rtl/memory.cc + ${XTOSKRNL_SOURCE_DIR}/rtl/sha1.cc + ${XTOSKRNL_SOURCE_DIR}/rtl/slist.cc ${XTOSKRNL_SOURCE_DIR}/rtl/string.cc ${XTOSKRNL_SOURCE_DIR}/rtl/widestr.cc) diff --git a/xtoskrnl/includes/rtl.hh b/xtoskrnl/includes/rtl.hh index a35ca99..8b28b89 100644 --- a/xtoskrnl/includes/rtl.hh +++ b/xtoskrnl/includes/rtl.hh @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include #include diff --git a/xtoskrnl/includes/rtl/llist.hh b/xtoskrnl/includes/rtl/llist.hh index dc0e6ab..acea1e5 100644 --- a/xtoskrnl/includes/rtl/llist.hh +++ b/xtoskrnl/includes/rtl/llist.hh @@ -4,6 +4,7 @@ * FILE: xtoskrnl/includes/rtl/llist.hh * DESCRIPTION: Linked list manipulation routines * DEVELOPERS: Aiken Harris + * Rafal Kupiec */ #ifndef __XTOSKRNL_RTL_LLIST_HH @@ -18,6 +19,7 @@ namespace RTL class LinkedList { public: + STATIC XTCDECL PLIST_ENTRY GetFirstEntry(IN PLIST_ENTRY ListHead); STATIC XTCDECL VOID InitializeListHead(IN PLIST_ENTRY ListHead); STATIC XTCDECL VOID InitializeListHead32(IN PLIST_ENTRY32 ListHead); STATIC XTCDECL VOID InsertHeadList(IN OUT PLIST_ENTRY ListHead, @@ -27,6 +29,10 @@ namespace RTL STATIC XTCDECL BOOLEAN ListEmpty(IN PLIST_ENTRY ListHead); STATIC XTCDECL BOOLEAN ListLoop(IN PLIST_ENTRY ListHead); STATIC XTCDECL VOID RemoveEntryList(IN PLIST_ENTRY Entry); + STATIC XTCDECL VOID SpliceHeadList(IN OUT PLIST_ENTRY ListHead, + IN OUT PLIST_ENTRY SpliceList); + STATIC XTCDECL VOID SpliceTailList(IN OUT PLIST_ENTRY ListHead, + IN OUT PLIST_ENTRY SpliceList); }; } diff --git a/xtoskrnl/includes/rtl/sha1.hh b/xtoskrnl/includes/rtl/sha1.hh new file mode 100644 index 0000000..4b5e5ed --- /dev/null +++ b/xtoskrnl/includes/rtl/sha1.hh @@ -0,0 +1,37 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/rtl/sha1.hh + * DESCRIPTION: SHA1 computation support + * DEVELOPERS: Rafal Kupiec + */ + +#ifndef __XTOSKRNL_RTL_SHA1_HH +#define __XTOSKRNL_RTL_SHA1_HH + +#include + + +/* Runtime Library */ +namespace RTL +{ + class SHA1 + { + public: + STATIC XTAPI XTSTATUS ComputeDigest(IN PCUCHAR Buffer, + IN SIZE_T BufferSize, + OUT PUCHAR Digest); + + private: + STATIC XTAPI VOID ComputeHash(IN OUT PRTL_SHA1_CONTEXT Context, + OUT PUCHAR Digest); + STATIC XTAPI VOID HashData(IN OUT PRTL_SHA1_CONTEXT Context, + IN PCUCHAR Data, + IN ULONG Length); + STATIC XTAPI XTSTATUS InitializeContext(OUT PRTL_SHA1_CONTEXT Context); + STATIC XTAPI VOID TransformData(IN OUT PULONG State, + IN PCUCHAR Buffer); + }; +} + +#endif /* __XTOSKRNL_RTL_SHA1_HH */ diff --git a/xtoskrnl/includes/rtl/slist.hh b/xtoskrnl/includes/rtl/slist.hh new file mode 100644 index 0000000..1ac5cbd --- /dev/null +++ b/xtoskrnl/includes/rtl/slist.hh @@ -0,0 +1,38 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/rtl/slist.hh + * DESCRIPTION: Singly linked list manipulation routines + * DEVELOPERS: Rafal Kupiec + */ + +#ifndef __XTOSKRNL_RTL_SLIST_HH +#define __XTOSKRNL_RTL_SLIST_HH + +#include + + +/* Runtime Library */ +namespace RTL +{ + class SinglyList + { + public: + STATIC XTCDECL PSINGLE_LIST_ENTRY GetFirstEntry(IN PSINGLE_LIST_HEADER ListHead); + STATIC XTCDECL VOID InitializeListHead(IN PSINGLE_LIST_HEADER ListHead); + STATIC XTCDECL VOID InsertHeadList(IN OUT PSINGLE_LIST_HEADER ListHead, + IN PSINGLE_LIST_ENTRY Entry); + STATIC XTCDECL VOID InsertTailList(IN OUT PSINGLE_LIST_HEADER ListHead, + IN PSINGLE_LIST_ENTRY Entry); + STATIC XTCDECL BOOLEAN ListEmpty(IN PSINGLE_LIST_HEADER ListHead); + STATIC XTAPI USHORT QueryListDepth(IN PSINGLE_LIST_HEADER ListHead); + STATIC XTCDECL VOID RemoveEntryList(IN PSINGLE_LIST_HEADER ListHead, + IN PSINGLE_LIST_ENTRY Entry); + STATIC XTCDECL VOID SpliceHeadList(IN OUT PSINGLE_LIST_HEADER ListHead, + IN OUT PSINGLE_LIST_HEADER SpliceList); + STATIC XTCDECL VOID SpliceTailList(IN OUT PSINGLE_LIST_HEADER ListHead, + IN OUT PSINGLE_LIST_HEADER SpliceList); + }; +} + +#endif /* __XTOSKRNL_RTL_SLIST_HH */ diff --git a/xtoskrnl/rtl/llist.cc b/xtoskrnl/rtl/llist.cc index 58bff64..7ebf450 100644 --- a/xtoskrnl/rtl/llist.cc +++ b/xtoskrnl/rtl/llist.cc @@ -2,7 +2,7 @@ * PROJECT: ExectOS * COPYRIGHT: See COPYING.md in the top level directory * FILE: xtoskrnl/rtl/llist.cc - * DESCRIPTION: Linked list manipulation routines + * DESCRIPTION: Doubly linked list manipulation routines * DEVELOPERS: Rafal Kupiec */ @@ -10,10 +10,35 @@ /** - * This routine initializes a structure representing the head of a double-linked list. + * Retrieves the first entry from a doubly linked list without removing it from the list. * * @param ListHead - * Pointer to a structure that serves as the list header. + * Supplies a pointer to a structure that serves as the list header. + * + * @return This routine returns a pointer to the first entry in the list, or NULLPTR if the list is empty. + * + * @since XT 1.0 + */ +XTCDECL +PLIST_ENTRY +RTL::LinkedList::GetFirstEntry(IN PLIST_ENTRY ListHead) +{ + /* Check if the list is empty */ + if(ListEmpty(ListHead)) + { + /* Empty list, return NULLPTR */ + return NULLPTR; + } + + /* Return first entry in the list */ + return ListHead->Flink; +} + +/** + * Initializes a structure representing the head of a doubly linked list. + * + * @param ListHead + * Supplies a pointer to a structure that serves as the list header. * * @return This routine does not return any value. * @@ -23,15 +48,16 @@ XTCDECL VOID RTL::LinkedList::InitializeListHead(IN PLIST_ENTRY ListHead) { + /* Initialize list head */ ListHead->Blink = ListHead; ListHead->Flink = ListHead; } /** - * This routine initializes a structure representing the head of a 32bit double-linked list. + * Initializes a structure representing the head of a 32bit doubly linked list. * * @param ListHead - * Pointer to a structure that serves as the list header. + * Supplies a pointer to a structure that serves as the list header. * * @return This routine does not return any value. * @@ -41,18 +67,19 @@ XTCDECL VOID RTL::LinkedList::InitializeListHead32(IN PLIST_ENTRY32 ListHead) { + /* Initialize list head */ ListHead->Blink = PtrToUlong(ListHead); ListHead->Flink = PtrToUlong(ListHead); } /** - * This routine inserts an entry at the head of a doubly linked list. + * Inserts an entry at the head of a doubly linked list. * * @param ListHead - * Pointer to the head of the list. + * Supplies a pointer to the head of the list. * * @param Entry - * Pointer to the entry that will be inserted in the list. + * Supplies a pointer to the entry that will be inserted in the list. * * @return This routine does not return any value. * @@ -63,6 +90,7 @@ VOID RTL::LinkedList::InsertHeadList(IN OUT PLIST_ENTRY ListHead, IN PLIST_ENTRY Entry) { + /* Insert entry at the head of the list */ Entry->Flink = ListHead->Flink; Entry->Blink = ListHead; ListHead->Flink->Blink = Entry; @@ -70,13 +98,13 @@ RTL::LinkedList::InsertHeadList(IN OUT PLIST_ENTRY ListHead, } /** - * This routine inserts an entry at the tail of a doubly linked list. + * Inserts an entry at the tail of a doubly linked list. * * @param ListHead - * Pointer to the head of the list. + * Supplies a pointer to the head of the list. * * @param Entry - * Pointer to the entry that will be inserted in the list. + * Supplies a pointer to the entry that will be inserted in the list. * * @return This routine does not return any value. * @@ -87,6 +115,7 @@ VOID RTL::LinkedList::InsertTailList(IN OUT PLIST_ENTRY ListHead, IN PLIST_ENTRY Entry) { + /* Insert entry at the tail of the list */ Entry->Flink = ListHead; Entry->Blink = ListHead->Blink; ListHead->Blink->Flink = Entry; @@ -97,9 +126,9 @@ RTL::LinkedList::InsertTailList(IN OUT PLIST_ENTRY ListHead, * Indicates whether a doubly linked list structure is empty, or not initialized at all. * * @param ListHead - * Pointer to a structure that represents the head of the list. + * Supplies a pointer to a structure that represents the head of the list. * - * @return TRUE if there are currently no entries in the list or FALSE otherwise. + * @return This routine returns TRUE if there are currently no entries in the list or FALSE otherwise. * * @since XT 1.0 */ @@ -107,14 +136,15 @@ XTCDECL BOOLEAN RTL::LinkedList::ListEmpty(IN PLIST_ENTRY ListHead) { + /* Check if the list is empty */ return (((ListHead->Flink == NULLPTR) && (ListHead->Blink == NULLPTR)) || (ListHead->Flink == ListHead)); } /** - * This routine detects a loop in a doubly linked list. + * Detects a loop in a doubly linked list. * * @param ListHead - * Pointer to a structure that represents the head of the list. + * Supplies a pointer to a structure that represents the head of the list. * * @return TRUE if linked list contains a loop or FALSE otherwise. * @@ -157,10 +187,10 @@ RTL::LinkedList::ListLoop(IN PLIST_ENTRY ListHead) } /** - * This routine removes an entry from a doubly linked list. + * Removes an entry from a doubly linked list. * * @param Entry - * Pointer to the entry that will be removed from the list. + * Supplies a pointer to the entry that will be removed from the list. * * @return This routine does not return any value. * @@ -170,6 +200,91 @@ XTCDECL VOID RTL::LinkedList::RemoveEntryList(IN PLIST_ENTRY Entry) { + /* Remove entry from the list */ Entry->Flink->Blink = Entry->Blink; Entry->Blink->Flink = Entry->Flink; } + +/** + * Splices a doubly linked list at the head of another list. The source list is reinitialized to empty. + * + * @param ListHead + * Supplies a pointer to a structure that represents the head of the list. + * + * @param SpliceList + * Supplies a pointer to a structure that represents the head of the list that will be spliced. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTCDECL +VOID +RTL::LinkedList::SpliceHeadList(IN OUT PLIST_ENTRY ListHead, + IN OUT PLIST_ENTRY SpliceList) +{ + PLIST_ENTRY FirstEntry, LastEntry; + + /* Check if the list to splice is empty */ + if(SpliceList->Flink == SpliceList) + { + /* Nothing to splice, return */ + return; + } + + /* Get first and last entries of the list to splice */ + FirstEntry = SpliceList->Flink; + LastEntry = SpliceList->Blink; + + /* Splice the list at the head of destination */ + FirstEntry->Blink = ListHead; + LastEntry->Flink = ListHead->Flink; + ListHead->Flink->Blink = LastEntry; + ListHead->Flink = FirstEntry; + + /* Reinitialize the source list to empty */ + SpliceList->Blink = SpliceList; + SpliceList->Flink = SpliceList; +} + +/** + * Splices a doubly linked list at the tail of another list. The source list is reinitialized to empty. + * + * @param ListHead + * Supplies a pointer to the head of the destination list. + * + * @param SpliceList + * Supplies a pointer to the head of the list that will be spliced. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTCDECL +VOID +RTL::LinkedList::SpliceTailList(IN OUT PLIST_ENTRY ListHead, + IN OUT PLIST_ENTRY SpliceList) +{ + PLIST_ENTRY FirstEntry, LastEntry; + + /* Check if the list to splice is empty */ + if(SpliceList->Flink == SpliceList) + { + /* Nothing to splice, return */ + return; + } + + /* Get first and last entries of the list to splice */ + FirstEntry = SpliceList->Flink; + LastEntry = SpliceList->Blink; + + /* Splice the list at the tail of destination */ + FirstEntry->Blink = ListHead->Blink; + LastEntry->Flink = ListHead; + ListHead->Blink->Flink = FirstEntry; + ListHead->Blink = LastEntry; + + /* Reinitialize the source list to empty */ + SpliceList->Blink = SpliceList; + SpliceList->Flink = SpliceList; +} diff --git a/xtoskrnl/rtl/sha1.cc b/xtoskrnl/rtl/sha1.cc new file mode 100644 index 0000000..3c8ab98 --- /dev/null +++ b/xtoskrnl/rtl/sha1.cc @@ -0,0 +1,322 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/rtl/sha1.cc + * DESCRIPTION: SHA1 computation support + * DEVELOPERS: Rafal Kupiec + */ + +#include + + +/** + * Computes the SHA-1 hash of a buffer in a single step. + * + * @param Buffer + * Supplies a pointer to the buffer containing the data to be hashed. + * + * @param BufferSize + * Specifies the size of the buffer in bytes. + * + * @param Digest + * Supplies a pointer to the buffer that receives the 20-byte SHA-1 hash digest. + * + * @return This routine returns STATUS_SUCCESS if the hash was computed successfully, + * or STATUS_INVALID_PARAMETER if an invalid parameter was supplied. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +RTL::SHA1::ComputeDigest(IN PCUCHAR Buffer, + IN SIZE_T BufferSize, + OUT PUCHAR Digest) +{ + RTL_SHA1_CONTEXT Context; + XTSTATUS Status; + + /* Validate input parameters */ + if(!Digest || (!Buffer && BufferSize > 0)) + { + /* Invalid parameters, return error */ + return STATUS_INVALID_PARAMETER; + } + + /* Initialize SHA-1 context */ + Status = InitializeContext(&Context); + if(Status != STATUS_SUCCESS) + { + /* Failed to initialize SHA-1 context, return error */ + return Status; + } + + /* Hash data and compute SHA-1 digest */ + HashData(&Context, Buffer, BufferSize); + ComputeHash(&Context, Digest); + + /* Return success */ + return STATUS_SUCCESS; +} + +/** + * Finalizes the SHA-1 hash computation and provides the digest. + * + * @param Context + * Supplies a pointer to the SHA-1 context structure. + * + * @param Digest + * Supplies a pointer to a buffer that receives the 20-byte SHA-1 hash digest. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +RTL::SHA1::ComputeHash(IN OUT PRTL_SHA1_CONTEXT Context, + OUT PUCHAR Digest) +{ + ULONG Index, PaddingLength; + UCHAR Padding[64]; + UCHAR Bits[8]; + + /* Zero padding and append 0x80 to it */ + RTL::Memory::ZeroMemory(Padding, 64); + Padding[0] = 0x80; + + /* Encode the total message length in bits as a Big Endian 64-bit integer */ + *(PULONG)(Bits) = RTL::Endianness::SwapByte32(Context->Count[1]); + *(PULONG)(Bits + 4) = RTL::Endianness::SwapByte32(Context->Count[0]); + + /* Calculate padding length needed to align the message to 56 bytes */ + Index = (Context->Count[0] >> 3) & 0x3F; + PaddingLength = (Index < 56) ? (56 - Index) : (120 - Index); + + /* Append the padding bytes to the message stream to satisfy the block boundary */ + HashData(Context, Padding, PaddingLength); + + /* Append bits before final transformation */ + HashData(Context, Bits, 8); + + /* Store hash to output in Big Endian format */ + Digest[0] = (UCHAR)((Context->State[0] >> 24) & 0xFF); + Digest[1] = (UCHAR)((Context->State[0] >> 16) & 0xFF); + Digest[2] = (UCHAR)((Context->State[0] >> 8) & 0xFF); + Digest[3] = (UCHAR)(Context->State[0] & 0xFF); + Digest[4] = (UCHAR)((Context->State[1] >> 24) & 0xFF); + Digest[5] = (UCHAR)((Context->State[1] >> 16) & 0xFF); + Digest[6] = (UCHAR)((Context->State[1] >> 8) & 0xFF); + Digest[7] = (UCHAR)(Context->State[1] & 0xFF); + Digest[8] = (UCHAR)((Context->State[2] >> 24) & 0xFF); + Digest[9] = (UCHAR)((Context->State[2] >> 16) & 0xFF); + Digest[10] = (UCHAR)((Context->State[2] >> 8) & 0xFF); + Digest[11] = (UCHAR)(Context->State[2] & 0xFF); + Digest[12] = (UCHAR)((Context->State[3] >> 24) & 0xFF); + Digest[13] = (UCHAR)((Context->State[3] >> 16) & 0xFF); + Digest[14] = (UCHAR)((Context->State[3] >> 8) & 0xFF); + Digest[15] = (UCHAR)(Context->State[3] & 0xFF); + Digest[16] = (UCHAR)((Context->State[4] >> 24) & 0xFF); + Digest[17] = (UCHAR)((Context->State[4] >> 16) & 0xFF); + Digest[18] = (UCHAR)((Context->State[4] >> 8) & 0xFF); + Digest[19] = (UCHAR)(Context->State[4] & 0xFF); + + /* Clear context memory for security */ + RTL::Memory::ZeroMemory(Context, sizeof(RTL_SHA1_CONTEXT)); +} + +/** + * Updates the SHA-1 context with the provided data buffer. + * + * @param Context + * Supplies a pointer to the SHA-1 context structure. + * + * @param Data + * Supplies a pointer to the buffer containing the data to be hashed. + * + * @param Length + * Specifies the length of the data buffer in bytes. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +RTL::SHA1::HashData(IN OUT PRTL_SHA1_CONTEXT Context, + IN PCUCHAR Data, + IN ULONG Length) +{ + ULONG Index, Input, PartialLength; + + /* Calculate byte offset within the 64-byte block buffer */ + Index = (Context->Count[0] >> 3) & 0x3F; + + /* Update the total bit count, handling overflow from low to high word */ + if((Context->Count[0] += (Length << 3)) < (Length << 3)) + { + /* Increment high 32-bit counter on low counter overflow */ + Context->Count[1]++; + } + + /* Add the high-order bits of the length (bytes -> bits overflow) to the high counter */ + Context->Count[1] += (Length >> 29); + + /* Calculate the number of bytes required to fill the remaining buffer space */ + PartialLength = 64 - Index; + + /* Transform as many times as possible */ + if(Length >= PartialLength) + { + /* Fill the buffer partially and transform */ + RTL::Memory::CopyMemory(&Context->Buffer[Index], Data, PartialLength); + TransformData(Context->State, Context->Buffer); + + /* Process remaining full 64-byte blocks directly from the input pointer */ + for(Input = PartialLength; Input + 63 < Length; Input += 64) + { + /* Transform the full block without copying to the internal buffer */ + TransformData(Context->State, &Data[Input]); + } + + /* Reset buffer index to indicate the buffer is now empty */ + Index = 0; + } + else + { + /* No full block was formed, begin copying from the start of input */ + Input = 0; + } + + /* Buffer remaining input */ + RTL::Memory::CopyMemory(&Context->Buffer[Index], &Data[Input], Length - Input); +} + +/** + * Initializes a SHA-1 context structure with the standard initial hash values. + * + * @param Context + * Supplies a pointer to the SHA-1 context structure to initialize. + * + * @return This routine returns STATUS_SUCCESS if the context was initialized successfully, + * or STATUS_INVALID_PARAMETER if the pointer is NULLPTR. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +RTL::SHA1::InitializeContext(OUT PRTL_SHA1_CONTEXT Context) +{ + /* Validate input parameter */ + if(!Context) + { + /* Invalid parameter, return error */ + return STATUS_INVALID_PARAMETER; + } + + /* Initialize hash constants defined by FIPS 180-4 */ + Context->State[0] = 0x67452301; + Context->State[1] = 0xEFCDAB89; + Context->State[2] = 0x98BADCFE; + Context->State[3] = 0x10325476; + Context->State[4] = 0xC3D2E1F0; + Context->Count[0] = 0; + Context->Count[1] = 0; + + /* Clear buffer */ + RTL::Memory::ZeroMemory(Context->Buffer, SHA1_BLOCK_SIZE); + + /* Return success */ + return STATUS_SUCCESS; +} + +/** + * Transforms a single 64-byte block using the SHA-1 compression function. + * + * @param State + * Supplies a pointer to the array containing the current hash state variables. + * + * @param Buffer + * Supplies a pointer to the 64-byte input buffer to be transformed. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +RTL::SHA1::TransformData(IN OUT PULONG State, + IN PCUCHAR Buffer) +{ + ULONG Constant, Function, Index, TempHash; + ULONG TempState[5]; + ULONG Stack[80]; + + /* Initialize working variables with current state */ + TempState[0] = State[0]; + TempState[1] = State[1]; + TempState[2] = State[2]; + TempState[3] = State[3]; + TempState[4] = State[4]; + + /* Initialize the first 16 words of the message schedule from the input buffer */ + for(Index = 0; Index < 16; Index++) + { + /* Convert input words from Little Endian to Big Endian required by SHA-1 */ + Stack[Index] = RTL::Endianness::SwapByte32(((const PULONG)Buffer)[Index]); + } + + /* Expand the message to 80 words using the SHA-1 algorithm */ + for(Index = 16; Index < 80; Index++) + { + /* Compute the next word value based on XOR and left rotation */ + Stack[Index] = ROTATE_LEFT((Stack[Index - 3] ^ Stack[Index - 8] ^ Stack[Index - 14] ^ Stack[Index - 16]), 1); + } + + /* Execute the main compression loop for 80 rounds */ + for(Index = 0; Index < 80; Index++) + { + /* Determine the logical function and constant based on the current round */ + if(Index < 20) + { + /* Set the constant defined by FIPS 180-4 for rounds 0-19 and calculate the logical function */ + Constant = 0x5A827999; + Function = (TempState[1] & TempState[2]) | ((~TempState[1]) & TempState[3]); + } + else if(Index < 40) + { + /* Set the constant defined by FIPS 180-4 for rounds 20-39 and calculate the logical function */ + Constant = 0x6ED9EBA1; + Function = TempState[1] ^ TempState[2] ^ TempState[3]; + } + else if(Index < 60) + { + /* Set the constant defined by FIPS 180-4 for rounds 40-59 and calculate the logical function */ + Constant = 0x8F1BBCDC; + Function = (TempState[1] & TempState[2]) | (TempState[1] & TempState[3]) | (TempState[2] & TempState[3]); + } + else + { + /* Set the constant defined by FIPS 180-4 for rounds 60-79 and calculate the logical function */ + Constant = 0xCA62C1D6; + Function = TempState[1] ^ TempState[2] ^ TempState[3]; + } + + /* Calculate the temporary hash value for this round */ + TempHash = ROTATE_LEFT(TempState[0], 5) + Function + TempState[4] + Constant + Stack[Index]; + TempState[4] = TempState[3]; + TempState[3] = TempState[2]; + TempState[2] = ROTATE_LEFT(TempState[1], 30); + TempState[1] = TempState[0]; + TempState[0] = TempHash; + } + + /* Add the compressed chunk to the current hash value */ + State[0] += TempState[0]; + State[1] += TempState[1]; + State[2] += TempState[2]; + State[3] += TempState[3]; + State[4] += TempState[4]; + + /* Clear sensitive data from stack */ + RTL::Memory::ZeroMemory(Stack, sizeof(Stack)); +} diff --git a/xtoskrnl/rtl/slist.cc b/xtoskrnl/rtl/slist.cc new file mode 100644 index 0000000..1cedebe --- /dev/null +++ b/xtoskrnl/rtl/slist.cc @@ -0,0 +1,327 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/rtl/slist.cc + * DESCRIPTION: Singly linked list manipulation routines + * DEVELOPERS: Rafal Kupiec + */ + +#include + + +/** + * Retrieves the first entry from a singly linked list without removing it from the list. + * + * @param ListHead + * Supplies a pointer to a structure that serves as the list header. + * + * @return This routine returns a pointer to the first entry in the list, or NULLPTR if the list is empty. + * + * @since XT 1.0 + */ +XTCDECL +PSINGLE_LIST_ENTRY +RTL::SinglyList::GetFirstEntry(IN PSINGLE_LIST_HEADER ListHead) +{ + /* Check if the list is empty */ + if(ListEmpty(ListHead)) + { + /* Empty list, return NULLPTR */ + return NULLPTR; + } + + /* Return first entry in the list */ + return ListHead->Next.Next; +} + +/** + * Initializes a structure representing the head of a singly linked list. + * + * @param ListHead + * Supplies a pointer to a structure that serves as the list header. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTCDECL +VOID +RTL::SinglyList::InitializeListHead(IN PSINGLE_LIST_HEADER ListHead) +{ + /* Initialize the list head */ + ListHead->Alignment = 0; +} + +/** + * Inserts an entry at the head of a singly linked list. + * + * @param ListHead + * Supplies a pointer to the head of the list. + * + * @param Entry + * Supplies a pointer to the entry that will be inserted in the list. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTCDECL +VOID +RTL::SinglyList::InsertHeadList(IN OUT PSINGLE_LIST_HEADER ListHead, + IN PSINGLE_LIST_ENTRY Entry) +{ + /* Insert entry at the head of the list and increment depth */ + Entry->Next = ListHead->Next.Next; + ListHead->Next.Next = Entry; + ListHead->Depth++; +} + +/** + * Inserts an entry at the tail of a singly linked list. + * + * @param ListHead + * Supplies a pointer to the head of the list. + * + * @param Entry + * Supplies a pointer to the entry that will be inserted in the list. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTCDECL +VOID +RTL::SinglyList::InsertTailList(IN OUT PSINGLE_LIST_HEADER ListHead, + IN PSINGLE_LIST_ENTRY Entry) +{ + PSINGLE_LIST_ENTRY CurrentEntry; + + /* Set Next pointer of the new entry to NULLPTR */ + Entry->Next = NULLPTR; + + /* Check if the list is empty */ + if(ListEmpty(ListHead)) + { + /* Insert entry at the head */ + ListHead->Next.Next = Entry; + } + else + { + /* Traverse the list to find the last entry */ + CurrentEntry = ListHead->Next.Next; + while(CurrentEntry->Next != NULLPTR) + { + /* Move to the next entry */ + CurrentEntry = CurrentEntry->Next; + } + + /* Insert entry at the tail */ + CurrentEntry->Next = Entry; + } + + /* Increment list depth */ + ListHead->Depth++; +} + +/** + * Indicates whether a singly linked list structure is empty, or not initialized at all. + * + * @param ListHead + * Supplies a pointer to a structure that represents the head of the list. + * + * @return This routine returns TRUE if there are currently no entries in the list or FALSE otherwise. + * + * @since XT 1.0 + */ +XTCDECL +BOOLEAN +RTL::SinglyList::ListEmpty(IN PSINGLE_LIST_HEADER ListHead) +{ + /* Check if the list is empty */ + return (ListHead == NULLPTR || ListHead->Next.Next == NULLPTR); +} + +/** + * Queries the current depth (number of entries) of a singly linked list. + * + * @param ListHead + * Supplies a pointer to a structure that represents the head of the singly linked list. + * + * @return This routine returns the number of entries currently in the list, or zero if the list head is NULLPTR. + * + * @since XT 1.0 + */ +XTAPI +USHORT +RTL::SinglyList::QueryListDepth(IN PSINGLE_LIST_HEADER ListHead) +{ + /* Check if the list head is initialized and valid */ + if(ListHead == NULLPTR) + { + /* Return zero */ + return 0; + } + + /* Return the list depth */ + return ListHead->Depth; +} + +/** + * Removes an entry from a singly linked list. + * + * @param ListHead + * Supplies a pointer to the head of the list. + * + * @param Entry + * Supplies a pointer to the entry that will be removed from the list. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTCDECL +VOID +RTL::SinglyList::RemoveEntryList(IN PSINGLE_LIST_HEADER ListHead, + IN PSINGLE_LIST_ENTRY Entry) +{ + PSINGLE_LIST_ENTRY PreviousEntry; + + /* Check if the list is empty */ + if(ListEmpty(ListHead)) + { + /* List is empty, nothing to remove */ + return; + } + + /* Check if the entry is the first one */ + if(ListHead->Next.Next == Entry) + { + /* Remove the first entry and decrement depth */ + ListHead->Next.Next = Entry->Next; + ListHead->Depth--; + + /* Nothing else to do */ + return; + } + + /* Find the previous entry */ + PreviousEntry = ListHead->Next.Next; + while(PreviousEntry->Next != Entry) + { + /* Move to the next entry */ + PreviousEntry = PreviousEntry->Next; + + /* Check if we reached the end of the list */ + if(PreviousEntry == NULLPTR) + { + /* Entry not found */ + return; + } + } + + /* Remove the entry and decrement depth */ + PreviousEntry->Next = Entry->Next; + ListHead->Depth--; +} + +/** + * Splices a singly linked list at the head of another list. The source list is reinitialized to empty. + * + * @param ListHead + * Supplies a pointer to a structure that represents the head of the list. + * + * @param SpliceList + * Supplies a pointer to a structure that represents the head of the list that will be spliced. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTCDECL +VOID +RTL::SinglyList::SpliceHeadList(IN OUT PSINGLE_LIST_HEADER ListHead, + IN OUT PSINGLE_LIST_HEADER SpliceList) +{ + PSINGLE_LIST_ENTRY LastEntry; + + /* Check if the list to splice is empty */ + if(ListEmpty(SpliceList)) + { + /* Nothing to splice, return */ + return; + } + + /* Find the last entry of the list to splice */ + LastEntry = SpliceList->Next.Next; + while(LastEntry->Next != NULLPTR) + { + /* Move to the next entry */ + LastEntry = LastEntry->Next; + } + + /* Splice the list at the head of destination */ + LastEntry->Next = ListHead->Next.Next; + ListHead->Next.Next = SpliceList->Next.Next; + + /* Update depth of the destination list */ + ListHead->Depth += SpliceList->Depth; + + /* Reinitialize the source list to empty */ + SpliceList->Next.Next = NULLPTR; + SpliceList->Depth = 0; +} + +/** + * Splices a singly linked list at the tail of another list. The source list is reinitialized to empty. + * + * @param ListHead + * Supplies a pointer to the head of the destination list. + * + * @param SpliceList + * Supplies a pointer to the head of the list that will be spliced. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTCDECL +VOID +RTL::SinglyList::SpliceTailList(IN OUT PSINGLE_LIST_HEADER ListHead, + IN OUT PSINGLE_LIST_HEADER SpliceList) +{ + PSINGLE_LIST_ENTRY LastEntry; + + /* Check if the list to splice is empty */ + if(ListEmpty(SpliceList)) + { + /* Nothing to splice, return */ + return; + } + + /* Check if the destination list is empty */ + if(ListHead->Next.Next == NULLPTR) + { + /* Simply move the splice list to the destination head */ + ListHead->Next.Next = SpliceList->Next.Next; + } + else + { + /* Find the last entry of the destination list */ + LastEntry = ListHead->Next.Next; + while(LastEntry->Next != NULLPTR) + { + /* Move to the next entry */ + LastEntry = LastEntry->Next; + } + + /* Splice the list at the tail of destination */ + LastEntry->Next = SpliceList->Next.Next; + } + + /* Update depth of the destination list */ + ListHead->Depth += SpliceList->Depth; + + /* Reinitialize the source list to empty */ + SpliceList->Next.Next = NULLPTR; + SpliceList->Depth = 0; +}