¿Cómo usar las claves generadas por OpenSSL en Java?

11

Tengo mi par de claves públicas y privadas y mi certificado. Aquellos donde se crearon en OpenSSL (¿por qué? Porque me pidieron que lo hiciera en OpenSSL).   Ahora quiero usar esas cosas para crear una aplicación Java que use firmas digitales.   ¿Cómo puedo usar mis claves privadas y públicas para cifrar / descifrar información (y usar el certificado para ver si los datos son válidos? ¿Cuáles son las clases en java que me permiten hacer eso?

Mis claves están en texto plano algo como esto:

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDuyg3h0VbP9iZ6RCxSU6x4WX4
anAwedMVUTqF0WHlvHl1Kiqa6N6TiUk23uXAVUX8RwLFjXWHlG0xwW7mGByA2mX9
5oPQpQFu8C70aMuUotGv87iiLi0UKCZV+9wS9rMdg5LHu1mMPilwgOO6MlyTxKem
-----END PUBLIC KEY-----

ACTUALIZAR

Hice este código pero aún no puedo usar la clave privada para firmar una cadena.

public void encryptHash(String hashToEncrypt, String pathOfKey, String Algorithm) {
    FileInputStream fis = null;
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    int len;

        File f = new File(pathOfKey);

        fis = new FileInputStream(pathOfKey);
        len = 0;
        while((len = fis.read()) != -1){
            baos.write(len);
        }

        KeyFactory kf = KeyFactory.getInstance(Algorithm); //Algorithm = "RSA"
        KeySpec keySpec = new PKCS8EncodedKeySpec(baos.toByteArray());
        baos.close();
        PrivateKey privateKey = kf.generatePrivate(keySpec);  //Here's the exception thrown

        Signature rsaSigner = Signature.getInstance("SHA1withRSA");
        rsaSigner.initSign(privateKey);

        fis = new FileInputStream(hashToEncrypt);
        BufferedInputStream bis = new BufferedInputStream(fis);
        byte[] buffer = new byte[1024];
        len = 0;
        while((len = bis.read(buffer)) >= 0){
            try {
                rsaSigner.update(buffer, 0, len);
            } catch (SignatureException ex) {
                Logger.getLogger(DataEncryptor.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        bis.close();

        byte[] signature = rsaSigner.sign();

        System.out.println(new String(signature));
}

la excepción que estoy obteniendo es

dic 09, 2011 12:49:02 PM firmaelectronica.DataEncryptor encryptHash
Grave: null
java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException : DER input, Integer tag error
    at sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(RSAKeyFactory.java:217)
    at java.security.KeyFactory.generatePrivate(KeyFactory.java:372)
    at firmaelectronica.DataEncryptor.encryptHash(DataEncryptor.java:40)
    at firmaelectronica.FirmaElectronica.main(FirmaElectronica.java:39)
Caused by: java.security.InvalidKeyException: IOException : DER input, Integer tag error
    at sun.security.pkcs.PKCS8Key.decode(PKCS8Key.java:361)
    at sun.security.pkcs.PKCS8Key.decode(PKCS8Key.java:367)
    at sun.security.rsa.RSAPrivateCrtKeyImpl.<init>(RSAPrivateCrtKeyImpl.java:91)
    at sun.security.rsa.RSAPrivateCrtKeyImpl.newKey(RSAPrivateCrtKeyImpl.java:75)
    at sun.security.rsa.RSAKeyFactory.generatePrivate(RSAKeyFactory.java:316)
    at sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(RSAKeyFactory.java:213)
    ... 3 more
    
pregunta BRabbit27 09.12.2011 - 00:22
fuente

1 respuesta

10

Si tiene una clave pública en este formulario (y no dentro de un certificado), le recomendaría que use BouncyCastle 's PEMReader . Su método readObject() puede leer mucho los formatos: claves públicas, certificados, claves privadas (aunque es posible que necesite usar el método con una contraseña) ...

Si no desea utilizar BouncyCastle, puede leer los certificados utilizando CertificateFactory (ver ejemplos). Con un certificado en formato PEM en un InputStream:

CertificateFactory cf = CertificateFactory.getInstance("X.509");
Certificate cert = cf.generateCertificate(inputStream);

Para claves privadas, si su clave privada es una estructura PKCS # 8 en formato DER, puede leerla directamente usando PKCS8EncodedKeySpec . Por ejemplo:

KeyFactory kf = KeyFactory.getInstance("RSA");
// Read privateKeyDerByteArray from DER file.
KeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyDerByteArray);
PrivateKey key = kf.generatePrivate(keySpec);

Puede convertir su clave privada en PKCS # 8 usando openssl pkcs8 -topk8 (recuerde -outform DER , es posible que también desee verificar los conjuntos de cifrado, ya que no todos pueden ser compatibles con Java y OpenSSL).

  • Desde el punto de vista del uso del almacén de claves:

Si no desea realizar mucha programación para manejar las claves, para ir entre Java y OpenSSL, es conveniente utilizar el formato PKCS # 12.

Si las claves y los certificados que ha producido con OpenSSL aún no están en un contenedor p12:

openssl pkcs12 -export -in cert.pem -inkey key.pem -out store.p12

En general, puede utilizar el tipo de almacén de claves " PKCS12 " de Java directamente (en lugar de " JKS " de forma predeterminada).

Si es necesario, puede convertir este almacén de claves PKCS12 a otro formato (por ejemplo, JKS) usando keytool (Java 6+):

keytool -importkeystore -srckeystore store.p12 -srcstoretype PKCS12 \
     -destkeystore store.jks -deststoretype JKS

(En esencia, la operación opuesta a la descrita en esta pregunta .)

De cualquier manera, ya sea usando PEMReader o cargando su clave / certificado desde un KeyStore , debería poder obtener instancias de PrivateKey y Certificate (o PublicKey directamente).

Puede verificar que la firma de un Certificate se haya realizado utilizando la clave privada que coincide con una clave pública determinada mediante su método verify(PublicKey) .

Con ellos, también puede utilizar la API de firma digital . Es una API más general para cualquier firma de documento, y no necesariamente verificaría una firma de certificado con ella (preferiría usar la API de ruta de certificación para esto, ya que también construirá la cadena).

    
respondido por el Bruno 09.12.2011 - 00:41
fuente

Lea otras preguntas en las etiquetas