KeyUtils.java
/*
* GovWay - A customizable API Gateway
* https://govway.org
*
* Copyright (c) 2005-2024 Link.it srl (https://link.it).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3, as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.openspcoop2.utils.certificate;
import java.io.ByteArrayInputStream;
import java.io.InputStreamReader;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import org.apache.commons.lang.StringUtils;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.openssl.PEMDecryptorProvider;
import org.bouncycastle.openssl.PEMEncryptedKeyPair;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder;
import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
import org.bouncycastle.operator.InputDecryptorProvider;
import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
import org.bouncycastle.util.io.pem.PemReader;
import org.openspcoop2.utils.UtilsException;
/**
* KeyUtils
*
* @author Poli Andrea (apoli@link.it)
* @author $Author$
* @version $Rev$, $Date$
*/
public class KeyUtils {
public static final String ALGO_RSA = "RSA";
public static final String ALGO_DSA = "DSA";
public static final String ALGO_DH = "DH"; // Diffie-Hellman
public static final String ALGO_EC = "EC"; // Elliptic Curve Digital Signature Algorithm o ECDH (Elliptic Curve Diffie-Hellman).
public static KeyUtils getInstance() throws UtilsException {
return new KeyUtils();
}
public static KeyUtils getInstance(String algo) throws UtilsException {
return new KeyUtils(algo);
}
private KeyFactory kf;
public KeyUtils() throws UtilsException {
this(ALGO_RSA);
}
public KeyUtils(String algo) throws UtilsException {
try {
this.kf = KeyFactory.getInstance(algo);
}catch(Exception e) {
throw new UtilsException(e.getMessage(),e);
}
}
// ** PUBLIC KEY **/
public PublicKey readPublicKeyPEMFormat(byte[] publicKey) throws UtilsException {
PEMReader pemArchive = new PEMReader(publicKey);
if(pemArchive.getPublicKey()!=null) {
publicKey = pemArchive.getPublicKey().getBytes();
}
try {
try (ByteArrayInputStream bin = new ByteArrayInputStream(publicKey);
InputStreamReader ir = new InputStreamReader(bin);
PemReader pemReader = new PemReader(ir);){
byte [] encoded = pemReader.readPemObject().getContent();
X509EncodedKeySpec specPub = new X509EncodedKeySpec(encoded);
return this.kf.generatePublic(specPub);
}
}catch(Exception e) {
throw new UtilsException(e.getMessage(),e);
}
}
public PublicKey readPublicKeyDERFormat(byte[] publicKey) throws UtilsException {
try {
X509EncodedKeySpec specPub = new X509EncodedKeySpec(publicKey);
return this.kf.generatePublic(specPub);
}catch(Exception e) {
throw new UtilsException(e.getMessage(),e);
}
}
public PublicKey readCertificate(byte[] publicKey) throws UtilsException {
PEMReader pemArchive = new PEMReader(publicKey);
if(pemArchive.getCertificates()!=null && !pemArchive.getCertificates().isEmpty()) {
String cert = pemArchive.getCertificates().get(0); // prendo il primo
if(cert!=null && StringUtils.isNotEmpty(cert)) {
publicKey = cert.getBytes();
}
}
return ArchiveLoader.load(publicKey).getCertificate().getCertificate().getPublicKey();
}
public PublicKey getPublicKey(byte[] publicKey) throws UtilsException {
PEMReader pemArchive = new PEMReader(publicKey);
if(pemArchive.getPublicKey()!=null) {
return this.readPublicKeyPEMFormat(pemArchive.getPublicKey().getBytes());
}
else if(pemArchive.getCertificates()!=null && !pemArchive.getCertificates().isEmpty()) {
String cert = pemArchive.getCertificates().get(0); // prendo il primo
if(cert!=null && StringUtils.isNotEmpty(cert)) {
return this.readCertificate(cert.getBytes());
}
}
try {
return readPublicKeyDERFormat(publicKey);
}catch(Exception e) {
// provo X509
try {
return readCertificate(publicKey);
}catch(Exception ignore) {
// rilancio eccezione precedente
throw new UtilsException(e.getMessage(),e);
}
}
}
// ** PRIVATE KEY **/
public PrivateKey readPKCS1PrivateKeyPEMFormat(byte[] privateKey) throws UtilsException {
PEMReader pemArchive = new PEMReader(privateKey,true,false,false);
if(pemArchive.getPrivateKey()!=null) {
privateKey = pemArchive.getPrivateKey().getBytes();
}
// Legge nel formato PEM PKCS1 e lo porta in PKCS8
try {
try (ByteArrayInputStream bin = new ByteArrayInputStream(privateKey);
InputStreamReader ir = new InputStreamReader(bin);){
PEMParser pemParser = new PEMParser(ir);
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider(org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME);
Object object = pemParser.readObject();
KeyPair kp = converter.getKeyPair((PEMKeyPair) object);
return kp.getPrivate();
}
}catch(Exception e) {
throw new UtilsException(e.getMessage(),e);
}
}
public PrivateKey readPKCS8PrivateKeyPEMFormat(byte[] privateKey) throws UtilsException {
PEMReader pemArchive = new PEMReader(privateKey,false,true,false);
if(pemArchive.getPrivateKey()!=null) {
privateKey = pemArchive.getPrivateKey().getBytes();
}
try {
try (ByteArrayInputStream bin = new ByteArrayInputStream(privateKey);
InputStreamReader ir = new InputStreamReader(bin);
PemReader pemReader = new PemReader(ir);){
byte [] encoded = pemReader.readPemObject().getContent();
PKCS8EncodedKeySpec specPriv = new PKCS8EncodedKeySpec(encoded);
return this.kf.generatePrivate(specPriv);
}
}catch(Exception e) {
throw new UtilsException(e.getMessage(),e);
}
}
public PrivateKey readPKCS8PrivateKeyDERFormat(byte[] privateKey) throws UtilsException {
try {
PKCS8EncodedKeySpec specPriv = new PKCS8EncodedKeySpec(privateKey);
return this.kf.generatePrivate(specPriv);
}catch(Exception e) {
throw new UtilsException(e.getMessage(),e);
}
}
public PrivateKey getPrivateKey(byte[] privateKey) throws UtilsException {
PEMReader pemArchive = new PEMReader(privateKey);
if(pemArchive.getPrivateKey()!=null) {
privateKey = pemArchive.getPrivateKey().getBytes();
if(pemArchive.isPkcs1()) {
return this.readPKCS1PrivateKeyPEMFormat(privateKey);
}
else if(pemArchive.isPkcs8()) {
return this.readPKCS8PrivateKeyPEMFormat(privateKey);
}
}
return readPKCS8PrivateKeyDERFormat(privateKey);
}
// ** PRIVATE KEY ENCRYPTED **/
public PrivateKey readPKCS1EncryptedPrivateKeyPEMFormat(byte[] privateKey, String password) throws UtilsException{
PEMReader pemArchive = new PEMReader(privateKey,true,false,false);
if(pemArchive.getPrivateKey()!=null) {
privateKey = pemArchive.getPrivateKey().getBytes();
}
// Legge nel formato PEM PKCS1 e lo porta in PKCS8
try {
try (ByteArrayInputStream bin = new ByteArrayInputStream(privateKey);
InputStreamReader ir = new InputStreamReader(bin);){
PEMParser pemParser = new PEMParser(ir);
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider(org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME);
Object object = pemParser.readObject();
PEMEncryptedKeyPair pair = (PEMEncryptedKeyPair) object;
JcePEMDecryptorProviderBuilder jce = new JcePEMDecryptorProviderBuilder().setProvider(org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME);
PEMDecryptorProvider decProv = jce.build(password.toCharArray());
KeyPair kp = converter.getKeyPair(pair.decryptKeyPair(decProv));
return kp.getPrivate();
}
}catch(Exception e) {
throw new UtilsException(e.getMessage(),e);
}
}
public PrivateKey readPKCS8EncryptedPrivateKeyPEMFormat(byte[] privateKey, String password) throws UtilsException{
PEMReader pemArchive = new PEMReader(privateKey,false,false,true);
if(pemArchive.getPrivateKey()!=null) {
privateKey = pemArchive.getPrivateKey().getBytes();
}
PKCS8EncryptedPrivateKeyInfo pair = null;
try {
try (ByteArrayInputStream bin = new ByteArrayInputStream(privateKey);
InputStreamReader ir = new InputStreamReader(bin);){
PEMParser parser = new PEMParser(ir);
pair = (PKCS8EncryptedPrivateKeyInfo)parser.readObject();
}
}catch(Exception e) {
throw new UtilsException(e.getMessage(),e);
}
return readPKCS8EncryptedPrivateKey(pair, password);
}
public PrivateKey readPKCS8EncryptedPrivateKeyDERFormat(byte[] privateKey, String password) throws UtilsException{
PKCS8EncryptedPrivateKeyInfo pair = null;
try {
pair = new PKCS8EncryptedPrivateKeyInfo(privateKey);
}catch(Exception e) {
throw new UtilsException(e.getMessage(),e);
}
return readPKCS8EncryptedPrivateKey(pair, password);
}
private PrivateKey readPKCS8EncryptedPrivateKey(PKCS8EncryptedPrivateKeyInfo pair, String password) throws UtilsException{
try {
JceOpenSSLPKCS8DecryptorProviderBuilder jce = new JceOpenSSLPKCS8DecryptorProviderBuilder().setProvider(org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME);
InputDecryptorProvider decProv = jce.build(password.toCharArray());
PrivateKeyInfo keyInfo = pair.decryptPrivateKeyInfo(decProv);
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider(org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME);
return converter.getPrivateKey(keyInfo);
}catch(Exception e) {
throw new UtilsException(e.getMessage(),e);
}
}
public PrivateKey getPrivateKey(byte[] privateKey, String password) throws UtilsException {
PEMReader pemArchive = new PEMReader(privateKey);
if(pemArchive.getPrivateKey()!=null) {
privateKey = pemArchive.getPrivateKey().getBytes();
if(pemArchive.isPkcs8encrypted()) {
return this.readPKCS8EncryptedPrivateKeyPEMFormat(privateKey, password);
}
else if(pemArchive.isPkcs1()) {
try {
return this.readPKCS1EncryptedPrivateKeyPEMFormat(privateKey, password);
}catch(Exception e) {
// provo senza password
try {
return this.readPKCS1PrivateKeyPEMFormat(privateKey);
}catch(Exception ignore) {
// rilancio eccezione precedente
throw new UtilsException(e.getMessage(),e);
}
}
}
else if(pemArchive.isPkcs8()) {
return this.readPKCS8PrivateKeyPEMFormat(privateKey);
}
}
try {
return readPKCS8EncryptedPrivateKeyDERFormat(privateKey, password);
}catch(Exception e) {
// provo senza password
try {
return readPKCS8PrivateKeyDERFormat(privateKey);
}catch(Exception ignore) {
// rilancio eccezione precedente
throw new UtilsException(e.getMessage(),e);
}
}
}
}