Existem algumas soluções comumente citadas para esse problema. Infelizmente, nenhum deles é totalmente satisfatório:
- Instale os arquivos de política de força ilimitados . Embora essa seja provavelmente a solução certa para sua estação de trabalho de desenvolvimento, ela rapidamente se torna um grande aborrecimento (se não um obstáculo) para que usuários não técnicos instalem os arquivos em todos os computadores. Não há como distribuir os arquivos com o seu programa; eles devem ser instalados no diretório JRE (que pode até ser somente leitura devido a permissões).
- Ignore a API do JCE e use outra biblioteca de criptografia como o Bouncy Castle . Essa abordagem requer uma biblioteca extra de 1 MB, que pode ser uma carga significativa, dependendo do aplicativo. Também é bobagem duplicar a funcionalidade incluída nas bibliotecas padrão. Obviamente, a API também é completamente diferente da interface JCE usual. (O BC implementa um provedor JCE, mas isso não ajuda, porque as restrições de força de chave são aplicadas antes da entrega à implementação.) Essa solução também não permitirá que você use conjuntos de cifras TLS (SSL) de 256 bits, porque o bibliotecas TLS padrão chamam o JCE internamente para determinar quaisquer restrições.
Mas depois há reflexão. Existe algo que você não possa fazer usando reflexão?
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"));
}
Simplesmente chame removeCryptographyRestrictions()
de um inicializador estático ou algo semelhante antes de executar qualquer operação criptográfica.
A JceSecurity.isRestricted = false
parte é tudo o que é necessário para usar cifras de 256 bits diretamente; no entanto, sem as duas outras operações, Cipher.getMaxAllowedKeyLength()
o relatório continuará sendo reportado por 128, e os conjuntos de criptografia TLS de 256 bits não funcionarão.
Esse código funciona no Oracle Java 7 e 8 e ignora automaticamente o processo no Java 9 e no OpenJDK onde não é necessário. Sendo um truque feio, afinal, provavelmente não funciona nas VMs de outros fornecedores.
Também não funciona no Oracle Java 6, porque as classes JCE privadas são ofuscadas por lá. A ofuscação não muda de versão para versão, portanto, ainda é tecnicamente possível oferecer suporte ao Java 6.