package comm import ( "strings" "testing" ) // 指纹的唯一用途是「两端比对」:实际 AES 密钥相同 → 指纹必相同;不同 → 指纹必不同。 func TestKeyFingerprint_同密钥同指纹_异密钥异指纹(t *testing.T) { a := KeyFingerprint("SzwdcXrtrmJMRZkZtQuzhAETOIJnFzMH") if a != KeyFingerprint("SzwdcXrtrmJMRZkZtQuzhAETOIJnFzMH") { t.Fatal("同一把 key 两次指纹不一致") } if a == KeyFingerprint("") { t.Fatal("真实 key 与空 key 指纹相同") } // 不得泄露密钥本身。 if strings.Contains(a, "Szwdc") { t.Fatalf("指纹泄露了密钥内容: %s", a) } } // normAESKey 截断到 32 字节:前 32 字节相同的两把 key 实为同一把 AES 密钥,指纹须相同, // 否则两端会因"指纹不同"去排查一个根本不存在的问题。 func TestKeyFingerprint_超长截断后等价(t *testing.T) { k32 := "SzwdcXrtrmJMRZkZtQuzhAETOIJnFzMH" // 恰好 32 字节 long := k32 + "这些字节根本不参与加密" if KeyFingerprint(k32) == KeyFingerprint(long) { // 指纹的哈希部分应相同(实际 AES key 相同),但备注不同,故比较哈希前缀。 t.Fatal("期望备注不同") } h1, h2 := strings.Fields(KeyFingerprint(k32))[0], strings.Fields(KeyFingerprint(long))[0] if h1 != h2 { t.Fatalf("前 32 字节相同的 key 实际 AES 密钥相同,指纹哈希应一致: %s vs %s", h1, h2) } if !strings.Contains(KeyFingerprint(long), "被丢弃") { t.Fatal("超长 key 应提示截断") } } func TestKeyFingerprint_标注常见事故(t *testing.T) { if !strings.Contains(KeyFingerprint(""), "未配置") { t.Error("空 key 应提示未配置") } if !strings.Contains(KeyFingerprint("short-key"), "补零") { t.Error("不足 32 字节应提示补零") } // .env 存成 CRLF 时,值尾部会多一个 \r,肉眼与正确值毫无差别。 if !strings.Contains(KeyFingerprint("SzwdcXrtrmJMRZkZtQuzhAETOIJnFzM\r"), "CR") { t.Error("尾部 CR 应被标注") } } // 事故复现:FIELD_ENCRYPT_KEY 进 env 模板之前,业务服务用空串(→全零密钥)把配置 seed 进了库。 // 后来 env 配上了真 key,解密失败——诊断必须指出"这是旧 key 加密的存量数据",而不是让人去查 env。 func TestDiagnoseDecryptFailure_识别空key加密的存量数据(t *testing.T) { const realKey = "SzwdcXrtrmJMRZkZtQuzhAETOIJnFzMH" legacyCT, err := Encrypt("", "wx-appsecret-plaintext") // 旧进程用空 key 加密 if err != nil { t.Fatal(err) } if _, err = Decrypt(realKey, legacyCT); err == nil { t.Fatal("前提不成立:真 key 不该能解开空 key 的密文") } d := DiagnoseDecryptFailure(realKey, legacyCT) if !strings.Contains(d, "全零密钥") { t.Errorf("应指认出空 key,实际: %s", d) } if strings.Contains(d, "wx-appsecret-plaintext") { t.Fatalf("诊断泄露了明文: %s", d) } } // .env 存成 CRLF:值尾部混入 \r,两端"看起来"配的是同一把 key,实际差一个字节。 func TestDiagnoseDecryptFailure_识别尾部CR(t *testing.T) { const clean = "SzwdcXrtrmJMRZkZtQuzhAETOIJnFzMH" ct, err := Encrypt(clean, "some-secret") if err != nil { t.Fatal(err) } d := DiagnoseDecryptFailure(clean+"\r", ct) // 本服务读到的 key 尾部多了 \r if !strings.Contains(d, "多余字符") { t.Errorf("应指认出尾部混入字符,实际: %s", d) } } func TestDiagnoseDecryptFailure_未知key不瞎猜(t *testing.T) { ct, err := Encrypt("some-unknown-key-nobody-has-seen", "x") if err != nil { t.Fatal(err) } if d := DiagnoseDecryptFailure("SzwdcXrtrmJMRZkZtQuzhAETOIJnFzMH", ct); !strings.Contains(d, "未知的 key") { t.Errorf("无线索时应如实说明,实际: %s", d) } }