[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加密提供者

Bouncy Castle加密包的分析(转)

Bouncy Castle Java 平台轻量级密码术包

基于Java Bouncy Castle的PGP加密解密示例

How to avoid installing “Unlimited Strength” JCE policy files when deploying an application?

 

 

posted on 2017-08-20 10:33  傻瓜乐园  阅读(2442)  评论(0编辑  收藏  举报

导航