Senior · Go service security
A fast hash is proposed for password storage
A team wants one SHA-256 helper for password storage, signed messages and encryption. Which requirements are being collapsed?
Try explaining this aloud before opening the answer. State your assumptions and trace a boundary case.
package main
import (
"crypto/hmac"
"crypto/rand"
"crypto/sha256"
"fmt"
)
func tag(key, message []byte) []byte {
m := hmac.New(sha256.New, key)
_, _ = m.Write(message)
return m.Sum(nil)
}
func main() {
key := make([]byte, 32)
if _, err := rand.Read(key); err != nil {
panic(err)
}
message := []byte("action=read;resource=7")
expected := tag(key, message)
fmt.Println(hmac.Equal(expected, tag(key, message))) // true
fmt.Println(hmac.Equal(expected, tag(key, []byte("action=write;resource=7")))) // false
// Never print key material; a MAC does not hide the message.
}Reveal a strong answer
A fast hash, password hash, MAC, encryption scheme and digital signature answer different questions. A SHA-256 digest does not make a password database resistant to guessing, and encryption without authentication can accept altered ciphertext. Use reviewed libraries and document the purpose, key lifetime, input format and resource budget before selecting a primitive.
Use an appropriate reviewed password KDF such as Argon2id where your policy permits it, with random salt and stored algorithm/version/cost parameters. Benchmark memory and CPU cost under concurrent login load and bound admission; expensive verification is also a denial-of-service surface. For secret encryption prefer a reviewed authenticated construction and a key/nonce management design instead of assembling low-level primitives. The secret key comes from crypto/rand rather than a predictable simulation PRNG. HMAC authenticates these exact bytes and hmac.Equal performs the intended tag comparison. This example has no expiry, replay store or message canonicalization policy, so it is not by itself a complete access-token protocol.
Do not use math/rand for secrets, a fast unsalted digest for password storage, or a plain equality loop for secret MAC tags. Do not copy one parameter value forever from a tutorial. Test corrupted tags, wrong keys, duplicate/replayed messages, unsupported KDF parameters and resource exhaustion. Keep production keys outside code and logs, and define rotation and recovery procedures.
Common trap
A cryptographic algorithm name is not a complete protocol, storage or resource-management design.
Try it
Assign password KDF, MAC, authenticated encryption and signature roles, then identify randomness, key, replay and admission budgets.
Worked solution
These primitives have different purposes. Password storage needs a reviewed slow, memory-aware KDF policy with salt and stored parameters; a MAC authenticates bytes with a secret key; encryption needs confidentiality and authentication; signatures have a separate trust model. Use crypto/rand for secret material, constant-time tag verification APIs where intended and explicit key lifecycle. Bound expensive password verification under concurrent load and test hostile parameter/input cases.
Change the constraint
How can an expensive password KDF itself become a denial-of-service surface?
How did you do?
Self-assessment, not a compiler pass or interview score. Explain the reasoning unaided before marking understood.
Not marked. Progress stays on this browser, separate from course completion.
Primary references
Checked 2026-10-28. Use documentation for your pinned runtime, driver and tool version.