完善不同加密方法的使用

This commit is contained in:
yun
2026-09-30 15:49:12 +08:00
parent 034315ddbd
commit 7db722f8b9
69 changed files with 21362 additions and 2563 deletions
+129 -6
View File
@@ -1,14 +1,137 @@
// Package sha256x 提供 SHA-224 与 SHA-256 摘要计算,以及十六进制/Base64 编码与流式、文件接口。
//
// 命名约定:带位数后缀的函数(Sum224、Hex224、New224 等)明确指定算法变体;
// 不带后缀的 Sum、Hex、Base64、New、SumReader、HexReader、HexFile 等价于 256 位变体,
// 因为 SHA-256 是本包最常用的变体。
package sha256x
import (
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"fmt"
"hash"
"io"
"os"
)
//Sha256加密
func Sha256(src string) string {
m := sha256.New()
m.Write([]byte(src))
res := hex.EncodeToString(m.Sum(nil))
return res
const (
// Size224 是 SHA-224 摘要的字节数(28)。
Size224 = sha256.Size224
// Size256 是 SHA-256 摘要的字节数(32)。
Size256 = sha256.Size
// BlockSize 是 SHA-224/SHA-256 分组的字节数(64)。
BlockSize = sha256.BlockSize
)
// New224 返回一个计算 SHA-224 摘要的 hash.Hash。
func New224() hash.Hash {
return sha256.New224()
}
// New256 返回一个计算 SHA-256 摘要的 hash.Hash。
func New256() hash.Hash {
return sha256.New()
}
// New 等价于 New256。
func New() hash.Hash {
return New256()
}
// Sum224 返回 data 的 SHA-224 摘要(Size224 字节原始数据)。
func Sum224(data []byte) []byte {
return sum(sha256.New224(), data)
}
// Sum256 返回 data 的 SHA-256 摘要(Size256 字节原始数据)。
func Sum256(data []byte) []byte {
return sum(sha256.New(), data)
}
// Sum 等价于 Sum256。
func Sum(data []byte) []byte {
return Sum256(data)
}
// Hex224 返回 data 的 SHA-224 摘要的小写十六进制字符串。
func Hex224(data []byte) string {
return hex.EncodeToString(Sum224(data))
}
// Hex256 返回 data 的 SHA-256 摘要的小写十六进制字符串。
func Hex256(data []byte) string {
return hex.EncodeToString(Sum256(data))
}
// Hex 等价于 Hex256。
func Hex(data []byte) string {
return Hex256(data)
}
// Base64Sum224 返回 data 的 SHA-224 摘要的标准 Base64 字符串。
func Base64Sum224(data []byte) string {
return base64.StdEncoding.EncodeToString(Sum224(data))
}
// Base64Sum256 返回 data 的 SHA-256 摘要的标准 Base64 字符串。
func Base64Sum256(data []byte) string {
return base64.StdEncoding.EncodeToString(Sum256(data))
}
// Base64 等价于 Base64Sum256。
func Base64(data []byte) string {
return Base64Sum256(data)
}
// SumReader 读取 r 中的全部数据并返回其 SHA-256 摘要;读取失败时返回包装后的 error。
func SumReader(r io.Reader) ([]byte, error) {
return sumReader(sha256.New(), r)
}
// HexReader 读取 r 中的全部数据并返回其 SHA-256 摘要的小写十六进制字符串。
func HexReader(r io.Reader) (string, error) {
sum, err := SumReader(r)
if err != nil {
return "", err
}
return hex.EncodeToString(sum), nil
}
// HexFile 计算 path 所指向文件的 SHA-256 摘要并返回小写十六进制字符串;
// 文件不存在或读取失败时返回包装后的 error,不 panic。
func HexFile(path string) (string, error) {
return hexFile(path, sha256.New)
}
// 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("sha256x: 读取器为 nil")
}
if _, err := io.Copy(h, r); err != nil {
return nil, fmt.Errorf("sha256x: 读取数据失败: %w", err)
}
return h.Sum(nil), nil
}
// hexFile 计算文件的小写十六进制摘要,newHash 提供具体算法实例。
func hexFile(path string, newHash func() hash.Hash) (string, error) {
f, err := os.Open(path)
if err != nil {
return "", fmt.Errorf("sha256x: 打开文件 %q 失败: %w", path, err)
}
defer f.Close()
sum, err := sumReader(newHash(), f)
if err != nil {
return "", fmt.Errorf("sha256x: 计算文件 %q 摘要失败: %w", path, err)
}
return hex.EncodeToString(sum), nil
}
+254
View File
@@ -0,0 +1,254 @@
package sha256x_test
import (
"bytes"
"encoding/base64"
"encoding/hex"
"errors"
"os"
"path/filepath"
"strings"
"testing"
"code.yun.ink/pkg/encryptx/sha256x"
)
// 测试向量来源:FIPS 180-4 示例与 NIST 标准测试向量,并经 Python 3 hashlib 独立复算确认。
var vectors224 = []struct {
name string
input string
want string
}{
{"空串", "", "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f"},
{"abc", "abc", "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7"},
}
var vectors256 = []struct {
name string
input string
want string
}{
{"空串", "", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"},
{"abc", "abc", "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"},
{"The quick brown fox jumps over the lazy dog", "The quick brown fox jumps over the lazy dog", "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592"},
}
type failingReader struct{}
func (failingReader) Read([]byte) (int, error) { return 0, errors.New("模拟读取失败") }
func TestConstants(t *testing.T) {
if sha256x.Size224 != 28 || sha256x.Size256 != 32 {
t.Fatalf("Size224 = %d, Size256 = %d, 期望 28 / 32", sha256x.Size224, sha256x.Size256)
}
if sha256x.BlockSize != 64 {
t.Fatalf("BlockSize = %d, 期望 64", sha256x.BlockSize)
}
}
func TestVectors224(t *testing.T) {
for _, v := range vectors224 {
t.Run(v.name, func(t *testing.T) {
data := []byte(v.input)
sum := sha256x.Sum224(data)
if len(sum) != sha256x.Size224 {
t.Fatalf("Sum224 长度 = %d, 期望 %d", len(sum), sha256x.Size224)
}
if got := hex.EncodeToString(sum); got != v.want {
t.Errorf("Sum224 = %s, 期望 %s", got, v.want)
}
if got := sha256x.Hex224(data); got != v.want {
t.Errorf("Hex224 = %s, 期望 %s", got, v.want)
}
if want := base64.StdEncoding.EncodeToString(sum); sha256x.Base64Sum224(data) != want {
t.Errorf("Base64Sum224 = %s, 期望 %s", sha256x.Base64Sum224(data), want)
}
h := sha256x.New224()
if _, err := h.Write(data); err != nil {
t.Fatalf("Write 失败: %v", err)
}
if got := hex.EncodeToString(h.Sum(nil)); got != v.want {
t.Errorf("New224+Write = %s, 期望 %s", got, v.want)
}
})
}
}
func TestVectors256(t *testing.T) {
for _, v := range vectors256 {
t.Run(v.name, func(t *testing.T) {
data := []byte(v.input)
sum := sha256x.Sum256(data)
if len(sum) != sha256x.Size256 {
t.Fatalf("Sum256 长度 = %d, 期望 %d", len(sum), sha256x.Size256)
}
if got := hex.EncodeToString(sum); got != v.want {
t.Errorf("Sum256 = %s, 期望 %s", got, v.want)
}
if got := sha256x.Hex256(data); got != v.want {
t.Errorf("Hex256 = %s, 期望 %s", got, v.want)
}
if want := base64.StdEncoding.EncodeToString(sum); sha256x.Base64Sum256(data) != want {
t.Errorf("Base64Sum256 = %s, 期望 %s", sha256x.Base64Sum256(data), want)
}
h := sha256x.New256()
if _, err := h.Write(data); err != nil {
t.Fatalf("Write 失败: %v", err)
}
if got := hex.EncodeToString(h.Sum(nil)); got != v.want {
t.Errorf("New256+Write = %s, 期望 %s", got, v.want)
}
})
}
}
func TestDefaultAliasesMatch256(t *testing.T) {
data := []byte("encryptx alias check")
if !bytes.Equal(sha256x.Sum(data), sha256x.Sum256(data)) {
t.Error("Sum 应等价于 Sum256")
}
if sha256x.Hex(data) != sha256x.Hex256(data) {
t.Error("Hex 应等价于 Hex256")
}
if sha256x.Base64(data) != sha256x.Base64Sum256(data) {
t.Error("Base64 应等价于 Base64Sum256")
}
h := sha256x.New()
if h.Size() != sha256x.Size256 {
t.Errorf("New().Size() = %d, 期望 %d", h.Size(), sha256x.Size256)
}
}
func TestVariantsDiffer(t *testing.T) {
data := []byte("abc")
if sha256x.Hex224(data) == sha256x.Hex256(data) {
t.Error("SHA-224 与 SHA-256 的摘要不应相同")
}
}
func TestStreamingMatchesSum(t *testing.T) {
data := []byte(strings.Repeat("encryptx-sha256-", 100))
for _, tc := range []struct {
name string
h hashLike
whole []byte
}{
{"SHA-224", sha256x.New224(), sha256x.Sum224(data)},
{"SHA-256", sha256x.New256(), sha256x.Sum256(data)},
} {
t.Run(tc.name, func(t *testing.T) {
for i := 0; i < len(data); i += 9 {
end := i + 9
if end > len(data) {
end = len(data)
}
if _, err := tc.h.Write(data[i:end]); err != nil {
t.Fatalf("Write 失败: %v", err)
}
}
if sum := tc.h.Sum(nil); !bytes.Equal(sum, tc.whole) {
t.Errorf("分块写入 = %x, 期望 %x", sum, tc.whole)
}
})
}
}
// hashLike 是测试用的最小哈希接口。
type hashLike interface {
Write([]byte) (int, error)
Sum([]byte) []byte
}
func TestReaderConsistency(t *testing.T) {
const s = "encryptx 一致性检查"
sum, err := sha256x.SumReader(strings.NewReader(s))
if err != nil {
t.Fatalf("SumReader 失败: %v", err)
}
if want := sha256x.Sum256([]byte(s)); !bytes.Equal(sum, want) {
t.Errorf("SumReader = %x, 期望 %x", sum, want)
}
hexStr, err := sha256x.HexReader(strings.NewReader(s))
if err != nil {
t.Fatalf("HexReader 失败: %v", err)
}
if want := sha256x.Hex256([]byte(s)); hexStr != want {
t.Errorf("HexReader = %s, 期望 %s", hexStr, want)
}
}
func TestReaderErrors(t *testing.T) {
if _, err := sha256x.SumReader(nil); err == nil {
t.Fatal("nil 读取器应返回 error")
}
if _, err := sha256x.HexReader(nil); err == nil {
t.Fatal("nil 读取器应返回 error")
}
if _, err := sha256x.SumReader(failingReader{}); err == nil {
t.Fatal("读取失败时应返回 error")
}
}
func TestHexFile(t *testing.T) {
dir := t.TempDir()
content := []byte("文件内容 file content\n")
path := filepath.Join(dir, "sample.bin")
if err := os.WriteFile(path, content, 0o600); err != nil {
t.Fatalf("写入测试文件失败: %v", err)
}
got, err := sha256x.HexFile(path)
if err != nil {
t.Fatalf("HexFile 失败: %v", err)
}
if want := sha256x.Hex256(content); got != want {
t.Errorf("HexFile = %s, 期望 %s", got, want)
}
}
func TestHexFileErrors(t *testing.T) {
if _, err := sha256x.HexFile(filepath.Join(t.TempDir(), "不存在.bin")); err == nil {
t.Fatal("不存在的文件应返回 error")
}
if _, err := sha256x.HexFile(""); err == nil {
t.Fatal("空路径应返回 error")
}
if _, err := sha256x.HexFile(t.TempDir()); err == nil {
t.Fatal("目录路径应返回 error")
}
}
func TestLargeInput(t *testing.T) {
data := largeData(1 << 20)
want := sha256x.Hex256(data)
if got := sha256x.Hex256(data); got != want {
t.Errorf("重复计算结果不一致: %s vs %s", got, want)
}
got, err := sha256x.HexReader(bytes.NewReader(data))
if err != nil {
t.Fatalf("HexReader 失败: %v", err)
}
if got != want {
t.Errorf("HexReader = %s, 期望 %s", got, want)
}
h := sha256x.New256()
if _, err := h.Write(data[:1<<19]); err != nil {
t.Fatalf("Write 失败: %v", err)
}
if _, err := h.Write(data[1<<19:]); err != nil {
t.Fatalf("Write 失败: %v", err)
}
if got := hex.EncodeToString(h.Sum(nil)); got != want {
t.Errorf("1MiB 分块 = %s, 期望 %s", got, want)
}
}
// largeData 生成确定性的 n 字节数据。
func largeData(n int) []byte {
b := make([]byte, n)
for i := range b {
b[i] = byte(i*31 + i/7)
}
return b
}