Android中SecretKey与String互转及Unsupported key size异常处理
AES SecretKey 与 String 互相转换的正确方案
你日志输出不一致的核心原因是:Java 中数组的toString()方法并不会输出数组内的实际内容,而是输出「数组类型@内存哈希值」格式的对象标识。你代码里的key.getEncoded()和keyCopy.getEncoded()是两个独立的字节数组对象,哪怕内容完全相同,调用toString()得到的结果也一定不一样。要验证两个密钥内容是否一致,应该用Arrays.equals(key.getEncoded(), keyCopy.getEncoded())对比字节内容,或者把字节数组转成Base64/十六进制字符串后再对比。
你之前出现Unsupported key size: 43 bytes异常,是因为错误调用了key.getEncoded().toString().getBytes():key.getEncoded()返回的是32字节的256位AES密钥,调用toString()得到的是类似[B@1234567长度为43的字符串,再调用getBytes()得到的就是43字节的数组,完全和原始密钥内容无关,长度不符合AES的密钥要求,自然会抛异常。
正确转换步骤
1. SecretKey 转可存储的 String
必须用Base64或者十六进制编码把二进制的密钥字节数组转成可打印的字符串,不要直接做字节和字符串的强制转换,示例代码(安卓环境,JDK环境可以用java.util.Base64工具类):
// 生成256位AES原始密钥 KeyGenerator keyGen = KeyGenerator.getInstance("AES"); keyGen.init(256); SecretKey originalKey = keyGen.generateKey(); // 二进制密钥字节转Base64编码字符串,用于持久化存储 byte[] originalKeyBytes = originalKey.getEncoded(); String storedKey = Base64.encodeToString(originalKeyBytes, Base64.NO_WRAP);
2. String 转回 SecretKey 对象
把存储的Base64字符串解码回原始的密钥字节数组,再用SecretKeySpec包装成SecretKey对象即可:
// 解码Base64字符串得到原始密钥字节 byte[] decodedKeyBytes = Base64.decode(storedKey, Base64.NO_WRAP); SecretKey restoredKey = new SecretKeySpec(decodedKeyBytes, "AES");
注意事项
- 256位AES密钥需要JDK内置无限制政策文件支持,部分低版本JDK默认不支持256位AES,需要单独替换政策文件或者升级JDK版本
- Base64编码时建议加
NO_WRAP参数,避免生成带换行符的字符串,存储或者传输时出现额外问题 - 密钥属于敏感信息,不要明文存储在本地,建议加密后再持久化
内容的提问来源于stack exchange,提问作者mystack
相关产品推荐
相关产品推荐

