Files
encryptx/sha3x/sha3x.go
T
2026-09-30 15:49:12 +08:00

364 lines
12 KiB
Go

// Package sha3x 提供 SHA3-224/256/384/512 摘要计算与 SHAKE128/SHAKE256 可扩展输出函数(XOF),
// 并附带十六进制/Base64 编码与流式、文件接口。
//
// SHAKE 是 XOF:输出长度由调用方指定,必须显式校验。本包要求 outputLength 在
// [1, MaxShakeOutputLength] 之间,超出范围返回 error 而不是 panic 或分配巨大内存。
//
// 命名约定:带位数后缀的函数(Sum224、Hex224、New224 等)明确指定算法变体;
// 不带后缀的 Sum、Hex、Base64、New、SumReader、HexReader、HexFile 等价于 256 位变体。
package sha3x
import (
"encoding/base64"
"encoding/hex"
"fmt"
"hash"
"io"
"os"
"golang.org/x/crypto/sha3"
)
const (
// Size224 是 SHA3-224 摘要的字节数(28)。
Size224 = 28
// Size256 是 SHA3-256 摘要的字节数(32)。
Size256 = 32
// Size384 是 SHA3-384 摘要的字节数(48)。
Size384 = 48
// Size512 是 SHA3-512 摘要的字节数(64)。
Size512 = 64
// Rate224 是 SHA3-224 的海绵分组(rate)字节数(144)。
Rate224 = 144
// Rate256 是 SHA3-256 的海绵分组(rate)字节数(136)。
Rate256 = 136
// Rate384 是 SHA3-384 的海绵分组(rate)字节数(104)。
Rate384 = 104
// Rate512 是 SHA3-512 的海绵分组(rate)字节数(72)。
Rate512 = 72
// MaxShakeOutputLength 是 SHAKE128/SHAKE256 单次允许请求的最大输出字节数(1 MiB)。
MaxShakeOutputLength = 1 << 20
)
// New224 返回一个计算 SHA3-224 摘要的 hash.Hash。
func New224() hash.Hash {
return sha3.New224()
}
// New256 返回一个计算 SHA3-256 摘要的 hash.Hash。
func New256() hash.Hash {
return sha3.New256()
}
// New384 返回一个计算 SHA3-384 摘要的 hash.Hash。
func New384() hash.Hash {
return sha3.New384()
}
// New512 返回一个计算 SHA3-512 摘要的 hash.Hash。
func New512() hash.Hash {
return sha3.New512()
}
// New 等价于 New256。
func New() hash.Hash {
return New256()
}
// NewShake128 返回一个 SHAKE128 XOF 实例,可流式 Write 输入后按需 Read 任意长度输出。
// 调用方需自行保证输出长度合理(参见 MaxShakeOutputLength)。
func NewShake128() sha3.ShakeHash {
return sha3.NewShake128()
}
// NewShake256 返回一个 SHAKE256 XOF 实例,可流式 Write 输入后按需 Read 任意长度输出。
// 调用方需自行保证输出长度合理(参见 MaxShakeOutputLength)。
func NewShake256() sha3.ShakeHash {
return sha3.NewShake256()
}
// Sum224 返回 data 的 SHA3-224 摘要(Size224 字节原始数据)。
func Sum224(data []byte) []byte {
return sum(sha3.New224(), data)
}
// Sum256 返回 data 的 SHA3-256 摘要(Size256 字节原始数据)。
func Sum256(data []byte) []byte {
return sum(sha3.New256(), data)
}
// Sum384 返回 data 的 SHA3-384 摘要(Size384 字节原始数据)。
func Sum384(data []byte) []byte {
return sum(sha3.New384(), data)
}
// Sum512 返回 data 的 SHA3-512 摘要(Size512 字节原始数据)。
func Sum512(data []byte) []byte {
return sum(sha3.New512(), data)
}
// Sum 等价于 Sum256。
func Sum(data []byte) []byte {
return Sum256(data)
}
// Hex224 返回 data 的 SHA3-224 摘要的小写十六进制字符串。
func Hex224(data []byte) string {
return hex.EncodeToString(Sum224(data))
}
// Hex256 返回 data 的 SHA3-256 摘要的小写十六进制字符串。
func Hex256(data []byte) string {
return hex.EncodeToString(Sum256(data))
}
// Hex384 返回 data 的 SHA3-384 摘要的小写十六进制字符串。
func Hex384(data []byte) string {
return hex.EncodeToString(Sum384(data))
}
// Hex512 返回 data 的 SHA3-512 摘要的小写十六进制字符串。
func Hex512(data []byte) string {
return hex.EncodeToString(Sum512(data))
}
// Hex 等价于 Hex256。
func Hex(data []byte) string {
return Hex256(data)
}
// Base64Sum224 返回 data 的 SHA3-224 摘要的标准 Base64 字符串。
func Base64Sum224(data []byte) string {
return base64.StdEncoding.EncodeToString(Sum224(data))
}
// Base64Sum256 返回 data 的 SHA3-256 摘要的标准 Base64 字符串。
func Base64Sum256(data []byte) string {
return base64.StdEncoding.EncodeToString(Sum256(data))
}
// Base64Sum384 返回 data 的 SHA3-384 摘要的标准 Base64 字符串。
func Base64Sum384(data []byte) string {
return base64.StdEncoding.EncodeToString(Sum384(data))
}
// Base64Sum512 返回 data 的 SHA3-512 摘要的标准 Base64 字符串。
func Base64Sum512(data []byte) string {
return base64.StdEncoding.EncodeToString(Sum512(data))
}
// Base64 等价于 Base64Sum256。
func Base64(data []byte) string {
return Base64Sum256(data)
}
// Sum224Reader 读取 r 中的全部数据并返回其 SHA3-224 摘要。
func Sum224Reader(r io.Reader) ([]byte, error) {
return sumReader(sha3.New224(), r)
}
// Sum256Reader 读取 r 中的全部数据并返回其 SHA3-256 摘要。
func Sum256Reader(r io.Reader) ([]byte, error) {
return sumReader(sha3.New256(), r)
}
// Sum384Reader 读取 r 中的全部数据并返回其 SHA3-384 摘要。
func Sum384Reader(r io.Reader) ([]byte, error) {
return sumReader(sha3.New384(), r)
}
// Sum512Reader 读取 r 中的全部数据并返回其 SHA3-512 摘要。
func Sum512Reader(r io.Reader) ([]byte, error) {
return sumReader(sha3.New512(), r)
}
// SumReader 等价于 Sum256Reader。
func SumReader(r io.Reader) ([]byte, error) {
return Sum256Reader(r)
}
// Hex224Reader 读取 r 中的全部数据并返回其 SHA3-224 摘要的小写十六进制字符串。
func Hex224Reader(r io.Reader) (string, error) {
return hexReader(sha3.New224(), r)
}
// Hex256Reader 读取 r 中的全部数据并返回其 SHA3-256 摘要的小写十六进制字符串。
func Hex256Reader(r io.Reader) (string, error) {
return hexReader(sha3.New256(), r)
}
// Hex384Reader 读取 r 中的全部数据并返回其 SHA3-384 摘要的小写十六进制字符串。
func Hex384Reader(r io.Reader) (string, error) {
return hexReader(sha3.New384(), r)
}
// Hex512Reader 读取 r 中的全部数据并返回其 SHA3-512 摘要的小写十六进制字符串。
func Hex512Reader(r io.Reader) (string, error) {
return hexReader(sha3.New512(), r)
}
// HexReader 等价于 Hex256Reader。
func HexReader(r io.Reader) (string, error) {
return Hex256Reader(r)
}
// HexFile224 计算 path 所指向文件的 SHA3-224 摘要并返回小写十六进制字符串。
func HexFile224(path string) (string, error) {
return hexFile(path, "SHA3-224", sha3.New224)
}
// HexFile256 计算 path 所指向文件的 SHA3-256 摘要并返回小写十六进制字符串。
func HexFile256(path string) (string, error) {
return hexFile(path, "SHA3-256", sha3.New256)
}
// HexFile384 计算 path 所指向文件的 SHA3-384 摘要并返回小写十六进制字符串。
func HexFile384(path string) (string, error) {
return hexFile(path, "SHA3-384", sha3.New384)
}
// HexFile512 计算 path 所指向文件的 SHA3-512 摘要并返回小写十六进制字符串。
func HexFile512(path string) (string, error) {
return hexFile(path, "SHA3-512", sha3.New512)
}
// HexFile 等价于 HexFile256。
func HexFile(path string) (string, error) {
return HexFile256(path)
}
// Shake128 返回 data 经 SHAKE128 扩展后的 outputLength 字节输出。
// outputLength 必须大于 0 且不超过 MaxShakeOutputLength,否则返回 error。
func Shake128(data []byte, outputLength int) ([]byte, error) {
return shakeSum(sha3.NewShake128(), data, outputLength)
}
// Shake256 返回 data 经 SHAKE256 扩展后的 outputLength 字节输出。
// outputLength 必须大于 0 且不超过 MaxShakeOutputLength,否则返回 error。
func Shake256(data []byte, outputLength int) ([]byte, error) {
return shakeSum(sha3.NewShake256(), data, outputLength)
}
// Shake128Hex 返回 data 经 SHAKE128 扩展后的 outputLength 字节输出的小写十六进制字符串。
// outputLength 必须大于 0 且不超过 MaxShakeOutputLength,否则返回 error。
func Shake128Hex(data []byte, outputLength int) (string, error) {
out, err := Shake128(data, outputLength)
if err != nil {
return "", err
}
return hex.EncodeToString(out), nil
}
// Shake256Hex 返回 data 经 SHAKE256 扩展后的 outputLength 字节输出的小写十六进制字符串。
// outputLength 必须大于 0 且不超过 MaxShakeOutputLength,否则返回 error。
func Shake256Hex(data []byte, outputLength int) (string, error) {
out, err := Shake256(data, outputLength)
if err != nil {
return "", err
}
return hex.EncodeToString(out), nil
}
// Shake128Reader 读取 r 中的全部数据并返回其 SHAKE128 扩展的 outputLength 字节输出。
// outputLength 必须大于 0 且不超过 MaxShakeOutputLength,否则返回 error。
func Shake128Reader(r io.Reader, outputLength int) ([]byte, error) {
return shakeSumReader(sha3.NewShake128(), r, outputLength)
}
// Shake256Reader 读取 r 中的全部数据并返回其 SHAKE256 扩展的 outputLength 字节输出。
// outputLength 必须大于 0 且不超过 MaxShakeOutputLength,否则返回 error。
func Shake256Reader(r io.Reader, outputLength int) ([]byte, error) {
return shakeSumReader(sha3.NewShake256(), r, outputLength)
}
// sum 把 data 一次性写入 h 并取出摘要。
func sum(h hash.Hash, data []byte) []byte {
_, _ = h.Write(data)
return h.Sum(nil)
}
// sumReader 把 r 的全部内容写入 h 并取出摘要。
func sumReader(h hash.Hash, r io.Reader) ([]byte, error) {
if r == nil {
return nil, fmt.Errorf("sha3x: 读取器为 nil")
}
if _, err := io.Copy(h, r); err != nil {
return nil, fmt.Errorf("sha3x: 读取数据失败: %w", err)
}
return h.Sum(nil), nil
}
// hexReader 读取 r 的全部内容并以小写十六进制返回摘要。
func hexReader(h hash.Hash, r io.Reader) (string, error) {
sum, err := sumReader(h, r)
if err != nil {
return "", err
}
return hex.EncodeToString(sum), nil
}
// hexFile 计算文件的小写十六进制摘要,name 仅用于错误信息。
func hexFile(path, name string, newHash func() hash.Hash) (string, error) {
f, err := os.Open(path)
if err != nil {
return "", fmt.Errorf("sha3x: 打开文件 %q 失败: %w", path, err)
}
defer f.Close()
sum, err := sumReader(newHash(), f)
if err != nil {
return "", fmt.Errorf("sha3x: 计算文件 %q 的 %s 摘要失败: %w", path, name, err)
}
return hex.EncodeToString(sum), nil
}
// checkShakeLength 校验 XOF 输出长度是否在允许范围内。
func checkShakeLength(outputLength int) error {
if outputLength <= 0 {
return fmt.Errorf("sha3x: SHAKE 输出长度必须大于 0,当前为 %d", outputLength)
}
if outputLength > MaxShakeOutputLength {
return fmt.Errorf("sha3x: SHAKE 输出长度 %d 超过上限 %d", outputLength, MaxShakeOutputLength)
}
return nil
}
// readShake 从已写入输入的 XOF 中精确读取 outputLength 字节。
func readShake(h sha3.ShakeHash, outputLength int) ([]byte, error) {
if err := checkShakeLength(outputLength); err != nil {
return nil, err
}
out := make([]byte, outputLength)
if _, err := io.ReadFull(h, out); err != nil {
return nil, fmt.Errorf("sha3x: 读取 SHAKE 输出失败: %w", err)
}
return out, nil
}
// shakeSum 计算 data 的 XOF 输出。
func shakeSum(h sha3.ShakeHash, data []byte, outputLength int) ([]byte, error) {
if err := checkShakeLength(outputLength); err != nil {
return nil, err
}
if _, err := h.Write(data); err != nil {
return nil, fmt.Errorf("sha3x: 写入 SHAKE 输入失败: %w", err)
}
return readShake(h, outputLength)
}
// shakeSumReader 计算 r 全部内容的 XOF 输出。
func shakeSumReader(h sha3.ShakeHash, r io.Reader, outputLength int) ([]byte, error) {
if r == nil {
return nil, fmt.Errorf("sha3x: 读取器为 nil")
}
if err := checkShakeLength(outputLength); err != nil {
return nil, err
}
if _, err := io.Copy(h, r); err != nil {
return nil, fmt.Errorf("sha3x: 读取数据失败: %w", err)
}
return readShake(h, outputLength)
}