如何用org.apache.commons.codec.binary.Base64替换android.util.Base64?
How to replace android.util.Base64 by org.apache.commons.codec.binary.Base64?
我正在将我的原生 Android 游戏迁移到 libGDX。所以我无法再访问 Android 库,我正在尝试用 org.apache.commons.codec.binary.Base64
替换 android.util.Base64
。 (我需要 Base64 的 encodeToString
和 decode
方法。)
不幸的是,使用新包时出现此错误:
java.security.InvalidKeyException: Illegal key size
(使用与之前相同的 24 个字符的密钥)。
在 Whosebug 上 they say 可能是因为缺少 "Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 7"。但是如果我使用它们,我的应用程序的用户也必须安装它们。
有没有更简单的解决方案?为什么以前有效?
编辑:
这是导致 InvalidKeyException
:
的代码
javax.crypto.Cipher writer = Cipher.getInstance("AES/CBC/PKCS5Padding");
String keyOf24Chars = "abcdefghijklmnopqrstuvwx";
IvParameterSpec ivSpec = getIv();
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.reset();
byte[] keyBytes = md.digest(keyOf24Chars.getBytes("UTF-8"));
SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES/CBC/PKCS5Padding");
// secretKey.getAlgorithm(): "AES/CBC/PKCS5Padding"
// secretKey.getFormat(): "RAW"
// secretKey.getEncoded().length: 32
writer.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec); // java.security.InvalidKeyException: Illegal key size
编辑 2:
正如 Maarten Bodewes 的评论中所解释的,Android 有自己的 java
和 javax
类 实现,这显然对 32 字节密钥没有问题。在我安装 "JCE Unlimited Strength Jurisdiction Policy Files 7" 之后,我们将看到使用 Base64
并导致此错误的代码:java.lang.NoSuchMethodError: org.apache.commons.codec.binary.Base64.encodeToString
:
String valueToEncode = "xyz";
byte[] secureValue;
try {
secureValue = writer.doFinal(valueToEncode.getBytes("UTF-8"));
} catch (Exception e) {
throw new SecurePreferencesException(e);
}
Base64 base64 = new Base64();
String secureValueEncoded = base64.encodeToString(secureValue);
但是这种方法确实存在(在 Base64
扩展的 BaseNCodec
中):
public String encodeToString(final byte[] pArray) {
return StringUtils.newStringUtf8(encode(pArray));
}
如何让Android使用这个方法?
编辑 3:
最后我通过编写一个接口然后使用我的旧 Android 代码(为 Android 编译时)解决了我的问题。检查 libGDX 这个例子:Interfacing with platform specific code.
不,没有更简单的解决方案。您可以使用 3DES 而不是 AES(我假设您正在使用),但您会降低安全性,并且仍然与以前的代码不兼容。将 AES 的安全性降级到 128 是一个更好的主意,但不兼容问题不会消失。
如果您没有在第三方库中使用 encryption/decryption(例如用于 SSL 的 JSSE 或 XML 加密),那么您可以直接使用 Bouncy Castle 或 Spongy Castle API的。所以这意味着直接使用 AESBlockCipher
+ 一种加密方式。 Bouncy Castle 没有这些限制 - 它们是 Oracle Cipher
实现的一部分。
它之前是有效的,因为 Android 没有这些限制,而 Java 7/8 SE 有。
我正在将我的原生 Android 游戏迁移到 libGDX。所以我无法再访问 Android 库,我正在尝试用 org.apache.commons.codec.binary.Base64
替换 android.util.Base64
。 (我需要 Base64 的 encodeToString
和 decode
方法。)
不幸的是,使用新包时出现此错误:
java.security.InvalidKeyException: Illegal key size
(使用与之前相同的 24 个字符的密钥)。
在 Whosebug 上 they say 可能是因为缺少 "Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 7"。但是如果我使用它们,我的应用程序的用户也必须安装它们。
有没有更简单的解决方案?为什么以前有效?
编辑:
这是导致 InvalidKeyException
:
javax.crypto.Cipher writer = Cipher.getInstance("AES/CBC/PKCS5Padding");
String keyOf24Chars = "abcdefghijklmnopqrstuvwx";
IvParameterSpec ivSpec = getIv();
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.reset();
byte[] keyBytes = md.digest(keyOf24Chars.getBytes("UTF-8"));
SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES/CBC/PKCS5Padding");
// secretKey.getAlgorithm(): "AES/CBC/PKCS5Padding"
// secretKey.getFormat(): "RAW"
// secretKey.getEncoded().length: 32
writer.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec); // java.security.InvalidKeyException: Illegal key size
编辑 2:
正如 Maarten Bodewes 的评论中所解释的,Android 有自己的 java
和 javax
类 实现,这显然对 32 字节密钥没有问题。在我安装 "JCE Unlimited Strength Jurisdiction Policy Files 7" 之后,我们将看到使用 Base64
并导致此错误的代码:java.lang.NoSuchMethodError: org.apache.commons.codec.binary.Base64.encodeToString
:
String valueToEncode = "xyz";
byte[] secureValue;
try {
secureValue = writer.doFinal(valueToEncode.getBytes("UTF-8"));
} catch (Exception e) {
throw new SecurePreferencesException(e);
}
Base64 base64 = new Base64();
String secureValueEncoded = base64.encodeToString(secureValue);
但是这种方法确实存在(在 Base64
扩展的 BaseNCodec
中):
public String encodeToString(final byte[] pArray) {
return StringUtils.newStringUtf8(encode(pArray));
}
如何让Android使用这个方法?
编辑 3:
最后我通过编写一个接口然后使用我的旧 Android 代码(为 Android 编译时)解决了我的问题。检查 libGDX 这个例子:Interfacing with platform specific code.
不,没有更简单的解决方案。您可以使用 3DES 而不是 AES(我假设您正在使用),但您会降低安全性,并且仍然与以前的代码不兼容。将 AES 的安全性降级到 128 是一个更好的主意,但不兼容问题不会消失。
如果您没有在第三方库中使用 encryption/decryption(例如用于 SSL 的 JSSE 或 XML 加密),那么您可以直接使用 Bouncy Castle 或 Spongy Castle API的。所以这意味着直接使用 AESBlockCipher
+ 一种加密方式。 Bouncy Castle 没有这些限制 - 它们是 Oracle Cipher
实现的一部分。
它之前是有效的,因为 Android 没有这些限制,而 Java 7/8 SE 有。