[JAVA special] JCE三种方法让AES支持256位keySize
以下内容转自:https://xiaoyao9184.wordpress.com/2015/12/15/java-special-jce-3-solution-4-aes-256bits-keysize/
[JAVA special] JCE三种方法让AES支持256位keySize
JCE
是JAVA中关于加密方面的标准。
来熟悉一个例子:
//byte[] key //byte[] iv //byte[] data Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); SecretKeySpec keyspec = new SecretKeySpec(key, "AES"); IvParameterSpec ivspec = new IvParameterSpec(iv); cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec); byte[] result = cipher.doFinal(data);
常见的问题
java.security.InvalidKeyException: Illegal key size or default parameters
正常情况下的Oracle JRE是对Key值长度有限制的,128位16字节,通过以下方法获取目前的KeySize限制。
int i = Cipher.getMaxAllowedKeyLength("AES/CBC/PKCS5Padding")) System.out.println(i);
解决方法
1、安装 Unlimited JCE Policy 文件
这个是网上最多的方法是,下载对应版本的 Unlimited JCE Policy 文件,替换原文件。下载地址jce7 jce8
{JAVA HOME}/lib/security/
例如开发环境的C:\Java\jdk1.7.0_79\jre\lib,部署环境的C:\Java\jre7\lib\security
也就是替换local_policy.jar、US_export_policy.jar这两个JAR文件。
优缺点:
你不能动态的通过代码来部署这2个文件,很有可能你本地开发时已经做了这个操作,但是部署时你忘记了。
2、使用第三方类库
例如Bouncy Castle,三方类库通常包含JCE标准实现,通过添加第三方Provider后使用JCE任然不能解决问题
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding", "BC");
因此必须使用BouncyCastle自己的对象编写解密过程
KeyParameter keyParam = new KeyParameter(key); CipherParameters params = new ParametersWithIV(keyParam, iv); BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESEngine()), new PKCS7Padding()); cipher.reset(); cipher.init(false, params); byte[] result = new byte[cipher.getOutputSize(data.length)]; int len = cipher.processBytes(data, 0, data.length, result, 0); len += cipher.doFinal(result, len);
优缺点:
仅仅通过引用JAR文件无须对JVM做操作,支持更多解码方式;需要重写JCE代码。
3、反射JCE移除限制
如果你发现解决方案1中的2个JAR文件里面没有代码,你就会明白 Unlimited JCE Policy 的作用仅仅相当于配置文件,标准JCE实现内部是支持更大key Size的。达到简单解决问题。
封装为Util类,方便以后使用
public class JCEUtil { private static Logger logger = Logger.getLogger(JCEUtil.class.getName()); /** * Remove Cryptography Restrictions * @author ntoskrnl * @see http://stackoverflow.com/questions/1179672/how-to-avoid-installing-unlimited-strength-jce-policy-files-when-deploying-an * * Sometime app need uses 256-bit AES encryption, * usually we need install “Unlimited Strength” JCE policy files, * or skip the JCE API and use another cryptography library such as Bouncy Castle. * * ! Use another cryptography library's JCEProvider cant skip key strength restrictions ! * So that code using reflection to change permissions without deploy any jar file. */ public static void removeCryptographyRestrictions() { if (!isRestrictedCryptography()) { logger.fine("Cryptography restrictions removal not needed"); return; } try { /* * Do the following, but with reflection to bypass access checks: * * JceSecurity.isRestricted = false; * JceSecurity.defaultPolicy.perms.clear(); * JceSecurity.defaultPolicy.add(CryptoAllPermission.INSTANCE); */ final Class<?> jceSecurity = Class.forName("javax.crypto.JceSecurity"); final Class<?> cryptoPermissions = Class.forName("javax.crypto.CryptoPermissions"); final Class<?> cryptoAllPermission = Class.forName("javax.crypto.CryptoAllPermission"); final Field isRestrictedField = jceSecurity.getDeclaredField("isRestricted"); isRestrictedField.setAccessible(true); isRestrictedField.set(null, false); final Field defaultPolicyField = jceSecurity.getDeclaredField("defaultPolicy"); defaultPolicyField.setAccessible(true); final PermissionCollection defaultPolicy = (PermissionCollection) defaultPolicyField.get(null); final Field perms = cryptoPermissions.getDeclaredField("perms"); perms.setAccessible(true); ((Map<?, ?>) perms.get(defaultPolicy)).clear(); final Field instance = cryptoAllPermission.getDeclaredField("INSTANCE"); instance.setAccessible(true); defaultPolicy.add((Permission) instance.get(null)); logger.fine("Successfully removed cryptography restrictions"); } catch (final Exception e) { logger.log(Level.WARNING, "Failed to remove cryptography restrictions", e); } } /** * Check JVM is Oracle JRE not OpenJDK * @author ntoskrnl * @see http://stackoverflow.com/questions/1179672/how-to-avoid-installing-unlimited-strength-jce-policy-files-when-deploying-an */ private static boolean isRestrictedCryptography() { // This simply matches the Oracle JRE, but not OpenJDK. return "Java(TM) SE Runtime Environment".equals(System.getProperty("java.runtime.name")); } }
优缺点:
无须添加JAR文件,无须部署文件到JVM。连带影响未知。
文章参考
The Legion of the Bouncy Castle
用Bouncy Castle作为Java的Security Provider
基于Java Bouncy Castle的PGP加密解密示例
How to avoid installing “Unlimited Strength” JCE policy files when deploying an application?