From 75e536df4ff4817067be642bbcb566321da2c4b5 Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Sun, 10 Nov 2024 22:23:46 -0500 Subject: [PATCH] Create more efficient MD2 implementation --- SabreTools.Hashing/MessageDigest/MD2.cs | 116 ++++++++++++++++-------- 1 file changed, 76 insertions(+), 40 deletions(-) diff --git a/SabreTools.Hashing/MessageDigest/MD2.cs b/SabreTools.Hashing/MessageDigest/MD2.cs index 1714526..5884ac7 100644 --- a/SabreTools.Hashing/MessageDigest/MD2.cs +++ b/SabreTools.Hashing/MessageDigest/MD2.cs @@ -4,7 +4,6 @@ using static SabreTools.Hashing.MessageDigest.Constants; namespace SabreTools.Hashing.MessageDigest { /// - /// Uses the inefficient reference implementation for now public class MD2 : MessageDigestBase { /// @@ -44,11 +43,70 @@ namespace SabreTools.Hashing.MessageDigest /// public override void TransformBlock(byte[] data, int offset, int length) { - // Loop and process all bytes sequentially - while (length > 0) + // If there is buffer to fill and it will meet the limit + if (_byteCount > 0 && _byteCount + length >= 16) { - Update(data[offset++]); - length--; + // Fill the buffer from the input + for (int i = 0; i < 16 - _byteCount; i++) + { + // Add new character to buffer + _digest[16 + _byteCount + i] = data[offset + i]; + _digest[32 + _byteCount + i] = (byte)(data[offset + i] ^ _digest[_byteCount + i]); + + // Update checksum register C and value L + _lastByte = _checksum[_byteCount] ^= MD2SBox[0xff & (data[offset + i] ^ _lastByte)]; + } + + // Set the new values + offset += 16 - _byteCount; + length -= 16 - _byteCount; + _byteCount = 0; + + // Run the update + Update(); + } + + /// Process any standalone blocks + while (length >= 16) + { + // Fill the buffer from the input + for (int i = 0; i < 16; i++) + { + // Add new character to buffer + _digest[16 + i] = data[offset + i]; + _digest[32 + i] = (byte)(data[offset + i] ^ _digest[i]); + + // Update checksum register C and value L + _lastByte = _checksum[i] ^= MD2SBox[0xff & (data[offset + i] ^ _lastByte)]; + } + + // Set the new values + offset += 16; + length -= 16; + _byteCount = 0; + + // Run the update + Update(); + } + + // Save the remainder in the buffer + if (length > 0) + { + // Fill the buffer from the input + for (int i = 0; i < length; i++) + { + // Add new character to buffer + _digest[16 + _byteCount] = data[offset]; + _digest[32 + _byteCount] = (byte)(data[offset] ^ _digest[i]); + + // Update checksum register C and value L + _lastByte = _checksum[_byteCount] ^= MD2SBox[0xff & (data[offset] ^ _lastByte)]; + + // Set the new values + offset++; + length--; + _byteCount = (byte)((_byteCount + 1) & 15); + } } } @@ -57,16 +115,12 @@ namespace SabreTools.Hashing.MessageDigest { // Determine the pad length byte padLength = (byte)(16 - _byteCount); - for (int i = 0; i < padLength; i++) - { - Update(padLength); - } - // Append the checksum - for (int i = 0; i < 16; i++) - { - Update(_checksum[i]); - } + // Pad the block + byte[] padding = new byte[padLength]; + Array.Fill(padding, padLength); + TransformBlock(padding, 0, padLength); + TransformBlock(_checksum, 0, _checksum.Length); } /// @@ -86,36 +140,18 @@ namespace SabreTools.Hashing.MessageDigest /// digest is being computed. This routine will be called for each /// message byte in turn. /// - private void Update(byte c) + /// The following is a more efficient version of the loop + private void Update() { - // TODO: The part from here until "Transform D if i = 0" - // can be moved into the main TransformBlock. All it's doing - // is ensuring that 16 bytes exist before it starts processing - - // Add new character to buffer - _digest[16 + _byteCount] = c; - _digest[32 + _byteCount] = (byte)(c ^ _digest[_byteCount]); - - // Update checksum register C and value L - _lastByte = _checksum[_byteCount] ^= MD2SBox[0xff & (c ^ _lastByte)]; - - // Increment i by one modulo 16 - _byteCount = (byte)((_byteCount + 1) & 15); - - // Transform D if i = 0 - if (_byteCount == 0) + byte t = 0; + for (byte j = 0; j < 18; j++) { - byte t = 0; - for (byte j = 0; j < 18; j++) + for (byte i = 0; i < 48; i++) { - // The following is a more efficient version of the loop - for (byte i = 0; i < 48; i++) - { - t = _digest[i] = (byte)(_digest[i] ^ MD2SBox[t]); - } - - t += j; + t = _digest[i] = (byte)(_digest[i] ^ MD2SBox[t]); } + + t += j; } } }