Start with the goal. Do you need to transport arbitrary bytes as text, detect accidental changes, authenticate bytes against a shared secret, or hide and authenticate a message? Those are different operations.
This course uses maintained Go primitives and a complete local record verifier. You need Go functions/errors, byte slices and basic trust-boundary reasoning. You will not implement a cipher, hash algorithm or password KDF from scratch.
Hex and Base64 encode bytes. Anyone can decode them. A SHA-256 digest is not normally reversible, but a party who changes a message can compute a fresh digest. It cannot prove origin when both values come from an untrusted source.
HMAC uses a secret to authenticate bytes. Anyone with that secret can create a valid tag. It does not identify an individual among key holders, prevent replay, or hide the message.
package main
import ("fmt";"encoding/base64")
func main(){
message:=[]byte("amount=10");encoded:=base64.StdEncoding.EncodeToString(message);decoded,_:=base64.StdEncoding.DecodeString(encoded);fmt.Println(string(decoded))
}Authenticated encryption such as AES-GCM combines confidentiality and integrity, including optional associated data that is authenticated but not encrypted. Its guarantees depend on correct key, nonce and message-count use. The later exercise uses Go’s random-nonce wrapper rather than accepting caller-supplied nonces.
Password storage is another goal. Low-entropy human passwords need an appropriate adaptive, salted KDF and tuned work policy. An ordinary fast hash or HMAC record tag is not a substitute.
The final record format provides shared-key integrity and context separation only. Its payload is Base64 and remains readable; freshness, user identity and replay prevention require additional application state or protocols.
package main
import ("fmt";"crypto/sha256";"encoding/hex")
func main(){
sum:=sha256.Sum256([]byte("amount=99"));fmt.Println(len(sum),hex.EncodeToString(sum[:])==hex.EncodeToString(sum[:]))
}Implement the guarantee table and explain one thing each primitive does not provide. Keep the low-level operation distinct from a complete security protocol.
Next we make byte encodings canonical and test binary round trips.