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 standard {@link KeyPair}. 047 * <p> 048 * This method can be used if no specific key type is required. It returns a 049 * "secp384r1" ECDSA key pair. 050 * 051 * @return Generated {@link KeyPair} 052 * @since 2.8 053 */ 054 public static KeyPair createKeyPair() { 055 return createECKeyPair("secp384r1"); 056 } 057 058 /** 059 * Creates a new RSA {@link KeyPair}. 060 * 061 * @param keysize 062 * Key size 063 * @return Generated {@link KeyPair} 064 */ 065 public static KeyPair createKeyPair(int keysize) { 066 try { 067 KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); 068 keyGen.initialize(keysize); 069 return keyGen.generateKeyPair(); 070 } catch (NoSuchAlgorithmException ex) { 071 throw new IllegalStateException(ex); 072 } 073 } 074 075 /** 076 * Creates a new elliptic curve {@link KeyPair}. 077 * 078 * @param name 079 * ECDSA curve name (e.g. "secp256r1") 080 * @return Generated {@link KeyPair} 081 */ 082 public static KeyPair createECKeyPair(String name) { 083 try { 084 ECParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec(name); 085 KeyPairGenerator g = KeyPairGenerator.getInstance("ECDSA", "BC"); 086 g.initialize(ecSpec, new SecureRandom()); 087 return g.generateKeyPair(); 088 } catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException ex) { 089 throw new IllegalArgumentException("Invalid curve name " + name, ex); 090 } catch (NoSuchProviderException ex) { 091 throw new IllegalStateException(ex); 092 } 093 } 094 095 /** 096 * Reads a {@link KeyPair} from a PEM file. 097 * 098 * @param r 099 * {@link Reader} to read the PEM file from. The {@link Reader} is closed 100 * after use. 101 * @return {@link KeyPair} read 102 */ 103 public static KeyPair readKeyPair(Reader r) throws IOException { 104 try (PEMParser parser = new PEMParser(r)) { 105 PEMKeyPair keyPair = (PEMKeyPair) parser.readObject(); 106 return new JcaPEMKeyConverter().getKeyPair(keyPair); 107 } catch (PEMException ex) { 108 throw new IOException("Invalid PEM file", ex); 109 } 110 } 111 112 /** 113 * Writes a {@link KeyPair} PEM file. 114 * 115 * @param keypair 116 * {@link KeyPair} to write 117 * @param w 118 * {@link Writer} to write the PEM file to. The {@link Writer} is closed 119 * after use. 120 */ 121 public static void writeKeyPair(KeyPair keypair, Writer w) throws IOException { 122 try (JcaPEMWriter jw = new JcaPEMWriter(w)) { 123 jw.writeObject(keypair); 124 } 125 } 126 127}