如何在 Java 代码中检查当前的 JVM 是否有无限强度的加密可用?
9 回答
本着与 Dan Cruz 的回答相同的精神,但只有一行代码并且没有遇到异常:
boolean limit = Cipher.getMaxAllowedKeyLength("RC5")<256;
所以一个完整的程序可能是:
import javax.crypto.Cipher;
public class TestUCE {
public static void main(String args[]) throws Exception {
boolean unlimited =
Cipher.getMaxAllowedKeyLength("RC5") >= 256;
System.out.println("Unlimited cryptography enabled: " + unlimited);
}
}
如果您在 Linux 上并且已经安装了 JDK(但 Beanshell 不可用),您可以使用runscript
JDK 提供的命令进行检查。
jrunscript -e 'exit (javax.crypto.Cipher.getMaxAllowedKeyLength("RC5") >= 256 ? 0 : 1);'; echo $?
0
如果 Unlimited Cryptography 可用或不可用,这将返回一个状态代码1
。零是 shell 函数的正确“成功”返回值,非零表示失败。
我认为您可能可以使用Cipher.getMaxAllowedKeyLength(),同时还将您使用的密码与已知的“好”、安全密码列表(例如 AES)进行比较。
这是一篇参考文章,列出了自 Java 1.4 起生效的最大密钥大小管辖权限制(这些可能没有改变,除非法律也改变了 - 见下文)。
如果您在一个有加密出口/进口限制的国家/地区开展业务,您必须咨询您所在国家/地区的法律,但在这些情况下可以安全地假设您没有可用的无限强度加密(默认情况下)在你的 JVM 中。换句话说,假设您使用的是Oracle 的官方 JVM,并且您碰巧生活在一个美国对密码学实施出口限制的国家(并且由于 Oracle 是一家美国公司,它会受到这些限制),那么你也可以假设在这种情况下你没有无限的力量可用。
当然,这并不能阻止您建立自己的,从而赋予自己无限的力量,但根据您当地的法律,这可能是非法的。
本文概述了从美国向其他国家出口的限制。
如何检查限制是否适用的方法记录在方法中Cipher.getMaxAllowedKeyLength
:
如果安装了 JCE 无限强度管辖策略文件,
Integer.MAX_VALUE
将被退回。
这意味着如果返回除(或实际上低于)以外的任何值,则Integer.MAX_VALUE
限制确实适用。
更多信息在以下方法的 JavaDoc 中:
/**
* Determines if cryptography restrictions apply.
* Restrictions apply if the value of {@link Cipher#getMaxAllowedKeyLength(String)} returns a value smaller than {@link Integer#MAX_VALUE} if there are any restrictions according to the JavaDoc of the method.
* This method is used with the transform <code>"AES/CBC/PKCS5Padding"</code> as this is an often used algorithm that is <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#impl">an implementation requirement for Java SE</a>.
*
* @return <code>true</code> if restrictions apply, <code>false</code> otherwise
*/
public static boolean restrictedCryptography() {
try {
return Cipher.getMaxAllowedKeyLength("AES/CBC/PKCS5Padding") < Integer.MAX_VALUE;
} catch (final NoSuchAlgorithmException e) {
throw new IllegalStateException("The transform \"AES/CBC/PKCS5Padding\" is not available (the availability of this algorithm is mandatory for Java SE implementations)", e);
}
}
请注意,自 Java 9 以来,默认安装了无限加密策略(受进出口法规影响的那些必须安装有限加密策略)。因此,此代码主要用于向后兼容性和/或其他运行时。
这是一个完整的复制粘贴版本,允许测试
import javax.crypto.Cipher;
import java.security.NoSuchAlgorithmException;
class Test {
public static void main(String[] args) {
int allowedKeyLength = 0;
try {
allowedKeyLength = Cipher.getMaxAllowedKeyLength("AES");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
System.out.println("The allowed key length for AES is: " + allowedKeyLength);
}
}
跑步
javac Test.java
java Test
如果 JCE 不工作输出:128
JCE 工作如下:2147483647
如果您使用的是 Linux,则可以使用此命令轻松检查
java -version ; \
echo 'System.err.println(javax.crypto.Cipher.getInstance("AES/CBC/PKCS5Padding").getMaxAllowedKeyLength("AES"));' \
| java -cp /usr/share/java/bsh-*.jar bsh.Interpreter >/dev/null
如果输出是这样的,则无限强度加密不可用
java version "1.7.0_76"
Java(TM) SE Runtime Environment (build 1.7.0_76-b13)
Java HotSpot(TM) 64-Bit Server VM (build 24.76-b04, mixed mode)
128
您可以使用 groovy 从命令行一步检查它:
groovysh -e 'javax.crypto.Cipher.getMaxAllowedKeyLength("AES")'
如果结果是2147483647
,则您拥有无限的密码学。
在旧版本的 groovy 上,您必须删除-e
:
groovysh 'javax.crypto.Cipher.getMaxAllowedKeyLength("AES")'
注意:请使用jefflunt 的答案或KonstantinSpirov 的答案。这个答案不是一个有效的答案,因为它总是会返回true
。我将这个答案留在这里只是因为它在答案和评论中的其他地方被引用并且仅作为参考有用。
您可以使用以下内容来初始化static final boolean
某个位置,然后您可以使用该位置来测试无限加密支持(因为仅在安装了不受限制的策略时才支持 AES 256 位)。
boolean isUnlimitedSupported = false;
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES", "SunJCE");
kgen.init(256);
isUnlimitedSupported = true;
} catch (NoSuchAlgorithmException e) {
isUnlimitedSupported = false;
} catch (NoSuchProviderException e) {
isUnlimitedSupported = false;
}
System.out.println("isUnlimitedSupported=" + isUnlimitedSupported);
// set static final variable = isUnlimitedSupported;
我最近不得不添加一个 JCE 检查,我的解决方案演变为以下代码段。这是一个 groovy 脚本,但它应该很容易通过 try catch 转换为标准 java 方法。这已经使用 Java 7 和 Java 8 进行了测试。
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.SecretKey;
// Make a blank 256 Bit AES Key
final SecretKey secretKey = new SecretKeySpec(new byte[32], "AES");
final Cipher encryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// This line will throw a invalid key length exception if you don't have
// JCE Unlimited strength installed
encryptCipher.init(Cipher.ENCRYPT_MODE, secretKey);
// If it makes it here, you have JCE installed