使用BouncyCastle实现AES CMAC:是否需转换提供的密钥?
问题核心与解决方案
你的代码里最关键的错误是直接把十六进制密钥字符串按UTF-8编码转成字节数组,这完全不符合十六进制密钥的解析逻辑。32个字符的十六进制字符串对应16个字节(每2个十六进制字符代表1个字节),而你现在的做法是把每个字符单独转成UTF-8字节,相当于生成了32个字节的错误密钥,这必然和C#端的密钥不匹配,导致CMAC结果错误。
正确的密钥转换方式
你需要把十六进制字符串解码成对应二进制字节数组,而非直接编码。用BouncyCastle自带的Hex工具类就能快速实现:
import org.bouncycastle.util.encoders.Hex; // 替换原代码中的KeyParameter初始化逻辑 byte[] keyBytes = Hex.decode(KEY); KeyParameter parameter = new KeyParameter(keyBytes);
如果不想依赖BouncyCastle的Hex类,也可以手动实现十六进制转字节数组的方法:
public static byte[] hexToByteArray(String hexStr) { int len = hexStr.length(); byte[] result = new byte[len / 2]; for (int i = 0; i < len; i += 2) { result[i / 2] = (byte) ((Character.digit(hexStr.charAt(i), 16) << 4) + Character.digit(hexStr.charAt(i+1), 16)); } return result; }
关于Java byte有符号的问题
不用纠结Java byte是有符号、C#是无符号的差异——密码学算法处理的是字节的二进制原始值,符号只是语言层面的表示方式。比如C#里的0xFF(数值255)和Java里的(byte)0xFF(数值-1),二进制都是11111111,底层运算时完全等价。只要你的密钥字节数组和C#端的二进制值一致,计算出的CMAC结果就会相同。
修正密钥的转换方式后,再运行代码应该就能得到和C#端一致的签名结果了。
内容的提问来源于stack exchange,提问作者Antonio E.
相关产品推荐
相关产品推荐

