net.etfbl.cryptodigitalcertificate.tool.CryptoDCTool.java Source code

Java tutorial

Introduction

Here is the source code for net.etfbl.cryptodigitalcertificate.tool.CryptoDCTool.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package net.etfbl.cryptodigitalcertificate.tool;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.SignatureException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Date;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.security.auth.x500.X500Principal;
import net.etfbl.cryptodigitalcertificate.CryptoDigitalCertificate;
import net.etfbl.cryptodigitalcertificate.tool.util.CryptoPEMExtractor;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.cert.CertIOException;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.crypto.util.PrivateKeyFactory;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.bc.BcRSAContentSignerBuilder;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.pkcs.PKCS10CertificationRequest;
import org.bouncycastle.pkcs.PKCS10CertificationRequestBuilder;
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;

/**
 *
 * @author ZM
 */
public class CryptoDCTool {

    private static final String DEFAULT_COUNTRY = "BA";
    private static final String DEFAULT_STATE = "RS";
    private static final String DEFAULT_LOCALITY = "Banja Luka";
    private static final String DEFAULT_ORGANIZATION = "etf";
    private static final String DEFAULT_ORG_UNIT = "etf";
    private static final String DEFAULT_COMMON_NAME = "";
    private static final String DEFAULT_EMAIL = "default@mail.com";

    private static final String DEFAULT_KEYSTORE_ALIAS = "Private Key";
    private static final int DEFAULT_NUMBER_OF_DAYS = 365;

    private String command;
    private String inputFile;
    private String outputFile;
    private String clientKeysFile;

    public String getClientKeysFile() {
        return clientKeysFile;
    }

    public void setClientKeysFile(String clientKeysFile) {
        this.clientKeysFile = clientKeysFile;
    }

    public String getOutputFile() {
        return outputFile;
    }

    public void setOutputFile(String outputFile) {
        this.outputFile = outputFile;
    }

    private String keyLenght;

    public String getInputFile() {
        return inputFile;
    }

    public void setInputFile(String inputFile) {
        this.inputFile = inputFile;
    }

    public String getKeyLenght() {
        return keyLenght;
    }

    public void setKeyLenght(String keyLenght) {
        this.keyLenght = keyLenght;
    }

    public String getCommand() {
        return command;
    }

    public void setCommand(String command) {
        this.command = command;
    }

    public void executeCommand() {
        switch (command) {
        case "genrsa": {
            generateRSA();
            break;
        }
        case "req": {
            createRequest();
            break;
        }
        case "pkcs12": {
            signCSR();
            break;
        }
        case "--help": {
            displayHelp();
            break;
        }
        default: {
            System.out.println("Invalid command " + command);
            break;
        }
        }
    }

    private void generateRSA() {
        assertParameter(keyLenght, "-key");
        assertParameter(outputFile, "-out");
        try {
            int keyLength = Integer.parseInt(keyLenght);
            KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance("RSA", "BC");
            keyGenerator.initialize(keyLength);
            KeyPair key = keyGenerator.generateKeyPair();
            new CryptoPEMExtractor().writeObject(key, outputFile);
            System.out.println("\nGenerated key (" + keyLenght + " bits): " + outputFile);

        } catch (NumberFormatException | NoSuchAlgorithmException | NoSuchProviderException
                | FileNotFoundException ex) {
            System.out.println(ex.getMessage());
        } catch (IOException ex) {
            System.out.println(ex.getMessage());
        }
    }

    private void createRequest() {
        assertParameter(inputFile, "-in");
        assertParameter(outputFile, "-out");
        try {
            String country = RequestFromUser("Country name (2 letter code) [" + "BA" + "]:", DEFAULT_COUNTRY);
            String state = RequestFromUser("State or Province Name (full name) [" + DEFAULT_STATE + "]:",
                    DEFAULT_STATE);
            String locality = RequestFromUser("Locality Name (eg, city) [" + DEFAULT_LOCALITY + "]:",
                    DEFAULT_LOCALITY);
            String organization = RequestFromUser("Organization Name (eg, company) [" + DEFAULT_ORGANIZATION + "]:",
                    DEFAULT_ORGANIZATION);
            String unit = RequestFromUser("Organizational Unit Name (eg, section) [" + DEFAULT_ORG_UNIT + "]:",
                    DEFAULT_ORG_UNIT);
            String common = RequestFromUser(
                    "Common Name (e.g. server FQDN or Your name) [" + DEFAULT_COMMON_NAME + "]:",
                    DEFAULT_COMMON_NAME);
            String email = RequestFromUser("Email Address [" + DEFAULT_EMAIL + "]:", DEFAULT_EMAIL);
            //TO DO - Check the data
            X500Principal subject = new X500Principal(
                    "C=" + country + ", " + "ST=" + state + ", " + "L=" + locality + ", " + "O=" + organization
                            + ", " + "OU= " + unit + ", " + "CN=" + common + ", " + "EMAILADDRESS=" + email);

            CryptoPEMExtractor exctractor = new CryptoPEMExtractor();
            KeyPair pair = exctractor.loadKeyPair(inputFile);
            if (pair != null) {
                PrivateKey key = pair.getPrivate();
                PKCS10CertificationRequestBuilder builder = new JcaPKCS10CertificationRequestBuilder(subject,
                        pair.getPublic());
                String signAlgorythm = "SHA256withRSA";
                ContentSigner signGen = new JcaContentSignerBuilder(signAlgorythm).build(key);
                PKCS10CertificationRequest request = builder.build(signGen);
                exctractor.writeObject(request, outputFile);

                System.out.println("\nGenerated certificate request: " + outputFile);

            } else {
                System.out.println("Failed to load key pair from file " + inputFile);
            }
        } catch (OperatorCreationException | IOException ex) {
            System.out.println(ex.getMessage());
        }

    }

    public void signCSR() {
        assertParameter(inputFile, "-in");
        assertParameter(clientKeysFile, "-keys");
        assertParameter(outputFile, "-out");
        try {
            CryptoPEMExtractor exctractor = new CryptoPEMExtractor();
            //Load CA keys and CA certificate
            KeyPair caKeys = exctractor.loadKeyPair(this.getClass().getResourceAsStream("/keys/caprivate.key"));
            CertificateFactory fact = CertificateFactory.getInstance("X.509");
            X509Certificate cacert = (X509Certificate) fact
                    .generateCertificate(this.getClass().getResourceAsStream("/certs/cacert.pem"));
            //Load certificate request
            PKCS10CertificationRequest request = (PKCS10CertificationRequest) exctractor.loadObject(inputFile);
            //Setup X509 certificate generator with specified certificate data
            X509v3CertificateBuilder certgen = setupCertificateData(cacert, request);
            ContentSigner signer = setupHashAndSignAlgorythm(caKeys);
            //Create certificate
            X509CertificateHolder holder = certgen.build(signer);
            X509Certificate clientCert = new JcaX509CertificateConverter().setProvider("BC").getCertificate(holder);
            //Generate password
            String exportPassword = java.util.UUID.randomUUID().toString().substring(0, 4);
            //Save certificate in keystore
            storeCertificateInKeyStore(cacert, clientCert, exportPassword);

            System.out.println("\nGenerated PKCS#12 file. Password is: " + exportPassword);

        } catch (CertificateException | OperatorCreationException | KeyStoreException | NoSuchAlgorithmException
                | InvalidKeyException | NoSuchProviderException | SignatureException | IOException ex) {
            System.out.println(ex.getMessage());
        }
    }

    private void displayHelp() {
        BufferedReader reader = new BufferedReader(
                new InputStreamReader(CryptoDigitalCertificate.class.getResourceAsStream("/doc/help.txt")));
        String line = "";
        try {
            System.out.println();
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
            reader.close();
        } catch (IOException ex) {
            System.out.println(ex.getMessage());
        }
    }

    private String RequestFromUser(String message, String defaultValue) {
        System.out.print(message);
        Scanner scanner = new Scanner(System.in);
        String input = scanner.nextLine();
        if (input == null || "".equals(input)) {
            input = defaultValue;
        }
        return input;
    }

    private X509v3CertificateBuilder setupCertificateData(X509Certificate cacert,
            PKCS10CertificationRequest request) throws CertIOException {
        X500Name issuer = new X500Name(cacert.getSubjectX500Principal().getName());
        BigInteger serial = new BigInteger(32, new SecureRandom());
        Date from = new Date();
        Date to = new Date(System.currentTimeMillis() + (DEFAULT_NUMBER_OF_DAYS * 86400000L));
        X509v3CertificateBuilder certgen = new X509v3CertificateBuilder(issuer, serial, from, to,
                request.getSubject(), request.getSubjectPublicKeyInfo());
        //
        //  Setup the certificate extensions
        //
        // Basic Constraints
        certgen.addExtension(Extension.basicConstraints, false, new BasicConstraints(false));
        // Authority Key Identifier
        SubjectPublicKeyInfo caSubjectPublicKeyInfo = SubjectPublicKeyInfo
                .getInstance(cacert.getPublicKey().getEncoded());
        // Key Usage
        certgen.addExtension(Extension.keyUsage, false,
                new KeyUsage(KeyUsage.nonRepudiation | KeyUsage.keyEncipherment));

        return certgen;
    }

    private ContentSigner setupHashAndSignAlgorythm(KeyPair caKeys) throws IOException, OperatorCreationException {
        AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA256WithRSA");
        AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
        return new BcRSAContentSignerBuilder(sigAlgId, digAlgId)
                .build(PrivateKeyFactory.createKey(caKeys.getPrivate().getEncoded()));
    }

    private void storeCertificateInKeyStore(X509Certificate cacert, X509Certificate clientCert,
            String exportPassword) throws IOException, CertificateException, NoSuchAlgorithmException,
            InvalidKeyException, NoSuchProviderException, SignatureException, KeyStoreException {
        CryptoPEMExtractor exctractor = new CryptoPEMExtractor();
        KeyPair clientPair = exctractor.loadKeyPair(clientKeysFile);
        clientCert.verify(cacert.getPublicKey());
        KeyStore store = KeyStore.getInstance("PKCS12");
        store.load(null, null);
        X509Certificate[] chain = new X509Certificate[1];
        chain[0] = clientCert;
        store.setKeyEntry(DEFAULT_KEYSTORE_ALIAS, clientPair.getPrivate(), exportPassword.toCharArray(), chain);
        FileOutputStream fOut = new FileOutputStream(outputFile);
        store.store(fOut, exportPassword.toCharArray());
    }

    private void assertParameter(String parameter, String name) {
        if (parameter == null) {
            System.out.println("Parameter " + name + " not specified. Use --help for more information.");
            System.exit(1);
        }
    }
}