<p>因为 a ^ b ^ b == a 恒成立,异或加解密操作完全对称,无需区分方向或额外缓冲区;C/C++ 中需逐字节原地异或,传入明确 size 避免 strlen 截断,推荐用 uint8_t* 指针防止符号扩展干扰。</p>

为什么异或能原地加解密
因为 a ^ b ^ b == a 恒成立,只要密钥 b 不变,对同一块内存连续做两次 ^ b 操作,数据就自动还原。不需要额外缓冲区,也不用判断加解密方向——操作完全对称。
如何在 C/C++ 中对 char 数组原地异或
关键点是逐字节遍历并直接修改原内存,不能越界、不能忽略空字符(\0)是否参与运算(取决于需求)。常见错误是把字符串长度误用为 strlen() 结果而跳过末尾 \0,导致解密后字符串截断。
- 若需加密整个内存块(含二进制零),必须传入明确的
size参数,不能依赖strlen() - 密钥可以是单字节(如
0x5a),也可以是多字节循环使用(如const uint8_t key[] = {0x12, 0x34, 0x56}) - 使用
uint8_t*指针而非char*更安全,避免符号扩展干扰(尤其当字节值 > 0x7f 时)
Java 中对 byte[] 原地异或的注意事项
Java 没有指针,但 byte[] 是可变对象,可以直接原地修改。容易踩的坑是:Java 的 byte 是有符号类型(-128 ~ 127),而异或结果可能超出该范围,但 JVM 会自动截断低 8 位,所以行为正确——你只需确保密钥也用 byte 或强制 & 0xFF 处理。
- 错误写法:
data[i] = (byte)(data[i] ^ 0xff)——0xff是 int,先提升为 int 再异或,再强转,易出错 - 推荐写法:
data[i] ^= keyByte(如果keyByte是byte)或data[i] ^= (byte)0xff - 多字节密钥循环时,用
key[i % key.length],别用i & (key.length - 1)(除非长度是 2 的幂)
原地异或在文件内存映射中的典型误用
当用 mmap()(Linux/macOS)或 CreateFileMapping()(Windows)把文件映射到内存后,直接对映射区域做异或看似高效,但有隐藏风险:
- 操作系统可能以页为单位刷新,若异或中途崩溃,部分页已写回磁盘、部分未写,文件损坏
- 没有原子性保证:无法确保“全加密成功”或“全不加密”,失败后难以回滚
- 若映射时用了
MAP_PRIVATE,异或操作不会落盘——改的是副本,不是原文件
真正安全的做法是:先 MAP_SHARED 映射,加密前调用 msync(..., MS_SYNC) 确保当前内容已刷盘;或者干脆不用 mmap,读入内存块 → 异或 → 写回,更可控。

















