-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
4263dac
commit fba7aba
Showing
2 changed files
with
160 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
// md5.go | ||
// description: The MD5 hashing function as defined in RFC 1321. | ||
// author: Simon Waldherr | ||
// ref: https://datatracker.ietf.org/doc/html/rfc1321 | ||
// see md5_test.go for testing | ||
|
||
package md5 | ||
|
||
import ( | ||
"encoding/binary" | ||
) | ||
|
||
// Constants for MD5 | ||
var ( | ||
s = [64]uint32{ | ||
7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, | ||
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, | ||
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, | ||
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, | ||
} | ||
|
||
K = [64]uint32{ | ||
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, | ||
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, | ||
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, | ||
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, | ||
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, | ||
0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, | ||
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, | ||
0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, | ||
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, | ||
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, | ||
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, | ||
0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, | ||
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, | ||
0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, | ||
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, | ||
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, | ||
} | ||
) | ||
|
||
// leftRotate rotates x left by n bits | ||
func leftRotate(x, n uint32) uint32 { | ||
return (x << n) | (x >> (32 - n)) | ||
} | ||
|
||
// pad pads the input message so that its length is congruent to 448 modulo 512 | ||
func pad(message []byte) []byte { | ||
originalLength := len(message) * 8 | ||
message = append(message, 0x80) | ||
for (len(message)*8)%512 != 448 { | ||
message = append(message, 0x00) | ||
} | ||
|
||
lengthBytes := make([]byte, 8) | ||
binary.LittleEndian.PutUint64(lengthBytes, uint64(originalLength)) | ||
message = append(message, lengthBytes...) | ||
|
||
return message | ||
} | ||
|
||
// Hash computes the MD5 hash of the input message | ||
func Hash(message []byte) [16]byte { | ||
message = pad(message) | ||
|
||
// Initialize MD5 state variables | ||
a0, b0, c0, d0 := uint32(0x67452301), uint32(0xefcdab89), uint32(0x98badcfe), uint32(0x10325476) | ||
|
||
// Process the message in successive 512-bit chunks | ||
for i := 0; i < len(message); i += 64 { | ||
chunk := message[i : i+64] | ||
var M [16]uint32 | ||
for j := 0; j < 16; j++ { | ||
M[j] = binary.LittleEndian.Uint32(chunk[j*4 : (j+1)*4]) | ||
} | ||
|
||
// Initialize hash value for this chunk | ||
A, B, C, D := a0, b0, c0, d0 | ||
|
||
// Main loop | ||
for i := 0; i < 64; i++ { | ||
var F, g uint32 | ||
if i < 16 { | ||
F = (B & C) | ((^B) & D) | ||
g = uint32(i) | ||
} else if i < 32 { | ||
F = (D & B) | ((^D) & C) | ||
g = uint32((5*i + 1) % 16) | ||
} else if i < 48 { | ||
F = B ^ C ^ D | ||
g = uint32((3*i + 5) % 16) | ||
} else { | ||
F = C ^ (B | (^D)) | ||
g = uint32((7 * i) % 16) | ||
} | ||
F = F + A + K[i] + M[g] | ||
A = D | ||
D = C | ||
C = B | ||
B = B + leftRotate(F, s[i]) | ||
} | ||
|
||
// Add this chunk's hash to result so far | ||
a0 += A | ||
b0 += B | ||
c0 += C | ||
d0 += D | ||
} | ||
|
||
// Produce the final hash value (digest) | ||
var digest [16]byte | ||
binary.LittleEndian.PutUint32(digest[0:4], a0) | ||
binary.LittleEndian.PutUint32(digest[4:8], b0) | ||
binary.LittleEndian.PutUint32(digest[8:12], c0) | ||
binary.LittleEndian.PutUint32(digest[12:16], d0) | ||
|
||
return digest | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
// md5_test.go | ||
// description: Tests for the MD5 hashing function as defined in RFC 1321. | ||
// author: Simon Waldherr | ||
|
||
package md5 | ||
|
||
import ( | ||
"encoding/hex" | ||
"testing" | ||
) | ||
|
||
// Helper function to convert hash output to hex string for comparison | ||
func toHexString(hash [16]byte) string { | ||
return hex.EncodeToString(hash[:]) | ||
} | ||
|
||
// Test vectors for MD5 (from RFC 1321 and other known sources) | ||
var tests = []struct { | ||
input string | ||
expected string | ||
}{ | ||
{"", "d41d8cd98f00b204e9800998ecf8427e"}, | ||
{"a", "0cc175b9c0f1b6a831c399e269772661"}, | ||
{"abc", "900150983cd24fb0d6963f7d28e17f72"}, | ||
{"message digest", "f96b697d7cb7938d525a2f31aaf161d0"}, | ||
{"abcdefghijklmnopqrstuvwxyz", "c3fcd3d76192e4007dfb496cca67e13b"}, | ||
{"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "d174ab98d277d9f5a5611c2c9f419d9f"}, | ||
{"12345678901234567890123456789012345678901234567890123456789012345678901234567890", "57edf4a22be3c955ac49da2e2107b67a"}, | ||
} | ||
|
||
// TestHash verifies that the Hash function produces the correct MD5 hash values | ||
func TestHash(t *testing.T) { | ||
for _, tt := range tests { | ||
t.Run(tt.input, func(t *testing.T) { | ||
result := Hash([]byte(tt.input)) | ||
resultHex := toHexString(result) | ||
if resultHex != tt.expected { | ||
t.Errorf("MD5(%q) = %s; want %s", tt.input, resultHex, tt.expected) | ||
} | ||
}) | ||
} | ||
} |