All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.manydesigns.crypto.KeyManager Maven / Gradle / Ivy

package com.manydesigns.crypto;

import org.apache.commons.configuration.Configuration;
import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.Base64;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class KeyManager {

    public static final Logger logger = LoggerFactory.getLogger(KeyManager.class);

    private static final String PROPERTY_ALG = "com.manydesigns.crypto.algorithm";
    private static final String PROPERTY_PRIVATE_KEY = "com.manydesigns.crypto.private.key";
    private static final String PROPERTY_PUBLIC_KEY = "com.manydesigns.crypto.public.key";
    private static final String PROPERTY_PRIVATE_KEY_DELETE = "com.manydesigns.crypto.delete.key";
    private static final String PROPERTY_PASSPHRASE = "com.manydesigns.crypto.passphrase";
    private static final String PROPERTY_SECURITY_LOCATION = "com.manydesigns.crypto.location";

    private static final String ASYMMETRIC_ALG = "ASIM";
    private static final String SYMMETRIC_ALG = "SIM";

    private SecretKey simmK;
    private PublicKey pbK;
    private PrivateKey prK;
    private String algo;
    private static KeyManager single;

    private KeyManager(Configuration configuration) throws GeneralSecurityException, IOException, InvalidPassphraseException, InvalidSettingsException {
        algo = configuration.getString(PROPERTY_ALG);

        if (algo == null) {
            logger.warn("No " + PROPERTY_ALG + " defined, KeyManager will not be initialized ");
            return;
        }

        boolean autoDelete = configuration.getBoolean(PROPERTY_PRIVATE_KEY_DELETE, false);
        String securityLocation = configuration.getString(PROPERTY_SECURITY_LOCATION);
        String publicKeyPath = securityLocation + "/" + configuration.getString(PROPERTY_PUBLIC_KEY);
        String privateKeyPath = securityLocation + "/" + configuration.getString(PROPERTY_PRIVATE_KEY);
        String passphrasePath = securityLocation + "/" + configuration.getString(PROPERTY_PASSPHRASE);

        if( StringUtils.trimToNull(securityLocation)==null )
            throw new InvalidSettingsException("Required property "+PROPERTY_SECURITY_LOCATION+" is invalid or empty");

        if (algo.equals(ASYMMETRIC_ALG)) {
            this.prK = getPrivateKey(privateKeyPath);
            this.pbK = getPublicKey(publicKeyPath);
            this.simmK = null;
            checkOrSaveHash(privateKeyPath, this.prK.toString());
            if (autoDelete)
                CryptoUtils.secureDeleteFile(privateKeyPath);
        } else {
            if (algo.equals(SYMMETRIC_ALG)) {
                String strK = getPassPhrase(passphrasePath);
                checkOrSaveHash(passphrasePath, strK);
                CryptoUtils.checkPassphrase(strK);

                byte[] key = strK.getBytes(StandardCharsets.UTF_8);
                MessageDigest sha = MessageDigest.getInstance("SHA-1");
                key = sha.digest(key);
                key = Arrays.copyOf(key, 16); // use only first 128 bit

                this.simmK = new SecretKeySpec(key, "AES");

                if (autoDelete)
                    CryptoUtils.secureDeleteFile(passphrasePath);
            } else {
                throw new InvalidSettingsException(algo + " not supported, possible values are: " + SYMMETRIC_ALG + " | " + ASYMMETRIC_ALG);
            }
        }
    }

    private void checkOrSaveHash(String path, String key) throws IOException, GeneralSecurityException, InvalidPassphraseException {
        File checksumFile = new File(path + ".sum");

        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        digest.update(path.getBytes(StandardCharsets.UTF_8));
        String checksum = CryptoUtils.getStringChecksum(digest, key);

        if (checksumFile.exists()) {
            String current = StringUtils.trimToEmpty(CryptoUtils.getKey(checksumFile.getAbsolutePath()));

            if (!checksum.equals(current))
                throw new InvalidPassphraseException("Checksum test failed, passphrase differs from last one used file: " + checksumFile.getAbsolutePath());
        } else {
            try (PrintWriter pw = new PrintWriter(checksumFile);) {
                pw.print(checksum);
            }
        }
    }

    public static KeyManager init(Configuration configuration) throws IOException, GeneralSecurityException, InvalidPassphraseException, InvalidSettingsException {
        if (isActive())
            throw new GeneralSecurityException("Key manager already initialized");
        single = new KeyManager(configuration);
        return getInstance();
    }

    public static KeyManager getInstance() throws GeneralSecurityException {
        if (single == null)
            throw new GeneralSecurityException("Key manager not initialized");
        return single;
    }

    public static boolean isActive() {
        return single != null;
    }

    public SecretKey getSimmK() {
        return this.simmK;
    }

    public PublicKey getPbKey() {
        return this.pbK;
    }

    public PrivateKey getPrKey() {
        return this.prK;
    }

    public String getAlgo() {
        return this.algo;
    }

    private static PrivateKey getPrivateKey(String filename) throws IOException, GeneralSecurityException {
        String privateKeyPEM = CryptoUtils.getKey(filename);
        return getPrivateKeyFromString(privateKeyPEM);
    }

    private static PrivateKey getPrivateKeyFromString(String key) throws IOException, GeneralSecurityException {
        String privateKeyPEM = key;
        privateKeyPEM = privateKeyPEM.replace("-----BEGIN PRIVATE KEY-----\n", "");
        privateKeyPEM = privateKeyPEM.replace("-----END PRIVATE KEY-----", "");
        byte[] encoded = Base64.getDecoder().decode(privateKeyPEM.getBytes());
        KeyFactory kf = KeyFactory.getInstance("RSA");
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
        return kf.generatePrivate(keySpec);
    }

    private static PublicKey getPublicKey(String filename) throws IOException, GeneralSecurityException {
        String publicKeyPEM = CryptoUtils.getKey(filename);
        return getPublicKeyFromString(publicKeyPEM);
    }

    private static PublicKey getPublicKeyFromString(String key) throws IOException, GeneralSecurityException {
        String publicKeyPEM = key;
        publicKeyPEM = publicKeyPEM.replace("-----BEGIN PUBLIC KEY-----\n", "");
        publicKeyPEM = publicKeyPEM.replace("-----END PUBLIC KEY-----", "");
        byte[] encoded = Base64.getDecoder().decode(publicKeyPEM.getBytes());
        KeyFactory kf = KeyFactory.getInstance("RSA");
        return kf.generatePublic(new X509EncodedKeySpec(encoded));
    }

    private String getPassPhrase(String passphrasePath) throws IOException, InvalidPassphraseException {
        logger.info("Retrieving passphrase");
        StringBuilder passPhrase = new StringBuilder();

        try (BufferedReader br = new BufferedReader(new FileReader(passphrasePath))) {
            String line;
            while ((line = br.readLine()) != null) {
                passPhrase.append(line);
            }
        } catch (IOException e) {
            logger.error("getPassPhrase: " + e.getMessage(), e);
            throw e;
        }
        return passPhrase.toString();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy