Hay un par de soluciones comúnmente citadas para este problema. Lamentablemente, ninguno de estos es completamente satisfactorio:
- Instale los archivos de política de fuerza ilimitada . Si bien esta es probablemente la solución adecuada para su estación de trabajo de desarrollo, rápidamente se convierte en una molestia importante (si no un obstáculo) que los usuarios no técnicos instalen los archivos en cada computadora. No hay forma de distribuir los archivos con su programa; deben instalarse en el directorio JRE (que incluso puede ser de solo lectura debido a los permisos).
- Omita la API de JCE y use otra biblioteca de criptografía como Bouncy Castle . Este enfoque requiere una biblioteca adicional de 1 MB, que puede ser una carga significativa dependiendo de la aplicación. También se siente tonto duplicar la funcionalidad incluida en las bibliotecas estándar. Obviamente, la API también es completamente diferente de la interfaz JCE habitual. (BC implementa un proveedor JCE, pero eso no ayuda porque las restricciones de fuerza clave se aplican antes de entregar la implementación). Esta solución tampoco le permitirá usar conjuntos de cifrado TLS (SSL) de 256 bits, porque Las bibliotecas TLS estándar llaman al JCE internamente para determinar cualquier restricción.
Pero luego está la reflexión. ¿Hay algo que no puedas hacer usando la reflexión?
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"));
}
Simplemente llame removeCryptographyRestrictions()
desde un inicializador estático o similar antes de realizar cualquier operación criptográfica.
La JceSecurity.isRestricted = false
parte es todo lo que se necesita para usar cifrados de 256 bits directamente; sin embargo, sin las otras dos operaciones, Cipher.getMaxAllowedKeyLength()
seguirá reportando 128, y los conjuntos de cifrado TLS de 256 bits no funcionarán.
Este código funciona en Oracle Java 7 y 8, y omite automáticamente el proceso en Java 9 y OpenJDK donde no es necesario. Al ser un truco feo después de todo, es probable que no funcione en las máquinas virtuales de otros proveedores.
Tampoco funciona en Oracle Java 6, porque las clases privadas de JCE están ofuscadas allí. Sin embargo, la ofuscación no cambia de una versión a otra, por lo que técnicamente es posible admitir Java 6.