webentwicklung-frage-antwort-db.com.de

Wie vermeide ich die Installation von JCE-Richtliniendateien mit unbegrenzter Stärke beim Bereitstellen einer Anwendung?

Ich besitze eine App, die eine 256-Bit-AES-Verschlüsselung verwendet, die von Java= von Anfang an nicht unterstützt wird. Ich weiß, dass ich die JCE-Gläser mit unbegrenzter Stärke im Sicherheitsordner installieren muss, um die ordnungsgemäße Funktion zu gewährleisten Das ist in Ordnung für mich als Entwickler, ich kann sie installieren.

Meine Frage ist, da diese App verteilt wird, werden Endbenutzer diese Richtliniendateien höchstwahrscheinlich nicht installiert haben. Es ist keine attraktive Lösung, wenn der Endbenutzer diese nur herunterlädt, damit die App funktioniert.

Gibt es eine Möglichkeit, meine App zum Ausführen zu bringen, ohne Dateien auf dem Endbenutzer-Computer zu überschreiben? Eine Drittanbieter-Software, die ohne installierte Richtliniendateien damit umgehen kann? Oder eine Möglichkeit, diese Richtliniendateien einfach aus einer JAR heraus zu referenzieren?

166
Ken

Es gibt ein paar häufig zitierte Lösungen für dieses Problem. Leider ist keines von beiden völlig zufriedenstellend:

  • Installieren Sie die Richtliniendateien mit unbegrenzter Stärke . Dies ist wahrscheinlich die richtige Lösung für Ihre Entwicklungsarbeitsstation, wird jedoch schnell zu einem großen Problem (wenn nicht eine Straßensperre), damit nicht-technische Benutzer die Dateien auf jedem Computer installieren. Es gibt keine Möglichkeit , die Dateien mit Ihrem Programm zu verteilen; Sie müssen im JRE-Verzeichnis installiert werden (das aufgrund von Berechtigungen sogar schreibgeschützt sein kann).
  • Überspringen Sie die JCE-API und verwenden Sie eine andere Kryptografiebibliothek wie Hüpfburg . Dieser Ansatz erfordert eine zusätzliche Bibliothek von 1 MB, was je nach Anwendung eine erhebliche Belastung darstellen kann. Es fühlt sich auch albern an, die in den Standardbibliotheken enthaltenen Funktionen zu duplizieren. Offensichtlich unterscheidet sich die API auch völlig von der üblichen JCE-Schnittstelle. (BC implementiert zwar einen JCE-Provider, aber das hilft nicht weiter, da die Schlüsselstärkenbeschränkungen angewendet werden Vorher Übergabe an die Implementierung.) Bei dieser Lösung können Sie auch keine 256-Bit-Version verwenden TLS (SSL) -Cipher-Suites, da die Standard-TLS-Bibliotheken die JCE intern aufrufen, um Einschränkungen zu ermitteln.

Aber dann gibt es Reflexion. Gibt es etwas, was Sie mit Reflexion nicht tun können?

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"));
}

Rufen Sie einfach removeCryptographyRestrictions() von einem statischen Initialisierer oder dergleichen aus auf, bevor Sie kryptografische Operationen ausführen.

Der Teil JceSecurity.isRestricted = false Ist alles, was benötigt wird, um 256-Bit-Chiffren direkt zu verwenden. Ohne die beiden anderen Operationen meldet Cipher.getMaxAllowedKeyLength() jedoch weiterhin 128, und 256-Bit-TLS-Chiffresuiten funktionieren nicht.

Dieser Code funktioniert unter Oracle Java 7 und 8 und überspringt automatisch den Prozess unter Java 9 und OpenJDK, wenn er nicht benötigt wird. Schließlich ist es ein hässlicher Hack, der auf den VMs anderer Hersteller wahrscheinlich nicht funktioniert.

Es funktioniert auch nicht mit Oracle Java 6, da die privaten JCE-Klassen dort verschleiert sind. Die Verschleierung ändert sich jedoch nicht von Version zu Version, sodass es technisch immer noch möglich ist, Java 6 zu unterstützen.

171
ntoskrnl

Dies wird jetzt nicht mehr für Java 9 oder für eine neuere Version von Java 6, 7 oder 8) benötigt . Endlich! :)

Per JDK-8170157 ist die unbegrenzte Verschlüsselungsrichtlinie jetzt standardmäßig aktiviert.

Spezifische Versionen aus der JIRA-Ausgabe:

  • Java 9 (10, 11, etc ..): Jede offizielle Veröffentlichung!
  • Java 8u161 oder neuer (Verfügbar jetzt)
  • Java 7u171 oder höher (nur über "My Oracle Support" verfügbar)
  • Java 6u181 oder höher (nur über "My Oracle Support" verfügbar)

Beachten Sie, dass wenn aus irgendeinem Grund das alte Verhalten in Java 9) benötigt wird, es eingestellt werden kann mit:

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

Hier ist die Lösung: 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) {
    }
}
22
mike

Ab JDK 8u102 funktionieren die veröffentlichten Lösungen, die auf Reflektion basieren, nicht mehr: Das Feld, das diese Lösungen festlegen, ist jetzt final ( https://bugs.openjdk.Java.net/browse/JDK -8149417 ).

Sieht so aus, als wäre es entweder (a) das Verwenden von Bouncy Castle oder (b) das Installieren der JCE-Richtliniendateien.

13
Sam Roberton

Für die Hüpfburg sind immer noch Gläser erforderlich, soweit ich das beurteilen kann.

Ich habe einen kleinen Test gemacht und es schien dies zu bestätigen:

http://www.bouncycastle.org/wiki/display/JA1/Frequently+Asked+Questions

13
timothyjc

Eine alternative Kryptografie-Bibliothek finden Sie unter Hüpfburg . Es hat AES und viele zusätzliche Funktionen. Es ist eine liberale Open-Source-Bibliothek. Sie müssen jedoch die schlanke, proprietäre Bouncy Castle-API verwenden, damit dies funktioniert.

8
user150924

Sie könnten Methode verwenden

javax.crypto.Cipher.getMaxAllowedKeyLength(String transformation)

um die verfügbare Schlüssellänge zu testen, verwenden Sie diese und informieren Sie den Benutzer über die aktuellen Vorgänge. Etwas, das besagt, dass Ihre Anwendung aufgrund der nicht installierten Richtliniendateien beispielsweise auf 128-Bit-Schlüssel zurückgreift. Sicherheitsbewusste Benutzer installieren die Richtliniendateien, andere verwenden weiterhin schwächere Schlüssel.

4

Für unsere Anwendung hatten wir eine Client-Server-Architektur und erlaubten nur das Entschlüsseln/Verschlüsseln von Daten auf Serverebene. Daher werden die JCE-Dateien nur dort benötigt.

Wir hatten ein weiteres Problem, bei dem wir eine Sicherheits-JAR auf den Client-Rechnern aktualisieren mussten. Durch JNLP werden die Bibliotheken in ${Java.home}/lib/security/ Und die JVM beim ersten Start überschrieben.

Das hat funktioniert.

3
Mohamed Mansour

Hier ist eine aktualisierte Version von ntoskrnl answer. Es enthält zusätzlich eine Funktion zum Entfernen des finalen Modifikators wie Arjan , der in den Kommentaren erwähnt wird.

Diese Version funktioniert mit JRE 8u111 oder neuer.

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"));
}
2
xoned

Hier ist eine modifizierte Version von @ ntoskrnls Code mit isRestrictedCryptography check by actual Cipher.getMaxAllowedKeyLength , slf4j-Protokollierung und Unterstützung der Singleton-Initialisierung von der Anwendung bootstrap wie folgt:

static {
    UnlimitedKeyStrengthJurisdictionPolicy.ensure();
}

Dieser Code würde die mangelnde Reflektion korrekt beenden, wenn standardmäßig unbegrenzte Richtlinien in Java 8u162 verfügbar sind, wie die Antwort von @ cranphin vorhersagt.


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://stackoverflow.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
    }
}
1
Vadzim

Während der Installation Ihres Programms müssen Sie lediglich den Benutzer auffordern, ein DOS-Batch-Skript oder ein Bash-Shell-Skript herunterzuladen und die JCE in den richtigen Systemspeicherort zu kopieren.

Früher musste ich dies für einen Server-Webservice tun und statt eines formellen Installationsprogramms habe ich nur Skripts zum Einrichten der App bereitgestellt, bevor der Benutzer sie ausführen konnte. Sie können die App so lange deaktivieren, bis das Setup-Skript ausgeführt wird. Sie könnten die App auch dazu bringen, sich über das Fehlen der JCE zu beschweren, und dann darum bitten, die App herunterzuladen und neu zu starten?

0
djangofan