unlimited strength jurisdiction instalar files extension downloads como java aes jce policyfiles

strength - jce java 8



¿Cómo evitar la instalación de archivos de política de JCE "Fortaleza ilimitada" al implementar una aplicación? (11)

Tengo una aplicación que usa cifrado AES de 256 bits que no es compatible con Java de fábrica. Sé que para que esto funcione correctamente instalo los frascos de fuerza ilimitada JCE en la carpeta de seguridad. Esto está bien para mí como desarrollador, puedo instalarlos.

Mi pregunta es que, dado que esta aplicación se distribuirá, es probable que los usuarios finales no tengan instalados estos archivos de políticas. Hacer que el usuario final descargue estos solo para hacer que la aplicación funcione no es una solución atractiva.

¿Hay alguna manera de hacer que mi aplicación se ejecute sin sobrescribir los archivos en la máquina del usuario final? ¿Un software de terceros que puede manejarlo sin los archivos de política instalados? ¿O una forma de simplemente referenciar estos archivos de políticas desde dentro de un JAR?


A partir de JDK 8u102, las soluciones publicadas que dependen de la reflexión ya no funcionarán: el campo que establecen estas soluciones ahora es final ( bugs.openjdk.java.net/browse/JDK-8149417 ).

Parece que se trata de (a) utilizar Bouncy Castle o (b) instalar los archivos de políticas de JCE.


Aquí hay una solución: http://middlesphere-1.blogspot.ru/2014/06/this-code-allows-to-break-limit-if.html

//this code allows to break limit if client jdk/jre has no unlimited policy files for JCE. //it should be run once. So this static section is always execute during the class loading process. //this code is useful when working with Bouncycastle library. static { try { Field field = Class.forName("javax.crypto.JceSecurity").getDeclaredField("isRestricted"); field.setAccessible(true); field.set(null, java.lang.Boolean.FALSE); } catch (Exception ex) { } }


Aquí hay una versión actualizada de la respuesta ntoskrnl . También contiene una función para eliminar el modificador final como Arjan mencionado en los comentarios.

Esta versión funciona con JRE 8u111 o más reciente.

private static void removeCryptographyRestrictions() { if (!isRestrictedCryptography()) { 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"); Field isRestrictedField = jceSecurity.getDeclaredField("isRestricted"); isRestrictedField.setAccessible(true); setFinalStatic(isRestrictedField, 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)); } catch (final Exception e) { e.printStackTrace(); } } static void setFinalStatic(Field field, Object newValue) throws Exception { field.setAccessible(true); Field modifiersField = Field.class.getDeclaredField("modifiers"); modifiersField.setAccessible(true); modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); field.set(null, newValue); } 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")); }


Aquí hay una versión modificada del código de @ ntoskrnl que isRestrictedCryptography comprobación isRestrictedCryptography por Cipher.getMaxAllowedKeyLength real , registro slf4j y soporte de inicialización singleton desde el arranque de la aplicación como este:

static { UnlimitedKeyStrengthJurisdictionPolicy.ensure(); }

Este código dejaría de funcionar correctamente con la reflexión cuando la política ilimitada esté disponible de forma predeterminada en Java 8u162, como predice la respuesta de @cranphin.

import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.crypto.Cipher; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.security.NoSuchAlgorithmException; import java.security.Permission; import java.security.PermissionCollection; import java.util.Map; // https://.com/questions/1179672/how-to-avoid-installing-unlimited-strength-jce-policy-files-when-deploying-an public class UnlimitedKeyStrengthJurisdictionPolicy { private static final Logger log = LoggerFactory.getLogger(UnlimitedKeyStrengthJurisdictionPolicy.class); private static boolean isRestrictedCryptography() throws NoSuchAlgorithmException { return Cipher.getMaxAllowedKeyLength("AES/ECB/NoPadding") <= 128; } private static void removeCryptographyRestrictions() { try { if (!isRestrictedCryptography()) { log.debug("Cryptography restrictions removal not needed"); return; } /* * Do the following, but with reflection to bypass access checks: * * JceSecurity.isRestricted = false; * JceSecurity.defaultPolicy.perms.clear(); * JceSecurity.defaultPolicy.add(CryptoAllPermission.INSTANCE); */ Class<?> jceSecurity = Class.forName("javax.crypto.JceSecurity"); Class<?> cryptoPermissions = Class.forName("javax.crypto.CryptoPermissions"); Class<?> cryptoAllPermission = Class.forName("javax.crypto.CryptoAllPermission"); Field isRestrictedField = jceSecurity.getDeclaredField("isRestricted"); isRestrictedField.setAccessible(true); Field modifiersField = Field.class.getDeclaredField("modifiers"); modifiersField.setAccessible(true); modifiersField.setInt(isRestrictedField, isRestrictedField.getModifiers() & ~Modifier.FINAL); isRestrictedField.set(null, false); Field defaultPolicyField = jceSecurity.getDeclaredField("defaultPolicy"); defaultPolicyField.setAccessible(true); PermissionCollection defaultPolicy = (PermissionCollection) defaultPolicyField.get(null); Field perms = cryptoPermissions.getDeclaredField("perms"); perms.setAccessible(true); ((Map<?, ?>) perms.get(defaultPolicy)).clear(); Field instance = cryptoAllPermission.getDeclaredField("INSTANCE"); instance.setAccessible(true); defaultPolicy.add((Permission) instance.get(null)); log.info("Successfully removed cryptography restrictions"); } catch (Exception e) { log.warn("Failed to remove cryptography restrictions", e); } } static { removeCryptographyRestrictions(); } public static void ensure() { // just force loading of this class } }



Durante la instalación de su programa, simplemente solicite al usuario y haga que un script de Lote de DOS o un script de shell Bash descarguen y copien el JCE en la ubicación correcta del sistema.

Solía ​​tener que hacer esto para un servicio web de servidor y en lugar de un instalador formal, solo proporcioné scripts para configurar la aplicación antes de que el usuario pudiera ejecutarla. Puede hacer que la aplicación no se pueda ejecutar hasta que ejecute el script de instalación. También podría hacer que la aplicación se queje de que falta la JCE y luego solicitar descargar y reiniciar la aplicación.


Esto ya no es necesario para Java 9 , ni para ninguna versión reciente de Java 6, 7 u 8. ¡Finalmente! :)

Según JDK-8170157 , la política criptográfica ilimitada ahora está habilitada de forma predeterminada.

Versiones específicas del problema JIRA:

  • Java 9: ​​¡Cualquier lanzamiento oficial!
  • Java 8u161 o posterior (disponible ahora )
  • Java 7u171 o posterior (solo disponible a través de ''My Oracle Support'')
  • Java 6u181 o posterior (solo disponible a través de ''My Oracle Support'')

Tenga en cuenta que si por algún motivo extraño el antiguo comportamiento es necesario en Java 9, se puede configurar mediante:

Security.setProperty("crypto.policy", "limited");


Hay un par de soluciones comúnmente citadas para este problema. Desafortunadamente, ninguno de estos es totalmente 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 gran molestia (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; se deben instalar en el directorio JRE (que incluso puede ser de solo lectura debido a permisos).
  • Omita la API de JCE y use otra biblioteca de criptografía como Bouncy Castle . Este enfoque requiere una biblioteca adicional de 1MB, que puede ser una carga significativa según 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 de JCE, pero eso no ayuda porque las restricciones de fuerza clave se aplican antes de entregarlas a la implementación). Esta solución tampoco le permitirá usar conjuntos de cifrado TLS (SSL) de 256 bits, porque el las bibliotecas estándar de TLS llaman a la JCE internamente para determinar cualquier restricción.

Pero luego está el reflejo. ¿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 a removeCryptographyRestrictions() desde un inicializador estático o removeCryptographyRestrictions() antes de realizar cualquier operación criptográfica.

La parte JceSecurity.isRestricted = false es todo lo que se necesita para usar cifrados de 256 bits directamente; sin embargo, sin las otras dos operaciones, Cipher.getMaxAllowedKeyLength() seguirá informando 128, y las suites 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. Siendo un hack 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 todavía es técnicamente posible admitir Java 6.


Para nuestra aplicación, teníamos una arquitectura de servidor de cliente y solo permitíamos descifrar / cifrar datos en el nivel del servidor. Por lo tanto, los archivos JCE solo se necesitan allí.

Tuvimos otro problema donde necesitábamos actualizar un jar de seguridad en las máquinas del cliente, a través de JNLP, sobrescribe las bibliotecas en ${java.home}/lib/security/ y la JVM en la primera ejecución.

Eso lo hizo funcionar.


Para una biblioteca de criptografía alternativa, eche un vistazo a Bouncy Castle . Tiene AES y mucha funcionalidad agregada. Es una biblioteca liberal de código abierto. Sin embargo, tendrás que usar la API ligera y patentada de Bouncy Castle para que funcione.


Puedes usar el método

javax.crypto.Cipher.getMaxAllowedKeyLength(String transformation)

Para probar la longitud de clave disponible, úselo e informe al usuario sobre lo que está sucediendo. Algo que indica que su aplicación se está replegando a claves de 128 bits debido a que los archivos de política no se han instalado, por ejemplo. Los usuarios conscientes de la seguridad instalarán los archivos de la política, otros continuarán usando claves más débiles.