使用Java Crypto库无法匹配AES-GCM规范测试向量问题排查
问题排查与修正
你的核心问题大概率出在**stringToByteArray方法的实现**以及对Java AES-GCM输出结构的理解上,以下是具体分析和解决步骤:
1. 最可能的错误:stringToByteArray生成的不是全零字节数组
你假设stringToByteArray("0", 12)会生成12个0x00(全零)字节,但如果这个方法的逻辑是重复字符串"0"再转成字节,那实际生成的是12个0x30(ASCII字符'0'的十六进制值)。这会导致IV、密钥、AAD全部偏离测试向量的要求,只有最简单的无AAD、无明文的测试用例可能巧合匹配,一旦加入AAD就必然出错。
正确生成全零字节数组的方式应该是直接初始化:
// 生成length个0x00字节的数组 byte[] getZeroBytes(int length) { return new byte[length]; }
把测试用例里的stringToByteArray("0", N)替换成这个方法,比如:
GCMParameterSpec parameterSpec = new GCMParameterSpec(128, getZeroBytes(12)); SecretKeySpec secretKey = new SecretKeySpec(getZeroBytes(16), "AES"); byte[] aad = getZeroBytes(16);
2. 确认Java AES-GCM的输出结构
Java的Cipher.doFinal()返回的结果是密文 + 认证标签的拼接字节数组(GCM标签长度由GCMParameterSpec指定,这里是128位即16字节)。如果测试向量里的密文和标签是分开给出的,你需要把返回的cipherText拆分后分别对比:
- 若明文长度为0(比如你的测试用例),则
cipherText就是16字节的标签,直接和规范里的标签对比即可; - 若有明文,前
明文长度字节是密文,后16字节是标签。
3. 验证AAD的处理逻辑
你的测试用例2中updateAAD的调用时机是正确的(在init之后、doFinal之前),但要确保没有在调用updateAAD后意外重置Cipher状态(比如再次调用init)。
修正以上两点后,应该就能匹配GCM规范中的测试向量了。
内容的提问来源于stack exchange,提问作者Guy Hutchison
相关产品推荐
相关产品推荐

