Есть несколько часто цитируемых решений этой проблемы. К сожалению, ни один из них не является полностью удовлетворительным:
- Установите файлы политики неограниченной силы . Хотя это, вероятно, правильное решение для вашей рабочей станции разработки, быстро становится главной проблемой (если не препятствием), чтобы пользователи, не являющиеся техническими специалистами, устанавливали файлы на каждом компьютере. Нет возможности распространять файлы с вашей программой; они должны быть установлены в каталоге JRE (который может быть доступен только для чтения из-за разрешений).
- Пропустите API JCE и используйте другую библиотеку криптографии, такую как Bouncy Castle . Этот подход требует дополнительной библиотеки 1 МБ, что может быть значительным бременем в зависимости от приложения. Также глупо дублировать функции, включенные в стандартные библиотеки. Очевидно, что API также полностью отличается от обычного интерфейса JCE. (BC действительно реализует JCE-провайдера, но это не помогает, потому что ограничения надежности ключа применяются перед передачей в реализацию.) Это решение также не позволит вам использовать 256-битные наборы шифров TLS (SSL), потому что стандартные библиотеки TLS вызывают JCE внутри, чтобы определить любые ограничения.
Но тогда есть отражение. Есть ли что-то, что вы не можете сделать с помощью отражения?
private 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);
final Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(isRestrictedField, isRestrictedField.getModifiers() & ~Modifier.FINAL);
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);
}
}
private static boolean isRestrictedCryptography() {
// This matches Oracle Java 7 and 8, but not Java 9 or OpenJDK.
final String name = System.getProperty("java.runtime.name");
final String ver = System.getProperty("java.version");
return name != null && name.equals("Java(TM) SE Runtime Environment")
&& ver != null && (ver.startsWith("1.7") || ver.startsWith("1.8"));
}
Просто позвоните removeCryptographyRestrictions()
из статического инициализатора или тому подобное, прежде чем выполнять какие-либо криптографические операции.
JceSecurity.isRestricted = false
Часть все , что необходимо для использования 256-битных шифров непосредственно; однако, без двух других операций, Cipher.getMaxAllowedKeyLength()
все равно будет продолжать сообщать 128, и 256-битные наборы шифров TLS не будут работать.
Этот код работает на Oracle Java 7 и 8 и автоматически пропускает процесс на Java 9 и OpenJDK там, где он не нужен. В конце концов, будучи уродливым хакером, он, вероятно, не работает на виртуальных машинах других производителей.
Это также не работает в Oracle Java 6, потому что частные классы JCE там запутаны. Однако запутывание не меняется от версии к версии, поэтому технически возможно поддерживать Java 6.