com.formkiq.core.service.crypto.KeyGenerator.java Source code

Java tutorial

Introduction

Here is the source code for com.formkiq.core.service.crypto.KeyGenerator.java

Source

/*
 * Copyright (C) 2017 FormKiQ Inc.
 *
 * Licensed 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 com.formkiq.core.service.crypto;

import java.io.IOException;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Date;

import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v1CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.crypto.params.RSAKeyParameters;
import org.bouncycastle.crypto.util.SubjectPublicKeyInfoFactory;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;

import com.formkiq.core.util.Strings;

/**
 * Crypto helper class for generating keys and certificates.
 *
 */
public class KeyGenerator {

    /** Add {@link BouncyCastleProvider}. */
    private static final JcaX509CertificateConverter CONVERTER = new JcaX509CertificateConverter()
            .setProvider(new BouncyCastleProvider());

    /** Signature Algorithm. */
    private static final String SIGNATURE_ALGORITHM = "SHA256WithRSA";

    /** serial the certificate serial number. */
    private static final BigInteger SERIAL = new BigInteger("1");

    /**
     * Generate Key Pair.
     * @param keysize int
     * @return {@link KeyPair}
     * @throws NoSuchAlgorithmException NoSuchAlgorithmException
     */
    public KeyPair generateKeyPair(final int keysize) throws NoSuchAlgorithmException {

        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
        kpg.initialize(keysize);
        KeyPair kp = kpg.generateKeyPair();
        return kp;
    }

    /**
     * Generate Certificate for KeyPair.
     * @param keys {@link KeyPair}
     * @param issuer {@link X500Name}
     * @return {@link Certificate}[]
     */
    public X509Certificate getCertificate(final KeyPair keys, final X500Name issuer) {

        try {
            X509v1CertificateBuilder certificateBuilder = getCertificateBuilder(keys.getPublic(), issuer);
            X509CertificateHolder certificateHolder = certificateBuilder.build(getSigner(keys));
            return CONVERTER.getCertificate(certificateHolder);
        } catch (CertificateException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Build {@link X509v1CertificateBuilder}.
     * @param publicKey {@link PublicKey}
     * @param issuer {@link X500Name}
     * @return {@link X509v1CertificateBuilder}.
     */
    private X509v1CertificateBuilder getCertificateBuilder(final PublicKey publicKey, final X500Name issuer) {
        X500Name subject = issuer;

        try {
            Date notafter = new SimpleDateFormat("yyyy-MM-dd").parse("3000-01-01");

            Date notbefore = new SimpleDateFormat("yyyy-MM-dd").parse("2000-01-01");

            return new X509v1CertificateBuilder(issuer, SERIAL, notbefore, notafter, subject,
                    getPublicKeyInfo(publicKey));
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Get {@link SubjectPublicKeyInfo}.
     * @param publicKey {@link PublicKey}
     * @return {@link SubjectPublicKeyInfo}
     */
    private SubjectPublicKeyInfo getPublicKeyInfo(final PublicKey publicKey) {
        if (!(publicKey instanceof RSAPublicKey)) {
            throw new RuntimeException("publicKey is not an RSAPublicKey");
        }

        RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey;

        try {
            return SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(
                    new RSAKeyParameters(false, rsaPublicKey.getModulus(), rsaPublicKey.getPublicExponent()));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Get Signer {@link KeyPair}.
     * @param keys {@link KeyPair}
     * @return {@link ContentSigner}
     */
    private ContentSigner getSigner(final KeyPair keys) {
        try {
            return new JcaContentSignerBuilder(SIGNATURE_ALGORITHM).setProvider(new BouncyCastleProvider())
                    .build(keys.getPrivate());
        } catch (OperatorCreationException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Converts Text to RSAPrivateKey.
     * @param text {@link String}
     * @return {@link RSAPublicKey}
     * @throws GeneralSecurityException GeneralSecurityException
     */
    public RSAPrivateKey stringToPrivateKey(final String text) throws GeneralSecurityException {

        PKCS8EncodedKeySpec specPriv = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(text));

        KeyFactory kf = KeyFactory.getInstance("RSA");
        RSAPrivateKey key = (RSAPrivateKey) kf.generatePrivate(specPriv);
        return key;
    }

    /**
     * Converts Text to RSAPublicKey.
     * @param text {@link String}
     * @return {@link RSAPublicKey}
     * @throws GeneralSecurityException GeneralSecurityException
     */
    public RSAPublicKey stringToPublicKey(final String text) throws GeneralSecurityException {

        X509EncodedKeySpec spec = new X509EncodedKeySpec(Base64.getDecoder().decode(text));

        KeyFactory kf = KeyFactory.getInstance("RSA");
        return (RSAPublicKey) kf.generatePublic(spec);
    }

    /**
     * Convert Key to String.
     * @param key {@link Key}
     * @return {@link String}
     */
    public String toString(final Key key) {
        return Base64.getEncoder().encodeToString(key.getEncoded());
    }

    /**
     * Convert {@link Certificate} to {@link String}.
     * @param cert {@link Certificate}
     * @return {@link String}
     * @throws CertificateEncodingException CertificateEncodingException
     */
    public String convertToPem(final Certificate cert) throws CertificateEncodingException {

        String begin = "-----BEGIN CERTIFICATE-----\n";
        String end = "-----END CERTIFICATE-----";

        byte[] derCert = cert.getEncoded();
        return begin + Strings.toString(Base64.getEncoder().encode(derCert)) + end;
    }
}