密文格式是 1 字节版本加 16 字节 IV 加数据,代码解密时直接从第 0 字节当 IV 读,版本号被当成 IV 的一部分,旧数据解密出来全是乱码。乍看像缓存或者权限的锅,追下去往往不是。
xxd -l 24 old_cipher.bin grep -rn 'Cipher.getInstance' src/main/java/**/CryptoUtil.java
追下去是这么回事:加解密封装升级时只改了加密侧,解密侧还按旧布局读。版本号写了但没人读,等于没写。两边的偏移量在不同类里各写一份,改一处不影响另一处。
「密钥版本错配」这类改动最怕改一半,回滚脚本先准备好,再动生产。验证用真实数据走一遍,测试数据太干净,边界情况根本碰不到。
能分两步做的操作就别合成一步,中间看一眼返回值,出问题好判断。
具体做法是,把密文布局抽成一个类 读写都走同一套偏移量;解密先读版本号 再按版本选择密钥和 IV 偏移;补一条用旧版本密文解密的单测;拿一条历史数据实际解一次确认。
验收就看一点,历史密文解出正确明文 新写入的密文版本号是 2。
