哈希 MD5 SHA256
2026-07-24
JavaScript hashing speed comparison: MD5 versus SHA-256(Daniel Lemire, 2025-01-11)通过 JavaScript 基准测试对比了 MD5 与 SHA-256 在 Node.js 23 和 Bun 运行时下的哈希性能,核心结论颠覆了“MD5 更快”的传统认知:
- 测试背景与方法:使用 1GB 随机 Uint8Array 数据,在 ARM(Apple M2、Graviton 4)和 x86(Intel Ice Lake)系统上,分别对
md5Hash 和 sha256Hash 进行基准测试,底层实际调用 OpenSSL 实现。
- 关键性能数据:在现代 CPU 上 SHA-256 显著快于 MD5。例如在 Apple M2(Node.js)上,SHA-256 约 2.6 GB/s,MD5 仅约 0.6–0.7 GB/s;在 Intel Ice Lake 上 SHA-256 也达到 1.2 GB/s,优于或持平 MD5。
- 原因分析:SHA-256 虽然在算法设计上更复杂,但现代处理器(ARMv8、x86 等)普遍带有 硬件密码学扩展指令(如 Intel SHA-NI),对其进行了加速;而老旧且已被破解的 MD5 并未获得类似优化。
- 最终建议:不应再使用 MD5。它既在安全性上已被彻底攻破(存在碰撞攻击),在实际速度上也失去了优势,开发者应默认选择 SHA-256 或更先进的算法(如 BLAKE3,若可用)。
这是采用的 JavaScript 做的基准测试,但是结论说明的是通用硬件现象:现代 CPU(ARM/x86)有 SHA-256 硬件指令加速,而 MD5 无优化,任何语言调底层实现都如此。
因此,在现代处理器上,SHA256 性能大幅优于 MD5 的结论在所有语言上都是通用的。
Python 哈希
2021-10-01
一个不值一提的小问题:
有个地方使用 hash 方法来做哈希计算,将字符串转换成一个数值,但是发现改用 Python 3 之后,这个值每次运行都不一样了。
Python 哈希 密码学
2021-10-01
开发时,有时候我们需要将任意字符串映射成一个数字或字符串,这就是哈希。
Golang 哈希
2021-02-12
哈希算法(hash)是一种将任意长度数据映射成固定长度数据的方法。有时也叫摘要算法。
有非常多不同的哈希算法,其中最常见的是 md5 和 sha (sha1/sha256/sha512)两种。Golang md5 在 2021/01/14, Go MD5 中已经写过了。这里就记录一下 Golang sha 的使用方法。
// crypto.sha1
func New() hash.Hash
func Sum(data []byte) [Size]byte {
if boringEnabled {
return boringSHA1(data)
}
var d digest
d.Reset()
d.Write(data)
return d.checkSum()
}
func (d *digest) MarshalBinary() ([]byte, error)
func (d *digest) UnmarshalBinary(b []byte) error
func (d *digest) Reset()
func (d *digest) Size() int
func (d *digest) BlockSize() int
func (d *digest) Write(p []byte) (nn int, err error)
func (d *digest) Sum(in []byte) []byte
func (d *digest) checkSum() [Size]byte
func (d *digest) ConstantTimeSum(in []byte) []byte
func (d *digest) constSum() [Size]byte
// crypto.sha256
func New() hash.Hash
func New224() hash.Hash // sha224
func Sum224(data []byte) [Size224]byte
func Sum256(data []byte) [Size]byte
// crypto.sha512
func New() hash.Hash
func New384() hash.Hash
func New512_224() hash.Hash
func New512_256() hash.Hash
func Sum384(data []byte) [Size384]byte
func Sum512(data []byte) [Size]byte
func Sum512_224(data []byte) [Size224]byte
func Sum512_256(data []byte) [Size256]byte
用法都一样:
h := sha1.New() // hash.Hash
io.WriteString(h, "His money is twice tainted:")
io.WriteString(h, " 'taint yours and 'taint mine.")
fmt.Printf("% x", h.Sum(nil))
h := sha1.New()
if _, err := io.Copy(h, f); err != nil {
log.Fatal(err)
}
fmt.Printf("% x", h.Sum(nil))
hash.Hash 接口
type Hash interface {
io.Writer
Sum(b []byte) []byte
Reset()
Size() int
BlockSize() int
}
函数
sha1.New() -> hash.Hash
-
sha1.Sum(data []byte) -> [Size]byte
-
sha256.New() -> hash.Hash
sha256.Sum256(data []byte) -> [Size]byte
sha256.New224() -> hash.Hash
-
sha256.Sum224(data []byte) -> [Size224]byte
-
sha512.New() -> hash.Hash
sha512.Sum512(data []byte) -> [Size]byte
sha512.New384() -> hash.Hash
sha512.Sum384(data []byte) -> [Size384]byte
sha512.New512_224() -> hash.Hash
sha512.Sum512_224(data []byte) -> [Size224]byte
sha512.New512_256() -> hash.Hash
sha512.Sum512_256(data []byte) -> [Size256]byte
package main
import (
"crypto/md5"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"fmt"
"hash/fnv"
"io"
"log"
"os"
)
func main() {
filepath := "go.mod"
f, err := os.Open(filepath)
if err != nil {
log.Fatal(err)
}
defer f.Close()
fi, err := f.Stat()
fmt.Printf("%#v err:%#v\n", fi, err)
data := make([]byte, fi.Size())
n, err := f.Read(data)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%d, %#v, err:%#v\n", n, data, err)
{
hash := fnv.New32a()
hash.Write(data)
result := hash.Sum32()
fmt.Printf("FNV-1a 32-bit hash: %d\n\n", result)
}
{
fmt.Printf("MD5 : %x\n", md5.Sum(data))
fmt.Printf("Sha1 : %x\n", sha1.Sum(data))
fmt.Printf("Sha256 : %x\n", sha256.Sum256(data))
fmt.Printf("Sha512 : %x\n", sha512.Sum512(data))
}
{
f.Seek(0, 0)
hasher := md5.New()
_, err = io.Copy(hasher, f)
if err != nil {
log.Fatal(err)
}
sum := hasher.Sum(nil)
fmt.Printf("MD5 2 : %x\n", sum)
}
}