SHA256 Hashes
crypto/sha256 for one-shot and streaming SHA-256 hashing, hex encoding the digest, and when not to use SHA256 for passwords.
The crypto/sha256 package computes SHA-256 digests. Use sha256.Sum256 for small byte slices; use sha256.New() with io.Copy for large files or streams.
sha256.Sum256 hashes a byte slice in one call and returns a [32]byte array. hex.EncodeToString converts the raw bytes to a lowercase hex string - the common representation for checksums and content hashes.
package main
import (
"crypto/sha256"
"encoding/hex"
"fmt"
)
func main() {
data := []byte("hello, world")
digest := sha256.Sum256(data)
fmt.Printf("bytes: %x\n", digest)
fmt.Println("hex: ", hex.EncodeToString(digest[:]))
}For large inputs, use sha256.New() to get a hash.Hash and write data incrementally. This avoids loading the entire content into memory and works with any io.Reader.
package main
import (
"crypto/sha256"
"encoding/hex"
"fmt"
"strings"
)
func main() {
h := sha256.New()
// Write data in chunks (simulated here with a Reader)
r := strings.NewReader("hello, world - this could be a large file")
buf := make([]byte, 8)
for {
n, err := r.Read(buf)
if n > 0 {
h.Write(buf[:n])
}
if err != nil {
break
}
}
fmt.Println(hex.EncodeToString(h.Sum(nil)))
}h.Sum(nil) appends the current digest to a nil slice, returning a fresh []byte. You can also call h.Sum(existing[:0]) to write into a pre-allocated buffer without an allocation.
package main
import (
"crypto/sha256"
"fmt"
"io"
"os"
)
func hashFile(path string) ([]byte, error) {
f, err := os.Open(path)
if err != nil {
return nil, err
}
defer f.Close()
h := sha256.New()
if _, err := io.Copy(h, f); err != nil {
return nil, err
}
return h.Sum(nil), nil
}
func main() {
digest, err := hashFile("go.sum")
if err != nil {
fmt.Println("open go.sum:", err)
return
}
fmt.Printf("%x\n", digest)
}In production
sha256.Sum256 hashes a byte slice in one call - convenient for small inputs, but it loads the entire content into memory. For files, use sha256.New() + io.Copy so the file is streamed through the hasher. Never use SHA-256 for password storage: it is a general-purpose hash, not a key derivation function. Use bcrypt, argon2id, or scrypt for passwords - they are intentionally slow and include salting. SHA-256 is appropriate for content addressing (deduplication, checksums), HMAC signatures, and certificate fingerprints. When comparing digests in security-sensitive code, use subtle.ConstantTimeCompare from crypto/subtle to prevent timing attacks; a naive bytes.Equal or == can leak timing information.
Enjoyed this? Get more essays on software craft delivered to your inbox.
Subscribe free