- 只翻注释/文档字符串:剥掉行尾注释后,每条「-」都有逐字节相同的「+」对应行(8 组,代码零改动) - 保留协议/线上标识符原文:errcode、bot_token、context_token、getupdates、binded_redirect、PKCS#7、ECB 等 - 术语对齐既有译法:owner→主人、peer→对端、long poll→长轮询、backoff→退避、sentinel error→哨兵错误 - 已知既有欠债(未顺手修):login_reuse_test.go 在 HEAD 上就未 gofmt 干净;login_test.go 的 TestStartLogin_ScanStatusTransition 91 行 >80(HEAD 同为 91 行)
110 lines
3.3 KiB
Go
110 lines
3.3 KiB
Go
package weixin_ilink
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/aes"
|
|
"errors"
|
|
"strconv"
|
|
"testing"
|
|
)
|
|
|
|
func TestAESECB_RoundTrip_AllBlockBoundaries(t *testing.T) {
|
|
t.Parallel()
|
|
key := bytes.Repeat([]byte{0x42}, aes.BlockSize)
|
|
// 覆盖长度 0 到刚过两个分组的范围(填充边界情况)。
|
|
for n := 0; n <= 2*aes.BlockSize+5; n++ {
|
|
n := n
|
|
t.Run("len="+strconv.Itoa(n), func(t *testing.T) {
|
|
t.Parallel()
|
|
pt := bytes.Repeat([]byte{0xAB}, n)
|
|
ct, err := aesECBEncrypt(key, pt)
|
|
if err != nil {
|
|
t.Fatalf("aesECBEncrypt: %v", err)
|
|
}
|
|
got, err := aesECBDecrypt(key, ct)
|
|
if err != nil {
|
|
t.Fatalf("aesECBDecrypt: %v", err)
|
|
}
|
|
if !bytes.Equal(got, pt) {
|
|
t.Fatalf("round trip mismatch: got %x want %x", got, pt)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAESECB_EncryptPadsToBlockSize(t *testing.T) {
|
|
t.Parallel()
|
|
key := bytes.Repeat([]byte{1}, aes.BlockSize)
|
|
ct, err := aesECBEncrypt(key, []byte("abc")) // 3 字节 -> 填充后 16 字节
|
|
if err != nil {
|
|
t.Fatalf("aesECBEncrypt: %v", err)
|
|
}
|
|
if len(ct) != aes.BlockSize {
|
|
t.Fatalf("ciphertext = %d bytes, want %d", len(ct), aes.BlockSize)
|
|
}
|
|
// 整块输入 -> 追加一个填充块。
|
|
ct2, err := aesECBEncrypt(key, bytes.Repeat([]byte{0}, aes.BlockSize))
|
|
if err != nil {
|
|
t.Fatalf("aesECBEncrypt: %v", err)
|
|
}
|
|
if len(ct2) != 2*aes.BlockSize {
|
|
t.Fatalf("full-block ciphertext = %d bytes, want %d", len(ct2), 2*aes.BlockSize)
|
|
}
|
|
}
|
|
|
|
func TestAESECB_DecryptRejectsBadLength(t *testing.T) {
|
|
t.Parallel()
|
|
key := bytes.Repeat([]byte{2}, aes.BlockSize)
|
|
cases := []int{0, 5, aes.BlockSize - 1, aes.BlockSize + 1}
|
|
for _, n := range cases {
|
|
n := n
|
|
t.Run("len="+strconv.Itoa(n), func(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := aesECBDecrypt(key, make([]byte, n))
|
|
if !errors.Is(err, ErrBadCiphertext) {
|
|
t.Fatalf("err = %v, want ErrBadCiphertext", err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAESECB_DecryptRejectsBadPadding(t *testing.T) {
|
|
t.Parallel()
|
|
key := bytes.Repeat([]byte{3}, aes.BlockSize)
|
|
// 一个分组、填充正确(0x10)的合法密文……
|
|
good, err := aesECBEncrypt(key, bytes.Repeat([]byte{4}, aes.BlockSize-1))
|
|
if err != nil {
|
|
t.Fatalf("aesECBEncrypt: %v", err)
|
|
}
|
|
// ……然后篡改末尾填充字节,使填充校验必然失败。
|
|
bad := append([]byte(nil), good...)
|
|
bad[len(bad)-1] ^= 0xFF
|
|
_, err = aesECBDecrypt(key, bad)
|
|
if !errors.Is(err, ErrBadCiphertext) {
|
|
t.Fatalf("err = %v, want ErrBadCiphertext", err)
|
|
}
|
|
}
|
|
|
|
func TestAESECB_KeySizesAccepted(t *testing.T) {
|
|
t.Parallel()
|
|
// AES-128 需要 16 字节密钥。验证超范围的密钥会被拒绝。
|
|
if _, err := aesECBEncrypt(bytes.Repeat([]byte{1}, aes.BlockSize-1), []byte("x")); err == nil {
|
|
t.Fatal("short key: expected error, got nil")
|
|
}
|
|
if _, err := aesECBEncrypt(bytes.Repeat([]byte{1}, aes.BlockSize+1), []byte("x")); err == nil {
|
|
t.Fatal("long key: expected error, got nil")
|
|
}
|
|
}
|
|
|
|
func TestPKCS7_UnpadRejectsInvalid(t *testing.T) {
|
|
t.Parallel()
|
|
// 填充字节多于一个分组。
|
|
if _, err := pkcs7Unpad([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17}, 16); !errors.Is(err, ErrBadCiphertext) {
|
|
t.Fatalf("oversize pad: err = %v, want ErrBadCiphertext", err)
|
|
}
|
|
// 填充字节为 0 永远非法。
|
|
if _, err := pkcs7Unpad([]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0}, 16); !errors.Is(err, ErrBadCiphertext) {
|
|
t.Fatalf("zero pad: err = %v, want ErrBadCiphertext", err)
|
|
}
|
|
}
|