The right way to authenticate a message with a secret key is HMAC, which wraps your hash in two keyed passes to sidestep length extension. Today you build HMAC-SHA256 and match an official RFC 4231 vector.
Build HMAC-SHA256 on top of your hash and match a published test vector.
HMAC is the standard way to turn a hash into a keyed message authentication
code - a tag that proves a message came from someone who knows the secret key.
It exists because, as the last lesson showed, Sum256(key || message) is broken by
length extension. HMAC’s fix is to hash twice with two different key-derived
pads: an inner hash of (key XOR ipad) || message, then an outer hash of
(key XOR opad) || inner. The extra outer pass means the attacker never sees a
hash state they can extend.
The mechanics: the key is first sized to the 64-byte block - zero-padded on the
right if short, or replaced by its own Sum256 if longer than 64 bytes - then
XORed with the two fixed constants ipad (0x36 repeated) and opad (0x5c
repeated). Everything else is just your existing Sum256, called twice. Pin RFC
4231’s test case 2 (key = "Jefe", message "what do ya want for nothing?"),
whose tag is 5bdcc146...64ec3843. HMAC is what real systems use for signed
cookies, API request signing, and key derivation - all built on the hash you wrote.
// key shorter than 64 bytes is zero-padded on the right to 64 bytes// (a key longer than 64 bytes would first be replaced by Sum256(key))func HMAC(key, msg []byte) [32]uint8 {k := make([]byte, 64)copy(k, key)ipad := xorConst(k, 0x36) // each of the 64 bytes XOR 0x36opad := xorConst(k, 0x5c)inner := Sum256(append(ipad, msg...))return Sum256(append(opad, inner[:]...))}