异或加密不能直接对字符串逐字节操作,因go中string不可变且utf-8多字节字符会被拆解导致乱码;应操作[]byte或rune,并对密文base64/hex编码以确保可传输与存储。

异或加密为什么不能直接用 ^ 对字符串逐字节操作?
因为 Go 的 string 是只读的字节序列,不能直接通过索引赋值;想“修改”字符串必须转成 []byte。另外,string 底层是 UTF-8 编码,如果原始内容含中文或 emoji,直接按字节异或会导致解密后乱码——不是算法错了,而是你把多字节字符拆开了。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 始终对
[]byte操作,加密后用string()转回(仅当确认输入是纯 ASCII 或你明确接受 UTF-8 字节级混淆时才安全) - 若需支持任意 Unicode 文本,先用
utf8.DecodeRuneInString拆成rune,再对每个rune做异或(注意:rune 是 int32,异或后可能超出有效 Unicode 范围,得做掩码处理,比如r ^ key & 0x10FFFF) - 更稳妥的做法:统一转 base64 或 hex 编码后再异或字节,避免编码歧义
如何让自定义异或密钥支持可变长度且不暴露明文规律?
固定单字节密钥(比如 key := byte(42))一查频次就露馅;而直接重复密钥(如 “abc” → “abcabcabc…”)在密文里会留下周期性特征,容易被统计分析击破。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 用
crypto/rand.Read生成与原文等长的随机密钥字节 slice,再异或——这是最简但安全的做法(密钥需随密文一起保存或传输) - 若不想存密钥,改用
sha256.Sum256对口令 + 盐(salt)哈希,取前len(src)字节作为密钥流(注意:哈希输出固定 32 字节,超长需循环或扩展) - 别手写密钥调度逻辑,比如 “key[i%len(key)] ^ i”,这种确定性模式在 CTF 题里第一轮就被识别出来
xor.Encrypt 和 xor.Decrypt 能写成同一个函数吗?
能,而且应该这么做。异或的数学性质是:a ^ b ^ b == a,所以加解密逻辑完全一致——传入原文和密钥流,返回异或结果。所谓“加密”“解密”只是语义区别,底层没差异。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 只写一个函数,比如
func Xor(data, key []byte) []byte,避免复制粘贴导致两处逻辑不一致 - 如果密钥长度不足,补足方式要统一:推荐用
bytes.Repeat或循环取模,别在 Encrypt 里用填充、Decrypt 里用截断 - 测试时用同一组
data和key连续调用两次:Xor(Xor(data, key), key)必须严格等于原data
混淆后的字符串还能直接打印或写入 JSON 吗?
大概率不行。异或后的字节流大概率包含 \x00、\x08、\x1F 等控制字符,甚至 \x7F 以上无效 UTF-8 序列。Go 的 fmt.Println 会显示 ,json.Marshal 则直接报错 invalid UTF-8。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 输出前必须编码:选
base64.StdEncoding.EncodeToString(推荐)或hex.EncodeToString,二者都保证可逆且无非法字符 - 如果坚持用原始字节,只能存二进制文件(
ioutil.WriteFile)或数据库 blob 字段,别碰文本协议 - 别在日志里直接打
string(cipherBytes)—— 看似方便,实则掩盖了乱码问题,后续调试全靠猜
真正麻烦的不是写对异或,而是怎么让结果“能用”:它得能存、能传、能读,还不引入新漏洞。这些边界情况,往往在第一次往 config.json 里塞密文时才突然跳出来。










