// 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) }