net.firejack.platform.web.security.x509.KeyUtils.java Source code

Java tutorial

Introduction

Here is the source code for net.firejack.platform.web.security.x509.KeyUtils.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package net.firejack.platform.web.security.x509;

import com.sun.jersey.core.util.Base64;
import net.firejack.platform.core.exception.OpenFlameRuntimeException;
import net.firejack.platform.core.utils.ArrayUtils;
import net.firejack.platform.core.utils.StringUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
import sun.security.x509.*;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.math.BigInteger;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.security.spec.EncodedKeySpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.*;

public class KeyUtils {

    private static final Logger logger = Logger.getLogger(KeyUtils.class);
    private static final char[] SECRET = "OpenFlameTheBest".toCharArray();
    private static final String ALIAS = "alias";
    private static final int KEYSIZE = 1024;

    public static KeyPair generate(File keystore) {
        if (keystore == null) {
            throw new IllegalArgumentException("Key Store file should not be null.");
        }

        try {
            KeyStore ks = KeyStore.getInstance("JKS", "SUN");
            if (keystore.exists()) {
                FileInputStream stream = new FileInputStream(keystore);
                ks.load(stream, SECRET);
                IOUtils.closeQuietly(stream);
            } else {
                ks.load(null, SECRET);
            }

            if (ks.containsAlias(ALIAS)) {
                PrivateKey privateKey = (PrivateKey) ks.getKey(ALIAS, SECRET);
                PublicKey publicKey = ks.getCertificate(ALIAS).getPublicKey();
                return new KeyPair(publicKey, privateKey);
            } else {
                KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
                generator.initialize(KEYSIZE, new SecureRandom());
                return generator.generateKeyPair();
            }
        } catch (Throwable th) {
            logger.error("Failed to initialize key store");
            throw new OpenFlameRuntimeException(th.getMessage(), th);
        }
    }

    public static void add(File keystore, KeyPair pair, String domain) {
        if (keystore == null) {
            throw new IllegalArgumentException("Key Store file should not be null.");
        }

        try {
            KeyStore ks = KeyStore.getInstance("JKS", "SUN");
            if (keystore.exists()) {
                FileInputStream stream = new FileInputStream(keystore);
                ks.load(stream, SECRET);
                IOUtils.closeQuietly(stream);
            } else {
                ks.load(null, SECRET);
            }

            if (!ks.containsAlias(ALIAS)) {
                X509Certificate certificate = generateCertificate(domain, 1, pair);

                ks.setKeyEntry(ALIAS, pair.getPrivate(), SECRET, new Certificate[] { certificate });

                FileOutputStream stream = new FileOutputStream(keystore);
                ks.store(stream, SECRET);
                IOUtils.closeQuietly(stream);
            }
        } catch (Throwable th) {
            logger.error("Failed to initialize key store");
            throw new OpenFlameRuntimeException(th.getMessage(), th);
        }
    }

    public static KeyPair load(File keyStoreFile) {
        if (keyStoreFile != null) {
            try {
                KeyStore ks = KeyStore.getInstance("JKS", "SUN");
                if (keyStoreFile.exists()) {
                    FileInputStream stream = new FileInputStream(keyStoreFile);
                    ks.load(stream, SECRET);
                    IOUtils.closeQuietly(stream);

                    PrivateKey privateKey = (PrivateKey) ks.getKey(ALIAS, SECRET);
                    if (privateKey == null)
                        return null;
                    PublicKey publicKey = ks.getCertificate(ALIAS).getPublicKey();
                    return new KeyPair(publicKey, privateKey);
                }
            } catch (Throwable th) {
                logger.error("Failed to initialize key store");
                throw new OpenFlameRuntimeException(th.getMessage(), th);
            }
        } else {
            throw new IllegalArgumentException("Key Store file should not be null.");
        }
        return null;
    }

    public static X500Name getInfo(File keystore) {
        try {
            KeyStore ks = KeyStore.getInstance("JKS", "SUN");
            FileInputStream stream = new FileInputStream(keystore);
            ks.load(stream, SECRET);
            IOUtils.closeQuietly(stream);
            X509CertImpl x509Cert = (X509CertImpl) ks.getCertificate(ALIAS);
            return (X500Name) x509Cert.getSubjectDN();
        } catch (Exception e) {
            return null;
        }
    }

    public static X509Certificate generateCertificate(String domain, int days, KeyPair keyPair)
            throws GeneralSecurityException, IOException {
        X509CertInfo info = new X509CertInfo();
        Date from = new Date();
        Date to = new Date(from.getTime() + days * 86400000l);
        CertificateValidity interval = new CertificateValidity(from, to);
        BigInteger sn = new BigInteger(64, new SecureRandom());

        X500Name owner = new X500Name("DC=" + domain);

        info.set(X509CertInfo.VALIDITY, interval);
        info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(sn));
        info.set(X509CertInfo.SUBJECT, new CertificateSubjectName(owner));
        info.set(X509CertInfo.ISSUER, new CertificateIssuerName(owner));
        info.set(X509CertInfo.KEY, new CertificateX509Key(keyPair.getPublic()));
        info.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3));

        AlgorithmId algo = new AlgorithmId(AlgorithmId.md5WithRSAEncryption_oid);
        info.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(algo));

        X509CertImpl cert = new X509CertImpl(info);
        cert.sign(keyPair.getPrivate(), "MD5WithRSA");

        return cert;
    }

    public static void verify(String cert64, String public64) throws CertificateException, NoSuchAlgorithmException,
            InvalidKeySpecException, SignatureException, NoSuchProviderException, InvalidKeyException {
        if (StringUtils.isBlank(cert64)) {
            throw new CertificateException("Certificate is empty");
        } else if (StringUtils.isBlank(public64)) {
            throw new InvalidKeyException("Public key is empty");
        }
        byte[] cert = Base64.decode(cert64);
        byte[] key = Base64.decode(public64);
        X509CertImpl x509 = new X509CertImpl(cert);

        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(key);
        PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);

        Calendar utc = Calendar.getInstance(TimeZone.getTimeZone("UTC"));

        x509.verify(publicKey);
        x509.checkValidity(utc.getTime());
    }

    public static byte[] encrypt(PublicKey key, byte[] bytes) throws Exception {
        byte[] result = new byte[0];

        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, key);

        int length = cipher.getOutputSize(bytes.length) - 11;
        for (int i = 0; i < bytes.length; i += length) {
            byte[] buffer = cipher.doFinal(bytes, i, Math.min(bytes.length - i, length));
            result = ArrayUtils.addAll(result, buffer);
        }

        return result;
    }

    public static byte[] encrypt(byte[] data, String password) throws Exception {
        Cipher c = Cipher.getInstance("AES");
        c.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key(password, 16), "AES"));
        return c.doFinal(data);
    }

    public static byte[] decrypt(PrivateKey key, byte[] bytes) throws Exception {
        byte[] result = new byte[0];

        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, key);
        int length = cipher.getOutputSize(bytes.length);

        for (int i = 0; i < bytes.length; i += length) {
            byte[] bytes1 = cipher.doFinal(bytes, i, Math.min(bytes.length - i, length));
            result = ArrayUtils.addAll(result, bytes1);
        }

        return result;
    }

    public static byte[] decrypt(byte[] data, String password) throws Exception {
        Cipher c = Cipher.getInstance("AES");
        c.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key(password, 16), "AES"));
        return c.doFinal(data);
    }

    public static Properties getProperties(File properties, File keystore) {
        Properties props = new Properties();
        if (!properties.exists())
            return props;

        InputStream stream = null;
        try {
            byte[] bytes = FileUtils.readFileToByteArray(properties);
            stream = new ByteArrayInputStream(bytes);
            if (keystore.exists()) {
                KeyPair keyPair = load(keystore);
                try {
                    byte[] decrypt = decrypt(keyPair.getPrivate(), bytes);
                    stream = new ByteArrayInputStream(decrypt);
                } catch (Exception e) {
                    logger.trace(e);
                }
            }
            props.load(stream);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            IOUtils.closeQuietly(stream);
        }

        return props;
    }

    private static byte[] key(String key, int len) {
        key = StringUtils.left(key, len);
        key = StringUtils.rightPad(key, len, '=');
        return key.getBytes();
    }

    public static Map<String, String> getMapProperties(File properties, File keystore) {
        Properties props = getProperties(properties, keystore);
        Map<String, String> propertiesMap = new HashMap<String, String>();
        for (Map.Entry<Object, Object> entry : props.entrySet()) {
            propertiesMap.put((String) entry.getKey(), (String) entry.getValue());
        }
        return propertiesMap;
    }

    public static void setProperties(File properties, File keystore, Map<String, String> append)
            throws IOException {
        Properties props = getProperties(properties, keystore);

        if (properties.exists() || properties.createNewFile()) {
            props.putAll(append);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            props.store(baos, null);

            InputStream stream = new ByteArrayInputStream(baos.toByteArray());
            if (keystore.exists()) {
                KeyPair keyPair = load(keystore);
                if (keyPair != null) {
                    try {
                        byte[] decrypt = encrypt(keyPair.getPublic(), baos.toByteArray());
                        stream = new ByteArrayInputStream(decrypt);
                    } catch (Exception e) {
                        logger.trace(e);
                    }
                }
            }

            FileOutputStream writer = new FileOutputStream(properties);
            IOUtils.copy(stream, writer);
            IOUtils.closeQuietly(writer);
        }
    }

    public static Properties getProperties(byte[] key, byte[] data) {
        Properties properties = new Properties();
        try {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(key);
            PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);

            byte[] decrypt = decrypt(privateKey, data);

            InputStream stream = new ByteArrayInputStream(decrypt);
            properties.load(stream);
        } catch (Exception e) {
            logger.trace(e);
        }
        return properties;
    }

    public static void writeCrypt(File file, File keystore, InputStream stream) throws IOException {
        if (keystore.exists()) {
            KeyPair keyPair = load(keystore);
            if (keyPair != null) {
                try {
                    byte[] decrypt = encrypt(keyPair.getPublic(), IOUtils.toByteArray(stream));
                    FileUtils.writeByteArrayToFile(file, decrypt);
                } catch (Exception e) {
                    logger.trace(e);
                }
            }
        }
    }

    public static InputStream readCrypt(File file, File keystore) {
        if (!file.exists())
            return null;

        InputStream stream = null;
        try {
            if (keystore.exists()) {
                KeyPair keyPair = load(keystore);
                byte[] decrypt = decrypt(keyPair.getPrivate(), FileUtils.readFileToByteArray(file));
                stream = new ByteArrayInputStream(decrypt);
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }

        return stream;
    }
}