Crypto recipe
Hashing with SHA-256
Compute a SHA-256 digest for integrity, deduplication, and content addressing.
A cryptographic hash maps any input to a fixed-size fingerprint. SHA-256 is the safe default; SHA-512 and SHA-3 are fine too. MD5 and SHA-1 are broken — never use them for anything security-relevant.
Hashing is for integrity, deduplication, and content addressing. It is NOT how you store passwords: a raw hash is far too fast to compute. For passwords see the password hashing guide; when a secret key is involved, use HMAC.
Get it right
- Default to SHA-256 (or SHA-512 / SHA-3). Never MD5 or SHA-1.
- A hash is not encryption and not a MAC — anyone can recompute it.
- Never hash passwords with a plain hash; use Argon2id.
- Hash raw bytes — fix your text encoding (UTF-8) before hashing strings.
Implementation
Setup Standard library (crypto/sha256). For SHA-512 use crypto/sha512.
package main
import (
"crypto/sha256"
"encoding/hex"
"fmt"
)
func main() {
data := []byte("hello, world")
sum := sha256.Sum256(data) // [32]byte
fmt.Println(hex.EncodeToString(sum[:]))
} Setup Standard library (hashlib).
import hashlib
data = b"hello, world"
digest = hashlib.sha256(data).digest() # 32 raw bytes
hexsum = hashlib.sha256(data).hexdigest() # 64-char hex string For large files, stream with .update() in a loop instead of loading it all into memory.
Setup Built in (node:crypto).
import { createHash } from 'node:crypto';
const data = 'hello, world';
const hex = createHash('sha256').update(data).digest('hex'); // 64-char hex string
const raw = createHash('sha256').update(data).digest(); // 32-byte Buffer In the browser use WebCrypto (async): await crypto.subtle.digest("SHA-256", bytes).
Setup Built in. SHA256.HashData is .NET 5+.
using System.Security.Cryptography;
using System.Text;
byte[] data = Encoding.UTF8.GetBytes("hello, world");
byte[] hash = SHA256.HashData(data); // 32 bytes; one-shot, nothing to dispose
string hex = Convert.ToHexString(hash).ToLowerInvariant(); Setup libsodium.
#include <sodium.h>
#include <string>
int main() {
if (sodium_init() < 0) return 1;
std::string data = "hello, world";
unsigned char hash[crypto_hash_sha256_BYTES]; // 32
crypto_hash_sha256(hash,
reinterpret_cast<const unsigned char *>(data.data()), data.size());
} When you don't specifically need SHA-256, libsodium's crypto_generichash (BLAKE2b) is faster and the recommended default.
Setup Built in (java.security.MessageDigest).
import java.security.MessageDigest;
import java.nio.charset.StandardCharsets;
byte[] data = "hello, world".getBytes(StandardCharsets.UTF_8);
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] hash = md.digest(data); // 32 bytes MessageDigest is not thread-safe — get a fresh instance per use (or per thread).
Setup Cargo.toml: sha2 = "0.10".
use sha2::{Digest, Sha256};
fn main() {
let data = b"hello, world";
let hash = Sha256::digest(data); // 32-byte output
println!("{:x}", hash);
}