Golang SHA-512: Sum512, hex, files, streams, salt verify, and SHA-256 comparison

Golang SHA-512 with crypto/sha512: Sum512 and hex, sha512.New streaming io.Copy, file checksum verify, streams vs one-shot, salt-and-hash demo with verification caveats, SHA-512 vs SHA-256, HMAC, use cases, passwords with bcrypt/Argon2; pkg.go.dev and FIPS links.

Published

Updated

Read time 9 min read

Reviewed byDeepak Prasad

Golang SHA-512: Sum512, hex, files, streams, salt verify, and SHA-256 comparison

SHA-512 in Go lives in crypto/sha512. It outputs a 64-byte (512-bit) digest, usually shown as 128 hexadecimal characters—double the width of SHA-256. This guide mirrors a practical layout: quick reference, string and file hashing, verification, streaming, salted verification patterns (not password storage), comparison with SHA-256, common use cases, and pitfalls. For the 256-bit variant, see Golang SHA-256. For real encryption, see encrypt and decrypt data in Go; here we only cover hashing.

Examples were run with Go 1.24 on Linux. Hex lines match printf '%s' '…' | sha512sum for the same bytes (watch for accidental newlines).


SHA512 in Go at a Glance

  • sha512.Sum512([]byte)[64]byte — one-shot when the full message is already in memory.
  • sha512.New()hash.Hash — stream with Write or io.Copy, then Sum(nil).
  • Hex: fmt.Printf("%x", sum[:]) or hex.EncodeToString(sum[:]) (128 characters for SHA-512).
  • Verify files: stream with io.Copy, compare []byte digests with bytes.Equal after hex.DecodeString on the expected value.
  • Keyed integrity: hmac.New(sha512.New, key) — not raw SHA-512 of a secret alone.

Quick reference table for common SHA512 operations

Task API Notes
Hash small []byte sha512.Sum512 Returns [64]byte; slice with sum[:] for []byte.
Show hex %x or hex.EncodeToString 128 lowercase hex chars with %x.
Hash a file io.Copy(sha512.New(), file) Constant memory streaming.
Incremental h.Write chunks, then h.Sum(nil) Same hash.Hash contract as SHA-256.
Verify checksum Decode hex, bytes.Equal Normalize spaces and case on the published string.
Keyed MAC hmac.New(sha512.New, key) Compare with hmac.Equal.
Passwords Not plain SHA-512 Use bcrypt or Argon2.

Generate a SHA512 Hash in Go

Hash a string using sha512.Sum512

sha512.Sum512(data []byte) [64]byte hashes the entire input at once.

go
package main

import (
	"crypto/sha512"
	"fmt"
)

func main() {
	sum := sha512.Sum512([]byte("Hello GoLinuxCloud!"))
	fmt.Printf("%x\n", sum)
}
Output

Run prints:

text
84ad5dfdd5265d37a3732986ffdee98fc0e635dbffa16f8771f5421cfb9c13dee61183d2ab8c90e647cf00daaa4e6141d2c2e40c4c39cbd42e3629c9076bff42

Convert the hash to a hexadecimal string

Sum512 returns an array; slice to []byte for APIs that need a slice.

go
package main

import (
	"crypto/sha512"
	"encoding/hex"
	"fmt"
)

func main() {
	sum := sha512.Sum512([]byte("hello"))
	fmt.Printf("fmt %%x:   %x\n", sum)
	fmt.Println("hex.Encode:", hex.EncodeToString(sum[:]))
}
Output

Run prints 9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e5c3adef46f73bcdec043 twice (same as printf '%s' 'hello' | sha512sum).


Hash Files Using SHA512

Calculate the SHA512 checksum of a file

Stream through hash.Hash so you do not read the whole file into RAM.

go
package main

import (
	"crypto/sha512"
	"fmt"
	"io"
	"os"
)

func main() {
	payload := []byte("line one\nline two\n")
	f, err := os.CreateTemp("", "sha512-*.txt")
	if err != nil {
		fmt.Println(err)
		return
	}
	name := f.Name()
	defer os.Remove(name)
	if _, err := f.Write(payload); err != nil {
		fmt.Println(err)
		return
	}
	f.Close()

	in, err := os.Open(name)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer in.Close()

	h := sha512.New()
	if _, err := io.Copy(h, in); err != nil {
		fmt.Println(err)
		return
	}
	fmt.Printf("%x\n", h.Sum(nil))
}

Run prints 8bb21ebab8648a9bda3489580a0844b05fc2b1550d3672463b8eca3f01fc69750e4264b9995676ac9ced7f9038e69a55be0ea8143260c1b8227b1e3f5d56218f for that payload (matches printf 'line one\nline two\n' | sha512sum).

Verify a downloaded file using a SHA512 checksum

Decode the published hex, hash the file on disk, then compare. Trim and lowercase the published string in real tools.

go
package main

import (
	"bytes"
	"crypto/sha512"
	"encoding/hex"
	"fmt"
	"io"
	"os"
	"strings"
)

func fileSHA512(path string) ([64]byte, error) {
	f, err := os.Open(path)
	if err != nil {
		return [64]byte{}, err
	}
	defer f.Close()
	h := sha512.New()
	if _, err := io.Copy(h, f); err != nil {
		return [64]byte{}, err
	}
	var out [64]byte
	copy(out[:], h.Sum(nil))
	return out, nil
}

func main() {
	const wantHex = "8bb21ebab8648a9bda3489580a0844b05fc2b1550d3672463b8eca3f01fc69750e4264b9995676ac9ced7f9038e69a55be0ea8143260c1b8227b1e3f5d56218f"

	f, _ := os.CreateTemp("", "verify-*.txt")
	defer os.Remove(f.Name())
	_, _ = f.Write([]byte("line one\nline two\n"))
	_ = f.Close()

	want, err := hex.DecodeString(strings.TrimSpace(strings.ToLower(wantHex)))
	if err != nil || len(want) != sha512.Size {
		fmt.Println("bad expected hex")
		return
	}
	got, err := fileSHA512(f.Name())
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println("checksum OK:", bytes.Equal(got[:], want))
}

Run prints checksum OK: true.


SHA512 for Large Files and Streams

Using sha512.New with io.Copy

sha512.New() implements hash.Hash. io.Copy feeds the reader in chunks, which is the usual pattern for large bodies and network streams. The same pattern applies to *os.File, bytes.Buffer, HTTP response bodies, or any io.Reader.

go
package main

import (
	"bytes"
	"crypto/sha512"
	"fmt"
	"io"
)

func main() {
	r := bytes.NewReader([]byte("chunked-read-example"))
	h := sha512.New()
	if _, err := io.Copy(h, r); err != nil {
		panic(err)
	}
	fmt.Printf("%x\n", h.Sum(nil))
}
Output

Run prints:

text
6073c66efc39b52cd7fabdaadeee2493137136dc53ac3a3ad7adc932137790af2f24c4976bfb0d386b970ae0c08b71a03950387557f5932b452e65de69a3c917

For a temp-file walkthrough, see Calculate the SHA512 checksum of a file above.

When to use sha512.New instead of sha512.Sum512

  • Data arrives in pieces or from an io.Reader.
  • The object is too large to buffer entirely.
  • You reuse one hasher with Reset in a loop.
  • You build hmac.New(sha512.New, key).

If you already hold the full []byte, Sum512 is shorter.

The same module also offers Sum384, Sum512_224, and Sum512_256 when a protocol asks for a truncated SHA-512/SHA-384 width (pkg.go.dev).


SHA512 with Salt

Add a salt before hashing

For a custom integrity scheme you might hash append(salt, message...) or write salt then message into sha512.New(). The snippet below concatenates password and salt into one SHA-512 pass for a reproducible demo only.

go
package main

import (
	"crypto/sha512"
	"encoding/hex"
	"fmt"
)

func digestPassword(password, salt []byte) string {
	h := sha512.New()
	h.Write(password)
	h.Write(salt)
	return hex.EncodeToString(h.Sum(nil))
}

func main() {
	password := []byte("secret")
	salt := []byte("demo-salt-16b!!")
	stored := digestPassword(password, salt)
	fmt.Println(stored)
	fmt.Println("verify ok:", digestPassword([]byte("secret"), salt) == stored)
	fmt.Println("verify bad:", digestPassword([]byte("wrong"), salt) == stored)
}
Output

Run prints the long hex line, then verify ok: true and verify bad: false.

Production salts must be random per user (for example from crypto/rand), and passwords should use Argon2 or bcrypt, not a single fast SHA-512 iteration.

Why SHA512 hashes cannot be decrypted

A digest is a one-way fingerprint: you cannot recover the input from the output. “Decrypt with salt” in search queries usually means “verify a candidate password by recomputing the digest.” That is comparison, not decryption. SHA-512 also does not provide confidentiality; pairing with a secret uses HMAC or AEAD encryption, not raw hashing.


SHA512 vs SHA256 in Go

SHA-256 SHA-512
Digest size 32 bytes (64 hex chars) 64 bytes (128 hex chars)
Typical use Default interop, TLS, Git objects, many checksums Protocols or policies that mandate wider SHA-2 output
Package crypto/sha256 crypto/sha512

Performance and output size differences

Digest width is fixed: SHA-256 is 32 bytes; SHA-512 is 64 bytes (see the table above). Raw speed depends on CPU microarchitecture, clock boost, and whether the data is already hot in cache—always measure on your own binaries with realistic buffers.

Sample benchmark (one machine, for orientation only)

The following numbers come from go test -bench=. -benchmem -benchtime=1s -count=1 on linux/amd64, Go 1.24.4, CPU Intel Core Ultra 5 135U. Each benchmark hashes an all-zero buffer of the given size using one-shot sha256.Sum256 vs sha512.Sum512 (no heap allocations in this loop).

Buffer sha256.Sum256 sha512.Sum512 Time ratio (512 / 256)
1 KiB ~1.99 µs/op (~515 MB/s) ~4.86 µs/op (~211 MB/s) ~2.4×
64 KiB ~80 µs/op (~818 MB/s) ~244 µs/op (~269 MB/s) ~3.0×
1 MiB ~912 µs/op (~1150 MB/s) ~3.11 ms/op (~337 MB/s) ~3.4×

On this run, SHA-512 was slower at every size, which is common on many laptop-class cores even though both use highly optimized assembly—your server or ARM box can rank differently. Re-run with testing.B and your real payload shapes; use benchstat if you compare changes over multiple commits.

Minimal benchmark you can copy into a module (for example internal/hashbench/sha_bench_test.go):

go
package hashbench

import (
	"crypto/sha256"
	"crypto/sha512"
	"testing"
)

func benchSum256(size int, b *testing.B) {
	data := make([]byte, size)
	b.SetBytes(int64(size))
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		sha256.Sum256(data)
	}
}

func benchSum512(size int, b *testing.B) {
	data := make([]byte, size)
	b.SetBytes(int64(size))
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		sha512.Sum512(data)
	}
}

func BenchmarkSHA256_1KB(b *testing.B)   { benchSum256(1024, b) }
func BenchmarkSHA512_1KB(b *testing.B)   { benchSum512(1024, b) }
func BenchmarkSHA256_64KB(b *testing.B)  { benchSum256(64*1024, b) }
func BenchmarkSHA512_64KB(b *testing.B)  { benchSum512(64*1024, b) }
func BenchmarkSHA256_1MB(b *testing.B)  { benchSum256(1024*1024, b) }
func BenchmarkSHA512_1MB(b *testing.B)  { benchSum512(1024*1024, b) }

Then from the module root: go test ./path/to/hashbench -bench=. -benchmem -benchtime=1s.

Choose SHA-256 unless you need the larger digest or a standard mandates SHA-512 explicitly.

Which algorithm should you choose?

Default to SHA-256 for new integrity work and broad ecosystem compatibility. Choose SHA-512 when a specification requires it, when you want a larger fingerprint without truncation, or when you standardize on SHA-512/384-style suites. For passwords, choose Argon2id or bcrypt regardless of SHA-2 size.


Common SHA512 Use Cases

File integrity verification

Same workflow as SHA-256: publish a .sha512 or SHA512SUMS file, recompute locally, compare digests (see verify a downloaded file).

Digital signatures and certificates

TLS, CMS, and certificate tooling may combine asymmetric keys with SHA-2 family digests; exact algorithms depend on the protocol version and cipher suite. In application code you rarely “pick SHA-512 for TLS” directly—libraries choose permitted pairs. SHA-512 appears in signing APIs where a standard specifies it.

Content fingerprinting

Use the hex digest (or a prefix) as a cache key or content address. Anyone who knows the input can recompute the digest, so this detects change, not secrecy.

HMAC-SHA512 example

go
package main

import (
	"crypto/hmac"
	"crypto/sha512"
	"encoding/hex"
	"fmt"
)

func main() {
	k := []byte("key")
	m := []byte("msg")
	mac := hmac.New(sha512.New, k)
	mac.Write(m)
	fmt.Println(hex.EncodeToString(mac.Sum(nil)))
}
Output

Run prints 1e4b55b925ccc28ed90d9d18fc2393fcbe164c0d84e67e173cc5aa486b7afc106633c66bdc309076f5f8d9fdbbb62456f894f2c23377fbcc12f4ab2940eb6d70.


Common Mistakes and Security Notes

SHA512 is not encryption

Hashing produces a fixed-size digest with no secret key in the basic form; it does not hide data. Confidentiality needs encryption (for example AES-GCM) with proper key management.

SHA512 should not be used for password storage

A single SHA-512 (even with a salt) is far too fast for password guessing at scale. Use Argon2id, bcrypt, or scrypt with parameters tuned to your environment.


SHA512 cheat sheet (single source)

Runnable programs live in the sections above. The quick reference table lists APIs; repeating full programs at the end tends to drift (wrong file paths, half snippets). Copy from the verified blocks in this page instead of maintaining a second copy.


Summary

Use sha512.Sum512 for small in-memory buffers and sha512.New with io.Copy or Write for files and streams. Format digests as 128 hex characters. Verify downloads by decoding expected hex and comparing 64-byte digests. Treat “salted SHA-512” demos as illustration only—real passwords belong to Argon2/bcrypt. Prefer SHA-256 unless you need SHA-512’s width or a standard requires it; use HMAC when the design calls for a keyed MAC.


References


Frequently Asked Questions

1. What is the difference between sha512.Sum512 and sha512.New?

Sum512 takes a complete []byte and returns [64]byte. New returns hash.Hash so you can stream with multiple Write calls or io.Copy from a file.

2. Can I decrypt SHA-512 with a salt?

No. A digest is not ciphertext. You can only verify a candidate by hashing it with the same salt and comparing digests.

3. Does this package include SHA-384 or SHA-512/256?

Yes. The same package provides Sum384, Sum512_224, and Sum512_256 variants per FIPS 180-4; this article focuses on Sum512 and New for full SHA-512.

4. Is raw SHA-512 enough for passwords?

Not recommended. Use a password-specific function such as Argon2id or bcrypt; they add tunable cost and resist common attacks better than a single fast hash.

5. How long is a SHA-512 hex string?

64 bytes of digest become 128 hexadecimal characters; sha512.Size is 64.
Tuan Nguyen

Data Scientist

Proficient in Golang, Python, Java, MongoDB, Selenium, Spring Boot, Kubernetes, Scrapy, API development, Docker, Data Scraping, PrimeFaces, Linux, Data Structures, and Data Mining. With expertise …