Security and Cryptography
Go puts the crypto in the standard library, so the question is never which library but which call: crypto/rand over math/rand, subtle over ==, and a tls.Config you mostly leave alone.
part ofGo (Golang)overview, primer and where to startread it →on this pageshowhide
explore
- Standard Library Primitives30 questions
- Key Derivation5 questions
- Randomness and Token Generation4 questions
- FIPS 140-3 Mode4 questions
- Hashing and HMAC4 questions
- Constant-Time Comparison4 questions
- AEAD Encryption and Nonces4 questions
- Ed25519 and crypto.Signer5 questions
- Identity and Credentials18 questions
- Certificates and x509 Chains4 questions
- Issuing Certificates5 questions
- Rotating Keys Without Downtime4 questions
- Secrets in Memory5 questions
- TLS Configuration18 questions
- Post-Quantum Key Exchange5 questions
- Serving and Dialing5 questions
- Verification and Trust Roots4 questions
- Mutual Authentication4 questions
- Dependency Risk14 questions
- Advisories and Reachability5 questions
- Checksum Database Trust4 questions
- Vetting a New Import5 questions
questions
80 · 4 sectionsHow do you build an AES-GCM cipher.AEAD in Go and encrypt one message with it?
basics
~10 sPass the key to aes.NewCipher to get a cipher.Block, wrap that block with cipher.NewGCM to get a cipher.AEAD, then call Seal(dst, nonce, plaintext, additionalData). Seal returns the ciphertext with a 16-byte authentication tag appended.
What does Go's hmac.Equal do that bytes.Equal does not, and what does it return?
basics
~20 shmac.Equal(mac1, mac2 []byte) returns a bool and scans every byte, so its running time does not depend on the contents. bytes.Equal stops at the first differing byte, so its timing reveals how much of the input matched.
What is the difference between sha256.Sum256 and sha256.New, and when do you use each?
basics
~20 ssha256.Sum256 hashes a byte slice you already hold and returns a [32]byte array. sha256.New returns a streaming hash.Hash you write data into and finish with Sum(nil) - use that when the input is a file or stream too large to buffer.
How do you use `hkdf.Key` in Go to turn one master secret into a separate key per purpose?
basics
~10 sCall hkdf.Key once per purpose with a different info string each time, for example "cookie-encryption-v1" versus "url-signing-v1". Same secret, same salt, different info, and you get independent keys you never have to store.
Why is math/rand/v2 unsafe for generating a password-reset token in Go, and what do you use instead?
basics
~20 smath/rand/v2 is a statistical generator that makes no unpredictability promise, so its output can be reconstructed no matter how it is seeded. Use crypto/rand instead: rand.Text() for a token string, or crypto/rand.Read to fill a byte slice.
What does x509.CreateCertificate return in Go, and what must you do before writing a .crt file?
basics
~10 sx509.CreateCertificate returns the signed certificate as raw DER bytes, not a file and not text. To get a .crt or .pem file, wrap those bytes with encoding/pem in a block whose Type is CERTIFICATE.
In Go, how do you tell an unset environment variable from one set to an empty string when loading a credential?
basics
~20 sos.Getenv returns an empty string for both cases, so it cannot tell them apart. os.LookupEnv returns the value plus a boolean that is false only when the variable is absent, letting you fail startup instead of running with an empty credential.
In Go, how do you turn the bytes of a PEM certificate file into an *x509.Certificate?
basics
~10 sCall pem.Decode on the file bytes, check the returned block is non-nil and its Type is CERTIFICATE, then pass block.Bytes, which is the DER, to x509.ParseCertificate. Both steps can fail; check both.
Why must a certificate you issue in Go set DNSNames rather than only Subject.CommonName?
basics
~20 sHostname checking reads the Subject Alternative Name extension, which the template fills from DNSNames, IPAddresses, URIs and EmailAddresses. Go's verifier stopped matching Subject.CommonName in Go 1.15, so a certificate carrying the hostname only in CommonName is rejected.
A Go reload goroutine assigns a new *tls.Certificate that GetCertificate reads — why does -race flag it?
basics
~20 sTwo goroutines touch one variable with no synchronisation: the reloader writes the pointer while handshake goroutines read it. A pointer-sized write is not automatically ordered in Go. Keep the certificate in an atomic.Pointer and Load it inside the callback.
How do you serve HTTPS from a Go net/http server, and where does a tls.Config go?
basics
~20 sCall ListenAndServeTLS with a certificate file and a key file. The package-level http.ListenAndServeTLS takes no tls.Config, so to set TLS options you build an http.Server, fill its TLSConfig field, and call that server's ListenAndServeTLS method.
Which tls.Config fields make a Go TLS server require and verify a client certificate?
basics
~10 sTwo fields on the server's tls.Config: ClientCAs, an x509.CertPool of the CAs you trust to issue client certificates, and ClientAuth set to tls.RequireAndVerifyClientCert. ClientCAs alone asks for nothing and verifies nothing.
What does tls.Config.InsecureSkipVerify = true actually turn off in a Go TLS client?
basics
~20 sIt turns off both checks a Go TLS client makes on the peer's certificate: the chain is no longer verified against any trust root, and the name in the certificate is no longer matched. Any certificate from anyone is accepted.
Since Go 1.24, which key exchange does crypto/tls prefer by default, and why is it a hybrid?
basics
~10 sGo 1.24 made X25519MLKEM768 the preferred TLS 1.3 key exchange whenever tls.Config.CurvePreferences is left nil. It is hybrid: classical X25519 runs alongside post-quantum ML-KEM-768, so the session key holds if either half survives.
What does tls.Config.MinVersion control, and what applies when you leave it at zero?
basics
~20 stls.Config.MinVersion is the oldest TLS protocol version Go will negotiate; older peers are refused during the handshake. Zero means the crypto/tls package default, TLS 1.2 in current Go. Set it explicitly, because that default has been raised across releases.
What does the Go checksum database at sum.golang.org guarantee that go.sum alone cannot?
basics
~20 sgo.sum only pins the bytes your machine saw first, so a poisoned first download is pinned faithfully forever. The checksum database is a global append-only log of module hashes that the go command consults before writing a new go.sum line.
What can a Go dependency's init functions and package-level variables do to every binary that imports it?
basics
~20 sAnything. Package-level variable initializers and every init function in an imported package run before main, in every binary that pulls the package in, directly or transitively. You cannot import a package and skip them, so whatever they do is imposed on your program.
Why does Go's symbol-level vulnerability analysis report fewer findings than a go.mod manifest scan?
basics
~20 sBecause it matches called symbols, not module versions. Go's analysis builds a static call graph and reports an advisory only when a path in your program reaches one of the vulnerable functions. A manifest scan flags every affected version you require.
What does `go mod verify` actually check, and what does a passing result not prove?
basics
~20 sgo mod verify recomputes hashes of the dependencies in your local module cache and compares them with the hashes recorded at download time. It proves nobody edited the cache since; it does not re-download, contact the checksum database, or find vulnerabilities.
Which go command shows why a module you never required is in your build, and what does it print?
basics
~20 sgo mod why -m <module> prints the shortest chain of package imports leading from your main module to that module. If nothing in your build imports it, the command reports that the main module does not need it.