001/*
002 * acme4j - Java ACME client
003 *
004 * Copyright (C) 2015 Richard "Shred" Körber
005 *   http://acme4j.shredzone.org
006 *
007 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
013 */
014package org.shredzone.acme4j.util;
015
016import java.io.IOException;
017import java.io.Reader;
018import java.io.Writer;
019import java.security.InvalidAlgorithmParameterException;
020import java.security.KeyPair;
021import java.security.KeyPairGenerator;
022import java.security.NoSuchAlgorithmException;
023import java.security.NoSuchProviderException;
024import java.security.SecureRandom;
025
026import org.bouncycastle.jce.ECNamedCurveTable;
027import org.bouncycastle.jce.spec.ECParameterSpec;
028import org.bouncycastle.openssl.PEMException;
029import org.bouncycastle.openssl.PEMKeyPair;
030import org.bouncycastle.openssl.PEMParser;
031import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
032import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
033
034/**
035 * Utility class offering convenience methods for {@link KeyPair}.
036 * <p>
037 * Requires {@code Bouncy Castle}. This class is part of the {@code acme4j-utils} module.
038 */
039public class KeyPairUtils {
040
041    private KeyPairUtils() {
042        // utility class without constructor
043    }
044
045    /**
046     * Creates a new RSA {@link KeyPair}.
047     *
048     * @param keysize
049     *            Key size
050     * @return Generated {@link KeyPair}
051     */
052    public static KeyPair createKeyPair(int keysize) {
053        try {
054            KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
055            keyGen.initialize(keysize);
056            return keyGen.generateKeyPair();
057        } catch (NoSuchAlgorithmException ex) {
058            throw new IllegalStateException(ex);
059        }
060    }
061
062    /**
063     * Creates a new elliptic curve {@link KeyPair}.
064     *
065     * @param name
066     *            ECDSA curve name (e.g. "secp256r1")
067     * @return Generated {@link KeyPair}
068     */
069    public static KeyPair createECKeyPair(String name) {
070        try {
071            ECParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec(name);
072            KeyPairGenerator g = KeyPairGenerator.getInstance("ECDSA", "BC");
073            g.initialize(ecSpec, new SecureRandom());
074            return g.generateKeyPair();
075        } catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException ex) {
076            throw new IllegalArgumentException("Invalid curve name " + name, ex);
077        } catch (NoSuchProviderException ex) {
078            throw new IllegalStateException(ex);
079        }
080    }
081
082    /**
083     * Reads a {@link KeyPair} from a PEM file.
084     *
085     * @param r
086     *            {@link Reader} to read the PEM file from. The {@link Reader} is closed
087     *            after use.
088     * @return {@link KeyPair} read
089     */
090    public static KeyPair readKeyPair(Reader r) throws IOException {
091        try (PEMParser parser = new PEMParser(r)) {
092            PEMKeyPair keyPair = (PEMKeyPair) parser.readObject();
093            return new JcaPEMKeyConverter().getKeyPair(keyPair);
094        } catch (PEMException ex) {
095            throw new IOException("Invalid PEM file", ex);
096        }
097    }
098
099    /**
100     * Writes a {@link KeyPair} PEM file.
101     *
102     * @param keypair
103     *            {@link KeyPair} to write
104     * @param w
105     *            {@link Writer} to write the PEM file to. The {@link Writer} is closed
106     *            after use.
107     */
108    public static void writeKeyPair(KeyPair keypair, Writer w) throws IOException {
109        try (JcaPEMWriter jw = new JcaPEMWriter(w)) {
110            jw.writeObject(keypair);
111        }
112    }
113
114}