Il existe quelques solutions couramment citées à ce problème. Malheureusement, aucun de ces éléments n'est entièrement satisfaisant:
- Installez les fichiers de stratégie de force illimitée . Bien que ce soit probablement la bonne solution pour votre poste de travail de développement, il devient rapidement un problème majeur (sinon un obstacle) que des utilisateurs non techniques installent les fichiers sur chaque ordinateur. Il n'y a aucun moyen de distribuer les fichiers avec votre programme; ils doivent être installés dans le répertoire JRE (qui peut même être en lecture seule en raison des autorisations).
- Ignorez l'API JCE et utilisez une autre bibliothèque de cryptographie telle que Bouncy Castle . Cette approche nécessite une bibliothèque supplémentaire de 1 Mo, ce qui peut représenter une charge importante en fonction de l'application. Il semble également ridicule de dupliquer les fonctionnalités incluses dans les bibliothèques standard. De toute évidence, l'API est également complètement différente de l'interface JCE habituelle. (BC implémente un fournisseur JCE, mais cela n'aide pas car les restrictions de force de clé sont appliquées avant de passer à l'implémentation.) Cette solution ne vous permettra pas non plus d'utiliser des suites de chiffrement TLS (SSL) 256 bits, car le Les bibliothèques TLS standard appellent le JCE en interne pour déterminer les restrictions.
Mais ensuite, il y a la réflexion. Y a-t-il quelque chose que vous ne pouvez pas faire en utilisant la réflexion?
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"));
}
Appelez simplement à removeCryptographyRestrictions()
partir d'un initialiseur statique ou autre avant d'effectuer des opérations cryptographiques.
La JceSecurity.isRestricted = false
partie est tout ce qui est nécessaire pour utiliser directement les chiffrements 256 bits; cependant, sans les deux autres opérations, Cipher.getMaxAllowedKeyLength()
continuera à rapporter 128, et les suites de chiffrement TLS 256 bits ne fonctionneront pas.
Ce code fonctionne sur Oracle Java 7 et 8 et ignore automatiquement le processus sur Java 9 et OpenJDK là où il n'est pas nécessaire. Étant un hack laid après tout, cela ne fonctionne probablement pas sur les VM d'autres fournisseurs.
Cela ne fonctionne pas non plus sur Oracle Java 6, car les classes JCE privées y sont masquées. L'obscurcissement ne change pas d'une version à l'autre, il est donc toujours techniquement possible de prendre en charge Java 6.