123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495 |
- /*++
- Copyright (c) 2015 Minoca Corp. All Rights Reserved
- Module Name:
- md5.c
- Abstract:
- This module implements the MD5 hash routine.
- Author:
- Evan Green 14-Jan-2015
- Environment:
- Kernel
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include "cryptop.h"
- //
- // --------------------------------------------------------------------- Macros
- //
- //
- // Define F, G, H, and I, the basic MD5 functions.
- //
- #define MD5_F(_ValueX, _ValueY, _ValueZ) \
- (((_ValueX) & (_ValueY)) | ((~_ValueX) & (_ValueZ)))
- #define MD5_G(_ValueX, _ValueY, _ValueZ) \
- (((_ValueX) & (_ValueZ)) | ((_ValueY) & (~_ValueZ)))
- #define MD5_H(_ValueX, _ValueY, _ValueZ) \
- ((_ValueX) ^ (_ValueY) ^ (_ValueZ))
- #define MD5_I(_ValueX, _ValueY, _ValueZ) \
- ((_ValueY) ^ ((_ValueX) | (~_ValueZ)))
- #define MD5_ROTATE_LEFT(_Value, _Count) \
- (((_Value) << (_Count)) | ((_Value) >> (32 - (_Count))))
- //
- // Define FF, GG, HH, and II transformations for rounds 1 through 4.
- //
- #define MD5_FF(_ValueA, _ValueB, _ValueC, _ValueD, _ValueX, _Shift, _ValueAc) \
- (_ValueA) += MD5_F((_ValueB), (_ValueC), (_ValueD)) + (_ValueX) + \
- (ULONG)(_ValueAc); \
- (_ValueA) = MD5_ROTATE_LEFT((_ValueA), (_Shift)); \
- (_ValueA) += (_ValueB);
- #define MD5_GG(_ValueA, _ValueB, _ValueC, _ValueD, _ValueX, _Shift, _ValueAc) \
- (_ValueA) += MD5_G((_ValueB), (_ValueC), (_ValueD)) + (_ValueX) + \
- (ULONG)(_ValueAc); \
- (_ValueA) = MD5_ROTATE_LEFT((_ValueA), (_Shift)); \
- (_ValueA) += (_ValueB);
- #define MD5_HH(_ValueA, _ValueB, _ValueC, _ValueD, _ValueX, _Shift, _ValueAc) \
- (_ValueA) += MD5_H((_ValueB), (_ValueC), (_ValueD)) + (_ValueX) + \
- (ULONG)(_ValueAc); \
- (_ValueA) = MD5_ROTATE_LEFT((_ValueA), (_Shift)); \
- (_ValueA) += (_ValueB);
- #define MD5_II(_ValueA, _ValueB, _ValueC, _ValueD, _ValueX, _Shift, _ValueAc) \
- (_ValueA) += MD5_I((_ValueB), (_ValueC), (_ValueD)) + (_ValueX) + \
- (ULONG)(_ValueAc); \
- (_ValueA) = MD5_ROTATE_LEFT((_ValueA), (_Shift)); \
- (_ValueA) += (_ValueB);
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // Define constants for the MD5 transform routine.
- //
- #define MD5_S11 7
- #define MD5_S12 12
- #define MD5_S13 17
- #define MD5_S14 22
- #define MD5_S21 5
- #define MD5_S22 9
- #define MD5_S23 14
- #define MD5_S24 20
- #define MD5_S31 4
- #define MD5_S32 11
- #define MD5_S33 16
- #define MD5_S34 23
- #define MD5_S41 6
- #define MD5_S42 10
- #define MD5_S43 15
- #define MD5_S44 21
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- VOID
- CypMd5ProcessMessage (
- PMD5_CONTEXT Context,
- UCHAR Block[MD5_BLOCK_SIZE]
- );
- VOID
- CypMd5PadMessage (
- PMD5_CONTEXT Context
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // ------------------------------------------------------------------ Functions
- //
- CRYPTO_API
- VOID
- CyMd5Initialize (
- PMD5_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine initializes a MD5 context structure, preparing it to accept
- and hash data.
- Arguments:
- Context - Supplies a pointer to the context to initialize.
- Return Value:
- None.
- --*/
- {
- Context->Length = 0;
- Context->State[0] = 0x67452301;
- Context->State[1] = 0xEFCDAB89;
- Context->State[2] = 0x98BADCFE;
- Context->State[3] = 0x10325476;
- return;
- }
- CRYPTO_API
- VOID
- CyMd5AddContent (
- PMD5_CONTEXT Context,
- PVOID Message,
- UINTN Length
- )
- /*++
- Routine Description:
- This routine adds data to a MD5 digest.
- Arguments:
- Context - Supplies a pointer to the initialized MD5 context.
- Message - Supplies a pointer to the buffer containing the bytes.
- Length - Supplies the length of the message buffer, in bytes.
- Return Value:
- None.
- --*/
- {
- PUCHAR Bytes;
- UINTN CurrentBlockBytes;
- UINTN Index;
- UINTN PartialSize;
- Bytes = Message;
- //
- // Figure out how many bytes are already in the block.
- //
- CurrentBlockBytes = (Context->Length / BITS_PER_BYTE) % MD5_BLOCK_SIZE;
- //
- // Update the length (in bits).
- //
- Context->Length += Length * BITS_PER_BYTE;
- PartialSize = MD5_BLOCK_SIZE - CurrentBlockBytes;
- if (Length >= PartialSize) {
- RtlCopyMemory(&(Context->MessageBlock[CurrentBlockBytes]),
- Bytes,
- PartialSize);
- CypMd5ProcessMessage(Context, Context->MessageBlock);
- //
- // Transform the other complete messages without copying.
- //
- for (Index = PartialSize;
- Index + MD5_BLOCK_SIZE - 1 < Length;
- Index += MD5_BLOCK_SIZE) {
- CypMd5ProcessMessage(Context, &(Bytes[Index]));
- }
- CurrentBlockBytes = 0;
- } else {
- Index = 0;
- }
- //
- // Copy the partial block to the working.
- //
- ASSERT(Length - Index + CurrentBlockBytes <= MD5_BLOCK_SIZE);
- if (Length - Index != 0) {
- RtlCopyMemory(&(Context->MessageBlock[CurrentBlockBytes]),
- &(Bytes[Index]),
- Length - Index);
- }
- return;
- }
- CRYPTO_API
- VOID
- CyMd5GetHash (
- PMD5_CONTEXT Context,
- UCHAR Hash[MD5_HASH_SIZE]
- )
- /*++
- Routine Description:
- This routine computes and returns the final MD5 hash value for the messages
- that have been previously entered.
- Arguments:
- Context - Supplies a pointer to the initialized MD5 context.
- Hash - Supplies a pointer where the final hash value will be returned. This
- buffer must be MD5_HASH_SIZE length in bytes.
- Return Value:
- None.
- --*/
- {
- CypMd5PadMessage(Context);
- RtlCopyMemory(Hash, Context->State, MD5_HASH_SIZE);
- return;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- VOID
- CypMd5ProcessMessage (
- PMD5_CONTEXT Context,
- UCHAR Block[MD5_BLOCK_SIZE]
- )
- /*++
- Routine Description:
- This routine processes the 512 bits in the current message block and adds
- them to the digest.
- Arguments:
- Context - Supplies a pointer to the initialized MD5 context with a full
- message block.
- Block - Supplies a pointer to the block to digest.
- Return Value:
- None.
- --*/
- {
- ULONG ValueA;
- ULONG ValueB;
- ULONG ValueC;
- ULONG ValueD;
- ULONG Working[MD5_HASH_SIZE];
- ASSERT(sizeof(Working) == MD5_BLOCK_SIZE);
- ValueA = Context->State[0];
- ValueB = Context->State[1];
- ValueC = Context->State[2];
- ValueD = Context->State[3];
- RtlCopyMemory(Working, Block, MD5_BLOCK_SIZE);
- //
- // Perform round 1.
- //
- MD5_FF(ValueA, ValueB, ValueC, ValueD, Working[0], MD5_S11, 0xD76AA478);
- MD5_FF(ValueD, ValueA, ValueB, ValueC, Working[1], MD5_S12, 0xE8C7B756);
- MD5_FF(ValueC, ValueD, ValueA, ValueB, Working[2], MD5_S13, 0x242070DB);
- MD5_FF(ValueB, ValueC, ValueD, ValueA, Working[3], MD5_S14, 0xC1BDCEEE);
- MD5_FF(ValueA, ValueB, ValueC, ValueD, Working[4], MD5_S11, 0xF57C0FAF);
- MD5_FF(ValueD, ValueA, ValueB, ValueC, Working[5], MD5_S12, 0x4787C62A);
- MD5_FF(ValueC, ValueD, ValueA, ValueB, Working[6], MD5_S13, 0xA8304613);
- MD5_FF(ValueB, ValueC, ValueD, ValueA, Working[7], MD5_S14, 0xFD469501);
- MD5_FF(ValueA, ValueB, ValueC, ValueD, Working[8], MD5_S11, 0x698098D8);
- MD5_FF(ValueD, ValueA, ValueB, ValueC, Working[9], MD5_S12, 0x8B44F7AF);
- MD5_FF(ValueC, ValueD, ValueA, ValueB, Working[10], MD5_S13, 0xFFFF5BB1);
- MD5_FF(ValueB, ValueC, ValueD, ValueA, Working[11], MD5_S14, 0x895CD7BE);
- MD5_FF(ValueA, ValueB, ValueC, ValueD, Working[12], MD5_S11, 0x6B901122);
- MD5_FF(ValueD, ValueA, ValueB, ValueC, Working[13], MD5_S12, 0xFD987193);
- MD5_FF(ValueC, ValueD, ValueA, ValueB, Working[14], MD5_S13, 0xA679438E);
- MD5_FF(ValueB, ValueC, ValueD, ValueA, Working[15], MD5_S14, 0x49B40821);
- //
- // Perform round 2.
- //
- MD5_GG(ValueA, ValueB, ValueC, ValueD, Working[1], MD5_S21, 0xF61E2562);
- MD5_GG(ValueD, ValueA, ValueB, ValueC, Working[6], MD5_S22, 0xC040B340);
- MD5_GG(ValueC, ValueD, ValueA, ValueB, Working[11], MD5_S23, 0x265E5A51);
- MD5_GG(ValueB, ValueC, ValueD, ValueA, Working[0], MD5_S24, 0xE9B6C7AA);
- MD5_GG(ValueA, ValueB, ValueC, ValueD, Working[5], MD5_S21, 0xD62F105D);
- MD5_GG(ValueD, ValueA, ValueB, ValueC, Working[10], MD5_S22, 0x02441453);
- MD5_GG(ValueC, ValueD, ValueA, ValueB, Working[15], MD5_S23, 0xD8A1E681);
- MD5_GG(ValueB, ValueC, ValueD, ValueA, Working[4], MD5_S24, 0xE7D3FBC8);
- MD5_GG(ValueA, ValueB, ValueC, ValueD, Working[9], MD5_S21, 0x21E1CDE6);
- MD5_GG(ValueD, ValueA, ValueB, ValueC, Working[14], MD5_S22, 0xC33707D6);
- MD5_GG(ValueC, ValueD, ValueA, ValueB, Working[3], MD5_S23, 0xF4D50D87);
- MD5_GG(ValueB, ValueC, ValueD, ValueA, Working[8], MD5_S24, 0x455A14ED);
- MD5_GG(ValueA, ValueB, ValueC, ValueD, Working[13], MD5_S21, 0xA9E3E905);
- MD5_GG(ValueD, ValueA, ValueB, ValueC, Working[2], MD5_S22, 0xFCEFA3F8);
- MD5_GG(ValueC, ValueD, ValueA, ValueB, Working[7], MD5_S23, 0x676F02D9);
- MD5_GG(ValueB, ValueC, ValueD, ValueA, Working[12], MD5_S24, 0x8D2A4C8A);
- //
- // Perform round 3.
- //
- MD5_HH(ValueA, ValueB, ValueC, ValueD, Working[5], MD5_S31, 0xFFFA3942);
- MD5_HH(ValueD, ValueA, ValueB, ValueC, Working[8], MD5_S32, 0x8771F681);
- MD5_HH(ValueC, ValueD, ValueA, ValueB, Working[11], MD5_S33, 0x6D9D6122);
- MD5_HH(ValueB, ValueC, ValueD, ValueA, Working[14], MD5_S34, 0xFDE5380C);
- MD5_HH(ValueA, ValueB, ValueC, ValueD, Working[1], MD5_S31, 0xA4BEEA44);
- MD5_HH(ValueD, ValueA, ValueB, ValueC, Working[4], MD5_S32, 0x4BDECFA9);
- MD5_HH(ValueC, ValueD, ValueA, ValueB, Working[7], MD5_S33, 0xF6BB4B60);
- MD5_HH(ValueB, ValueC, ValueD, ValueA, Working[10], MD5_S34, 0xBEBFBC70);
- MD5_HH(ValueA, ValueB, ValueC, ValueD, Working[13], MD5_S31, 0x289B7EC6);
- MD5_HH(ValueD, ValueA, ValueB, ValueC, Working[0], MD5_S32, 0xEAA127FA);
- MD5_HH(ValueC, ValueD, ValueA, ValueB, Working[3], MD5_S33, 0xD4EF3085);
- MD5_HH(ValueB, ValueC, ValueD, ValueA, Working[6], MD5_S34, 0x04881D05);
- MD5_HH(ValueA, ValueB, ValueC, ValueD, Working[9], MD5_S31, 0xD9D4D039);
- MD5_HH(ValueD, ValueA, ValueB, ValueC, Working[12], MD5_S32, 0xE6DB99E5);
- MD5_HH(ValueC, ValueD, ValueA, ValueB, Working[15], MD5_S33, 0x1FA27CF8);
- MD5_HH(ValueB, ValueC, ValueD, ValueA, Working[2], MD5_S34, 0xC4AC5665);
- //
- // Perform round 4.
- //
- MD5_II(ValueA, ValueB, ValueC, ValueD, Working[0], MD5_S41, 0xF4292244);
- MD5_II(ValueD, ValueA, ValueB, ValueC, Working[7], MD5_S42, 0x432AFF97);
- MD5_II(ValueC, ValueD, ValueA, ValueB, Working[14], MD5_S43, 0xAB9423A7);
- MD5_II(ValueB, ValueC, ValueD, ValueA, Working[5], MD5_S44, 0xFC93A039);
- MD5_II(ValueA, ValueB, ValueC, ValueD, Working[12], MD5_S41, 0x655B59C3);
- MD5_II(ValueD, ValueA, ValueB, ValueC, Working[3], MD5_S42, 0x8F0CCC92);
- MD5_II(ValueC, ValueD, ValueA, ValueB, Working[10], MD5_S43, 0xFFEFF47D);
- MD5_II(ValueB, ValueC, ValueD, ValueA, Working[1], MD5_S44, 0x85845DD1);
- MD5_II(ValueA, ValueB, ValueC, ValueD, Working[8], MD5_S41, 0x6FA87E4F);
- MD5_II(ValueD, ValueA, ValueB, ValueC, Working[15], MD5_S42, 0xFE2CE6E0);
- MD5_II(ValueC, ValueD, ValueA, ValueB, Working[6], MD5_S43, 0xA3014314);
- MD5_II(ValueB, ValueC, ValueD, ValueA, Working[13], MD5_S44, 0x4E0811A1);
- MD5_II(ValueA, ValueB, ValueC, ValueD, Working[4], MD5_S41, 0xF7537E82);
- MD5_II(ValueD, ValueA, ValueB, ValueC, Working[11], MD5_S42, 0xBD3AF235);
- MD5_II(ValueC, ValueD, ValueA, ValueB, Working[2], MD5_S43, 0x2AD7D2BB);
- MD5_II(ValueB, ValueC, ValueD, ValueA, Working[9], MD5_S44, 0xEB86D391);
- Context->State[0] += ValueA;
- Context->State[1] += ValueB;
- Context->State[2] += ValueC;
- Context->State[3] += ValueD;
- return;
- }
- VOID
- CypMd5PadMessage (
- PMD5_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine pads the message out to an even multiple of 512 bits.
- The standard specifies that the first padding bit must be a 1, and then the
- last 64 bits represent the length of the original message.
- Arguments:
- Context - Supplies a pointer to the initialized MD5 context.
- Return Value:
- None.
- --*/
- {
- UINTN Index;
- //
- // Check to see if the current message block is too small to hold the
- // initial padding bits and length. If so, process the block, then continue
- // padding onto a second block.
- //
- Index = (Context->Length / BITS_PER_BYTE) % MD5_BLOCK_SIZE;
- if (Index < 56) {
- Context->MessageBlock[Index] = 0x80;
- Index += 1;
- while (Index < 56) {
- Context->MessageBlock[Index] = 0;
- Index += 1;
- }
- } else {
- Context->MessageBlock[Index] = 0x80;
- Index += 1;
- while (Index < sizeof(Context->MessageBlock)) {
- Context->MessageBlock[Index] = 0;
- Index += 1;
- }
- CypMd5ProcessMessage(Context, Context->MessageBlock);
- RtlZeroMemory(Context->MessageBlock, 56);
- }
- //
- // Store the message length in the last 8 octets.
- //
- Context->MessageBlock[56] = (UCHAR)(Context->Length);
- Context->MessageBlock[57] = (UCHAR)(Context->Length >> 8);
- Context->MessageBlock[58] = (UCHAR)(Context->Length >> 16);
- Context->MessageBlock[59] = (UCHAR)(Context->Length >> 24);
- Context->MessageBlock[60] = (UCHAR)(Context->Length >> 32);
- Context->MessageBlock[61] = (UCHAR)(Context->Length >> (32 + 8));
- Context->MessageBlock[62] = (UCHAR)(Context->Length >> (32 + 16));
- Context->MessageBlock[63] = (UCHAR)(Context->Length >> (32 + 24));
- CypMd5ProcessMessage(Context, Context->MessageBlock);
- return;
- }
|