70 lines
1.9 KiB
Go
70 lines
1.9 KiB
Go
package passwordutil
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"testing"
|
|
)
|
|
|
|
// TestHashVerifyArgon2id 新算法:哈希后可校验,错误密码拒绝
|
|
func TestHashVerifyArgon2id(t *testing.T) {
|
|
stored, err := Hash("Passw0rd@2026")
|
|
if err != nil {
|
|
t.Fatalf("Hash 失败: %v", err)
|
|
}
|
|
if !verifyArgon2id(stored, "Passw0rd@2026") {
|
|
t.Fatal("正确密码应校验通过")
|
|
}
|
|
if verifyArgon2id(stored, "wrong-password") {
|
|
t.Fatal("错误密码不应通过")
|
|
}
|
|
if NeedsRehash(stored) {
|
|
t.Fatal("argon2id 不应需要重新哈希")
|
|
}
|
|
if AlgoOf(stored) != AlgoArgon2id {
|
|
t.Fatalf("算法标识应为 argon2id,实际 %s", AlgoOf(stored))
|
|
}
|
|
}
|
|
|
|
// TestLegacyCompat 旧算法兼容:历史 salt$sha256 串仍可登录,且被标记为需要升级
|
|
func TestLegacyCompat(t *testing.T) {
|
|
saltHex := "0123456789abcdef0123456789abcdef"
|
|
sum := sha256.Sum256([]byte(saltHex + "oldpass"))
|
|
legacy := saltHex + "$" + hex.EncodeToString(sum[:])
|
|
|
|
if !Verify(legacy, "oldpass") {
|
|
t.Fatal("历史密码应校验通过(兼容)")
|
|
}
|
|
if Verify(legacy, "other") {
|
|
t.Fatal("错误密码不应通过")
|
|
}
|
|
if !NeedsRehash(legacy) {
|
|
t.Fatal("历史密码应标记为需要重新哈希")
|
|
}
|
|
if AlgoOf(legacy) != AlgoLegacy {
|
|
t.Fatalf("算法标识应为 legacy,实际 %s", AlgoOf(legacy))
|
|
}
|
|
}
|
|
|
|
// TestDifferentSaltSamePassword 相同明文两次哈希结果必须不同(盐随机)
|
|
func TestDifferentSaltSamePassword(t *testing.T) {
|
|
a, _ := Hash("same-password")
|
|
b, _ := Hash("same-password")
|
|
if a == b {
|
|
t.Fatal("相同明文两次哈希不应相同(盐必须随机)")
|
|
}
|
|
if !Verify(a, "same-password") || !Verify(b, "same-password") {
|
|
t.Fatal("两份哈希都应能通过校验")
|
|
}
|
|
}
|
|
|
|
// TestEmptyPassword 空密码边界
|
|
func TestEmptyPassword(t *testing.T) {
|
|
if _, err := Hash(" "); err == nil {
|
|
t.Fatal("空密码应返回错误")
|
|
}
|
|
if Verify("", "x") || Verify("x", "") {
|
|
t.Fatal("空输入不应通过校验")
|
|
}
|
|
}
|