KeyUtils.java

  1. /*
  2.  * GovWay - A customizable API Gateway
  3.  * https://govway.org
  4.  *
  5.  * Copyright (c) 2005-2025 Link.it srl (https://link.it).
  6.  *
  7.  * This program is free software: you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License version 3, as published by
  9.  * the Free Software Foundation.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18.  *
  19.  */
  20. package org.openspcoop2.utils.certificate;

  21. import java.io.ByteArrayInputStream;
  22. import java.io.InputStreamReader;
  23. import java.security.KeyFactory;
  24. import java.security.KeyPair;
  25. import java.security.PrivateKey;
  26. import java.security.PublicKey;
  27. import java.security.spec.PKCS8EncodedKeySpec;
  28. import java.security.spec.X509EncodedKeySpec;

  29. import org.apache.commons.lang.StringUtils;
  30. import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
  31. import org.bouncycastle.openssl.PEMDecryptorProvider;
  32. import org.bouncycastle.openssl.PEMEncryptedKeyPair;
  33. import org.bouncycastle.openssl.PEMKeyPair;
  34. import org.bouncycastle.openssl.PEMParser;
  35. import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
  36. import org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder;
  37. import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
  38. import org.bouncycastle.operator.InputDecryptorProvider;
  39. import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
  40. import org.bouncycastle.util.io.pem.PemReader;
  41. import org.openspcoop2.utils.UtilsException;

  42. /**
  43.  * KeyUtils
  44.  *
  45.  * @author Poli Andrea (apoli@link.it)
  46.  * @author $Author$
  47.  * @version $Rev$, $Date$
  48.  */
  49. public class KeyUtils {

  50.     public static final String ALGO_RSA = "RSA";
  51.     public static final String ALGO_DSA = "DSA";
  52.     public static final String ALGO_DH = "DH"; // Diffie-Hellman
  53.     public static final String ALGO_EC = "EC"; // Elliptic Curve Digital Signature Algorithm o ECDH (Elliptic Curve Diffie-Hellman).

  54.    
  55.     public static KeyUtils getInstance() throws UtilsException {
  56.         return new KeyUtils();
  57.     }
  58.     public static KeyUtils getInstance(String algo) throws UtilsException {
  59.         return new KeyUtils(algo);
  60.     }
  61.    
  62.     private KeyFactory kf;
  63.    
  64.     public KeyUtils() throws UtilsException {
  65.         this(ALGO_RSA);
  66.     }
  67.     public KeyUtils(String algo) throws UtilsException {
  68.         try {
  69.             this.kf = KeyFactory.getInstance(algo);
  70.         }catch(Exception e) {
  71.             throw new UtilsException(e.getMessage(),e);
  72.         }
  73.     }
  74.    
  75.     // ** PUBLIC KEY **/
  76.    
  77.     public PublicKey readPublicKeyPEMFormat(byte[] publicKey) throws UtilsException {
  78.        
  79.         PEMReader pemArchive = new PEMReader(publicKey);
  80.         if(pemArchive.getPublicKey()!=null) {
  81.             publicKey = pemArchive.getPublicKey().getBytes();
  82.         }
  83.        
  84.         try {
  85.             try (ByteArrayInputStream bin = new ByteArrayInputStream(publicKey);
  86.                     InputStreamReader ir = new InputStreamReader(bin);
  87.                     PemReader pemReader = new PemReader(ir);){
  88.                 byte [] encoded = pemReader.readPemObject().getContent();
  89.                 X509EncodedKeySpec specPub = new X509EncodedKeySpec(encoded);
  90.                 return this.kf.generatePublic(specPub);
  91.             }
  92.         }catch(Exception e) {
  93.             throw new UtilsException(e.getMessage(),e);
  94.         }
  95.     }
  96.     public PublicKey readPublicKeyDERFormat(byte[] publicKey) throws UtilsException {
  97.         try {
  98.             X509EncodedKeySpec specPub = new X509EncodedKeySpec(publicKey);
  99.             return this.kf.generatePublic(specPub);
  100.         }catch(Exception e) {
  101.             throw new UtilsException(e.getMessage(),e);
  102.         }
  103.     }
  104.     public PublicKey readCertificate(byte[] publicKey) throws UtilsException {
  105.        
  106.         PEMReader pemArchive = new PEMReader(publicKey);
  107.         if(pemArchive.getCertificates()!=null && !pemArchive.getCertificates().isEmpty()) {
  108.             String cert = pemArchive.getCertificates().get(0); // prendo il primo
  109.             if(cert!=null && StringUtils.isNotEmpty(cert)) {
  110.                 publicKey = cert.getBytes();
  111.             }
  112.         }
  113.        
  114.         return ArchiveLoader.load(publicKey).getCertificate().getCertificate().getPublicKey();
  115.     }
  116.    
  117.     public PublicKey getPublicKey(byte[] publicKey) throws UtilsException {
  118.        
  119.         PEMReader pemArchive = new PEMReader(publicKey);
  120.        
  121.         if(pemArchive.getPublicKey()!=null) {
  122.             return this.readPublicKeyPEMFormat(pemArchive.getPublicKey().getBytes());
  123.         }
  124.         else if(pemArchive.getCertificates()!=null && !pemArchive.getCertificates().isEmpty()) {
  125.             String cert = pemArchive.getCertificates().get(0); // prendo il primo
  126.             if(cert!=null && StringUtils.isNotEmpty(cert)) {
  127.                 return this.readCertificate(cert.getBytes());
  128.             }
  129.         }
  130.        
  131.         try {
  132.             return readPublicKeyDERFormat(publicKey);
  133.         }catch(Exception e) {
  134.             // provo X509
  135.             try {
  136.                 return readCertificate(publicKey);
  137.             }catch(Exception ignore) {
  138.                 // rilancio eccezione precedente
  139.                 throw new UtilsException(e.getMessage(),e);
  140.             }
  141.         }
  142.        
  143.     }
  144.    
  145.    
  146.     // ** PRIVATE KEY **/
  147.    
  148.     public PrivateKey readPKCS1PrivateKeyPEMFormat(byte[] privateKey) throws UtilsException {
  149.        
  150.         PEMReader pemArchive = new PEMReader(privateKey,true,false,false);
  151.         if(pemArchive.getPrivateKey()!=null) {
  152.             privateKey = pemArchive.getPrivateKey().getBytes();
  153.         }
  154.        
  155.         // Legge nel formato PEM PKCS1 e lo porta in PKCS8
  156.        
  157.         try {
  158.             try (ByteArrayInputStream bin = new ByteArrayInputStream(privateKey);
  159.                     InputStreamReader ir = new InputStreamReader(bin);){
  160.                 PEMParser pemParser = new PEMParser(ir);
  161.                 JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider(org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME);
  162.                 Object object = pemParser.readObject();
  163.                 KeyPair kp = converter.getKeyPair((PEMKeyPair) object);
  164.                 return kp.getPrivate();
  165.             }
  166.         }catch(Exception e) {
  167.             throw new UtilsException(e.getMessage(),e);
  168.         }
  169.     }
  170.    
  171.     public PrivateKey readPKCS8PrivateKeyPEMFormat(byte[] privateKey) throws UtilsException {
  172.        
  173.         PEMReader pemArchive = new PEMReader(privateKey,false,true,false);
  174.         if(pemArchive.getPrivateKey()!=null) {
  175.             privateKey = pemArchive.getPrivateKey().getBytes();
  176.         }
  177.        
  178.         try {
  179.             try (ByteArrayInputStream bin = new ByteArrayInputStream(privateKey);
  180.                     InputStreamReader ir = new InputStreamReader(bin);
  181.                     PemReader pemReader = new PemReader(ir);){
  182.                 byte [] encoded = pemReader.readPemObject().getContent();
  183.                 PKCS8EncodedKeySpec specPriv = new PKCS8EncodedKeySpec(encoded);
  184.                 return this.kf.generatePrivate(specPriv);
  185.             }
  186.         }catch(Exception e) {
  187.             throw new UtilsException(e.getMessage(),e);
  188.         }
  189.     }
  190.    
  191.     public PrivateKey readPKCS8PrivateKeyDERFormat(byte[] privateKey) throws UtilsException {
  192.         try {
  193.             PKCS8EncodedKeySpec specPriv = new PKCS8EncodedKeySpec(privateKey);
  194.             return this.kf.generatePrivate(specPriv);
  195.         }catch(Exception e) {
  196.             throw new UtilsException(e.getMessage(),e);
  197.         }
  198.     }
  199.    
  200.     public PrivateKey getPrivateKey(byte[] privateKey) throws UtilsException {
  201.        
  202.         PEMReader pemArchive = new PEMReader(privateKey);
  203.         if(pemArchive.getPrivateKey()!=null) {
  204.             privateKey = pemArchive.getPrivateKey().getBytes();
  205.            
  206.             if(pemArchive.isPkcs1()) {
  207.                 return this.readPKCS1PrivateKeyPEMFormat(privateKey);  
  208.             }
  209.             else if(pemArchive.isPkcs8()) {
  210.                 return this.readPKCS8PrivateKeyPEMFormat(privateKey);
  211.             }
  212.         }
  213.        
  214.         return readPKCS8PrivateKeyDERFormat(privateKey);
  215.     }
  216.    
  217.    
  218.     // ** PRIVATE KEY ENCRYPTED **/
  219.    
  220.     public PrivateKey readPKCS1EncryptedPrivateKeyPEMFormat(byte[] privateKey, String password) throws UtilsException{
  221.        
  222.         PEMReader pemArchive = new PEMReader(privateKey,true,false,false);
  223.         if(pemArchive.getPrivateKey()!=null) {
  224.             privateKey = pemArchive.getPrivateKey().getBytes();
  225.         }
  226.        
  227.         // Legge nel formato PEM PKCS1 e lo porta in PKCS8
  228.        
  229.         try {
  230.             try (ByteArrayInputStream bin = new ByteArrayInputStream(privateKey);
  231.                     InputStreamReader ir = new InputStreamReader(bin);){
  232.                 PEMParser pemParser = new PEMParser(ir);
  233.                 JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider(org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME);
  234.                 Object object = pemParser.readObject();
  235.                 PEMEncryptedKeyPair pair = (PEMEncryptedKeyPair) object;
  236.                 JcePEMDecryptorProviderBuilder jce = new JcePEMDecryptorProviderBuilder().setProvider(org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME);
  237.                 PEMDecryptorProvider decProv = jce.build(password.toCharArray());
  238.                 KeyPair kp = converter.getKeyPair(pair.decryptKeyPair(decProv));
  239.                 return kp.getPrivate();
  240.             }
  241.         }catch(Exception e) {
  242.             throw new UtilsException(e.getMessage(),e);
  243.         }

  244.     }
  245.        
  246.     public PrivateKey readPKCS8EncryptedPrivateKeyPEMFormat(byte[] privateKey, String password) throws UtilsException{
  247.            
  248.         PEMReader pemArchive = new PEMReader(privateKey,false,false,true);
  249.         if(pemArchive.getPrivateKey()!=null) {
  250.             privateKey = pemArchive.getPrivateKey().getBytes();
  251.         }
  252.        
  253.         PKCS8EncryptedPrivateKeyInfo pair = null;
  254.         try {
  255.             try (ByteArrayInputStream bin = new ByteArrayInputStream(privateKey);
  256.                     InputStreamReader ir = new InputStreamReader(bin);){
  257.                 PEMParser parser = new PEMParser(ir);
  258.                 pair = (PKCS8EncryptedPrivateKeyInfo)parser.readObject();
  259.             }
  260.         }catch(Exception e) {
  261.             throw new UtilsException(e.getMessage(),e);
  262.         }
  263.         return readPKCS8EncryptedPrivateKey(pair, password);

  264.     }
  265.    
  266.     public PrivateKey readPKCS8EncryptedPrivateKeyDERFormat(byte[] privateKey, String password) throws UtilsException{
  267.         PKCS8EncryptedPrivateKeyInfo pair = null;
  268.         try {
  269.             pair = new PKCS8EncryptedPrivateKeyInfo(privateKey);
  270.         }catch(Exception e) {
  271.             throw new UtilsException(e.getMessage(),e);
  272.         }
  273.         return readPKCS8EncryptedPrivateKey(pair, password);
  274.     }
  275.    
  276.     private PrivateKey readPKCS8EncryptedPrivateKey(PKCS8EncryptedPrivateKeyInfo pair, String password) throws UtilsException{
  277.         try {
  278.             JceOpenSSLPKCS8DecryptorProviderBuilder jce = new JceOpenSSLPKCS8DecryptorProviderBuilder().setProvider(org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME);
  279.             InputDecryptorProvider decProv = jce.build(password.toCharArray());
  280.             PrivateKeyInfo keyInfo = pair.decryptPrivateKeyInfo(decProv);
  281.             JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider(org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME);
  282.             return converter.getPrivateKey(keyInfo);
  283.         }catch(Exception e) {
  284.             throw new UtilsException(e.getMessage(),e);
  285.         }
  286.     }
  287.    
  288.     public PrivateKey getPrivateKey(byte[] privateKey, String password) throws UtilsException {
  289.        
  290.         PEMReader pemArchive = new PEMReader(privateKey);
  291.         if(pemArchive.getPrivateKey()!=null) {
  292.             privateKey = pemArchive.getPrivateKey().getBytes();
  293.            
  294.             if(pemArchive.isPkcs8encrypted()) {
  295.                 return this.readPKCS8EncryptedPrivateKeyPEMFormat(privateKey, password);
  296.             }
  297.             else if(pemArchive.isPkcs1()) {
  298.                 try {
  299.                     return this.readPKCS1EncryptedPrivateKeyPEMFormat(privateKey, password);
  300.                 }catch(Exception e) {
  301.                     // provo senza password
  302.                     try {
  303.                         return this.readPKCS1PrivateKeyPEMFormat(privateKey);
  304.                     }catch(Exception ignore) {
  305.                         // rilancio eccezione precedente
  306.                         throw new UtilsException(e.getMessage(),e);
  307.                     }
  308.                 }  
  309.             }
  310.             else if(pemArchive.isPkcs8()) {
  311.                 return this.readPKCS8PrivateKeyPEMFormat(privateKey);
  312.             }
  313.         }
  314.                
  315.         try {
  316.             return readPKCS8EncryptedPrivateKeyDERFormat(privateKey, password);
  317.         }catch(Exception e) {
  318.             // provo senza password
  319.             try {
  320.                 return readPKCS8PrivateKeyDERFormat(privateKey);
  321.             }catch(Exception ignore) {
  322.                 // rilancio eccezione precedente
  323.                 throw new UtilsException(e.getMessage(),e);
  324.             }
  325.         }
  326.        
  327.     }

  328.    
  329. }