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}