org.kse.crypto.jcepolicy.JcePolicyUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.kse.crypto.jcepolicy.JcePolicyUtil.java

Source

/*
 * Copyright 2004 - 2013 Wayne Grant
 *           2013 - 2017 Kai Kramer
 *
 * This file is part of KeyStore Explorer.
 *
 * KeyStore Explorer is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * KeyStore Explorer is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with KeyStore Explorer.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.kse.crypto.jcepolicy;

import static org.kse.crypto.jcepolicy.CryptoStrength.LIMITED;
import static org.kse.crypto.jcepolicy.CryptoStrength.UNLIMITED;

import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.security.NoSuchAlgorithmException;
import java.security.Permission;
import java.security.PermissionCollection;
import java.text.MessageFormat;
import java.util.Enumeration;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.Manifest;

import javax.crypto.Cipher;

import org.apache.commons.io.IOUtils;
import org.kse.crypto.CryptoException;
import org.kse.utilities.io.CopyUtil;
import org.kse.utilities.net.URLs;
import org.kse.version.JavaVersion;

/**
 * Provides utility methods relating to JCE policies.
 *
 */
public class JcePolicyUtil {
    private static ResourceBundle res = ResourceBundle.getBundle("org/kse/crypto/jcepolicy/resources");

    private JcePolicyUtil() {
    }

    /**
     * Is the local JCE policy's crypto strength limited?
     *
     * @return True if it is
     * @throws CryptoException
     *             If there was a problem getting the policy or crypto strength
     */
    public static boolean isLocalPolicyCrytoStrengthLimited() throws CryptoException {
        return unlimitedStrengthTest() == CryptoStrength.LIMITED;
    }

    /**
     * Get a JCE policy's crypto strength.
     *
     * @param jcePolicy
     *            JCE policy
     * @return Crypto strength
     * @throws CryptoException
     *             If there was a problem getting the crypto strength
     */
    public static CryptoStrength getCryptoStrength(JcePolicy jcePolicy) throws CryptoException {
        JarFile jarFile = null;
        try {
            File file = getJarFile(jcePolicy);

            // if there is no policy file at all, we assume that we are running under OpenJDK
            if (!file.exists()) {
                return UNLIMITED;
            }

            jarFile = new JarFile(file);

            Manifest jarManifest = jarFile.getManifest();
            String strength = jarManifest.getMainAttributes().getValue("Crypto-Strength");

            // workaround for IBM JDK: test for maximum key size
            if (strength == null) {
                return unlimitedStrengthTest();
            }

            if (strength.equals(LIMITED.manifestValue())) {
                return LIMITED;
            } else {
                return UNLIMITED;
            }
        } catch (IOException ex) {
            throw new CryptoException(
                    MessageFormat.format(res.getString("NoGetCryptoStrength.exception.message"), jcePolicy), ex);
        } finally {
            IOUtils.closeQuietly(jarFile);
        }
    }

    private static CryptoStrength unlimitedStrengthTest() {
        try {
            if (Cipher.getMaxAllowedKeyLength("AES") >= 256) {
                return UNLIMITED;
            }
        } catch (NoSuchAlgorithmException e) {
            // swallow exception
        }
        return LIMITED;
    }

    /**
     * Get a JCE policy's details.
     *
     * @param jcePolicy
     *            JCE policy
     * @return Policy details
     * @throws CryptoException
     *             If there was a problem getting the policy details
     */
    public static String getPolicyDetails(JcePolicy jcePolicy) throws CryptoException {
        JarFile jarFile = null;
        try {
            StringWriter sw = new StringWriter();

            File file = getJarFile(jcePolicy);

            // if there is no policy file at all, return empty string
            if (!file.exists()) {
                return "";
            }

            jarFile = new JarFile(file);

            Enumeration<JarEntry> jarEntries = jarFile.entries();

            while (jarEntries.hasMoreElements()) {
                JarEntry jarEntry = jarEntries.nextElement();

                String entryName = jarEntry.getName();

                if (!jarEntry.isDirectory() && entryName.endsWith(".policy")) {
                    sw.write(entryName + ":\n\n");

                    InputStreamReader isr = null;
                    try {
                        isr = new InputStreamReader(jarFile.getInputStream(jarEntry));
                        CopyUtil.copy(isr, sw);
                    } finally {
                        IOUtils.closeQuietly(isr);
                    }

                    sw.write('\n');
                }
            }

            return sw.toString();
        } catch (IOException ex) {
            throw new CryptoException(
                    MessageFormat.format(res.getString("NoGetPolicyDetails.exception.message"), jcePolicy), ex);
        } finally {
            IOUtils.closeQuietly(jarFile);
        }
    }

    /**
     * Get a JCE policy's JAR file.
     *
     * @param jcePolicy
     *            JCE policy
     * @return JAR file
     */
    public static File getJarFile(JcePolicy jcePolicy) {
        String fileSeperator = System.getProperty("file.separator");
        String javaHome = System.getProperty("java.home");
        File libSecurityFile = new File(javaHome, "lib" + fileSeperator + "security");

        return new File(libSecurityFile, jcePolicy.jar());
    }

    /**
     * Get JCE Unlimited Strength Jurisdiction Policy download URL for the
     * current JRE.
     *
     * @return Download page URL
     */
    public static String getJcePolicyDownloadUrl() {
        JavaVersion jreVersion = JavaVersion.getJreVersion();

        int major = jreVersion.getMajor();
        int middle = jreVersion.getMinor();
        int minor = jreVersion.getSecurity();

        String version = MessageFormat.format("{0}.{1}.{2}", major, middle, minor);

        String url = MessageFormat.format(URLs.JCE_POLICY_DOWNLOAD_URL, version);

        return url;
    }

    /**
     * Hack to disable crypto restrictions until Java 9 is out.
     *
     * See http://stackoverflow.com/a/22492582/2672392
     */
    public static void removeRestrictions() {
        try {
            Class<?> jceSecurityClass = Class.forName("javax.crypto.JceSecurity");
            Class<?> cryptoPermissionsClass = Class.forName("javax.crypto.CryptoPermissions");
            Class<?> cryptoAllPermissionClass = Class.forName("javax.crypto.CryptoAllPermission");

            Field isRestrictedField = jceSecurityClass.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 = jceSecurityClass.getDeclaredField("defaultPolicy");
            defaultPolicyField.setAccessible(true);
            PermissionCollection defaultPolicy = (PermissionCollection) defaultPolicyField.get(null);

            Field permsField = cryptoPermissionsClass.getDeclaredField("perms");
            permsField.setAccessible(true);
            ((Map<?, ?>) permsField.get(defaultPolicy)).clear();

            Field cryptoAllPermissionInstanceField = cryptoAllPermissionClass.getDeclaredField("INSTANCE");
            cryptoAllPermissionInstanceField.setAccessible(true);
            defaultPolicy.add((Permission) cryptoAllPermissionInstanceField.get(null));
        } catch (Exception e) {
            // ignore
        }
    }
}