it-swarm-eu.dev

Come usare le chiavi generate da OpenSSL in Java?

Ho la mia coppia di chiavi pubbliche e private e il mio certificato. Quelli dove sono stati creati in OpenSSL (perché? Perché mi è stato chiesto di farlo in OpenSSL). Ora voglio usare queste cose per creare un Java che utilizza le firme digitali. Come posso usare le mie chiavi pubbliche e private per crittografare/decrittografare le informazioni (e usare il certificato per vedere se i dati sono valido? Quali sono le classi in Java che mi permettono di farlo?

Le mie chiavi sono in chiaro: qualcosa del genere:

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

[~ ~ #] aggiornamento [~ ~ #]

Ho creato questo codice ma non riesco ancora a utilizzare la chiave privata per firmare una stringa.

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));
}

l'eccezione che sto ottenendo è

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
11
BRabbit27

Se hai una chiave pubblica in questo modulo (e non all'interno di un certificato), ti consiglio di usare BouncyCastle 's PEMReader. Il suo metodo readObject() può leggere molto per i formati: chiavi pubbliche, certificati, chiavi private (anche se potrebbe essere necessario utilizzare il metodo con una password) ...

Se non vuoi usare BouncyCastle, puoi leggere i certificati usando CertificateFactory (vedi esempi). Con un certificato in formato PEM in un InputStream:

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

Per le chiavi private, se la tua chiave privata è una struttura PKCS # 8 in formato DER, puoi leggerla direttamente usando PKCS8EncodedKeySpec . Per esempio:

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

Puoi convertire la tua chiave privata in PKCS # 8 usando openssl pkcs8 -topk8 (Ricorda -outform DER, Potresti anche voler controllare le suite di cifratura poiché non tutti potrebbero essere comunemente supportati da entrambi Java e OpenSSL).

  • Dal punto di vista dell'utilizzo del keystore:

Se non vuoi fare molta programmazione per gestire le chiavi, per passare da Java e OpenSSL, è conveniente usare il formato PKCS # 12.

Se le chiavi e i certificati prodotti con OpenSSL non si trovano già in un contenitore p12:

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

In generale, è possibile utilizzare direttamente il, utilizzando il tipo di archivio chiavi [PKCS12 "Di Java (invece di" JKS "per impostazione predefinita).

Se necessario, è possibile convertire questo keystore PKCS12 in un altro formato (ad esempio JKS) utilizzando keytool (Java 6+):

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

(Essenzialmente, l'operazione opposta a quella descritta in questa domanda .)

Ad ogni modo, sia usando PEMReader o caricando la tua chiave/certificato da un KeyStore, dovresti essere in grado di ottenere istanze di PrivateKey e Certificate (oppure PublicKey direttamente).

Puoi verificare che la firma di Certificate sia stata eseguita utilizzando la chiave privata corrispondente a una determinata chiave pubblica utilizzando il suo metodo verify(PublicKey).

Con loro, puoi anche usare API per la firma digitale . È un'API più generale per qualsiasi firma di documento e non verificherei necessariamente una firma di certificato con essa (preferirei utilizzare l'API del percorso di certificazione per questo, poiché costruirà anche la catena).

10
Bruno