Існує пара загально цитованих рішень цієї проблеми. На жаль, жодне з них не є цілком задовільним:
- Встановіть файли політики необмеженої міцності . Хоча це, мабуть, правильне рішення для вашої робочої станції з розробки, це швидко стає головним клопотом (якщо не дорожнім блоком), щоб не-технічні користувачі встановлювали файли на кожному комп’ютері. Немає способу розповсюдження файлів у вашій програмі; вони повинні бути встановлені в каталозі JRE (який може бути доступним лише для читання через дозволи).
- Пропустіть API JCE та використовуйте іншу бібліотеку криптовалют, таку як Замок Bouncy . Цей підхід вимагає додаткової бібліотеки на 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 там, де це не потрібно. Зрештою, це некрасивий хакер, він, ймовірно, не працює на VM інших постачальників.
Він також не працює на Oracle Java 6, оскільки там закриваються приватні класи JCE. Обфускація не змінюється від версії до версії, тому технічно можливо підтримувати Java 6.