it-swarm-id.com

Bagaimana cara menggunakan kunci yang dihasilkan OpenSSL di Jawa?

Saya memiliki sepasang kunci Publik dan Pribadi dan sertifikat saya. Di mana dibuat di OpenSSL (mengapa? Karena saya diminta untuk melakukannya di OpenSSL). Sekarang saya ingin menggunakan hal-hal itu untuk membuat aplikasi Java yang menggunakan tanda tangan digital. Bagaimana saya bisa menggunakan kunci pribadi dan publik saya untuk mengenkripsi/mendekripsi info (dan menggunakan sertifikat untuk melihat apakah data valid? Apa kelas-kelas di Java yang memungkinkan saya melakukan itu?

Kunci saya dalam teks biasa, kira-kira seperti ini:

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

PEMBARUAN

Saya membuat kode ini tetapi masih tidak dapat menggunakan kunci pribadi untuk menandatangani string.

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

pengecualian yang saya dapatkan adalah

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

Jika Anda memiliki kunci publik dalam formulir ini (dan tidak dalam sertifikat), saya sarankan menggunakan BouncyCastle '_ PEMReader. Metode readObject() dapat banyak membaca untuk format: kunci publik, sertifikat, kunci pribadi (walaupun Anda mungkin perlu menggunakan metode ini dengan kata sandi) ...

Jika Anda tidak ingin menggunakan BouncyCastle, Anda dapat membaca sertifikat menggunakan CertificateFactory (lihat contoh). Dengan sertifikat dalam format PEM dalam InputStream:

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

Untuk kunci pribadi, jika kunci pribadi Anda adalah struktur PKCS # 8 dalam format DER, Anda dapat membacanya secara langsung menggunakan PKCS8EncodedKeySpec . Sebagai contoh:

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

Anda dapat mengonversi kunci pribadi Anda menjadi PKCS # 8 menggunakan openssl pkcs8 -topk8 (Ingat -outform DER, Anda mungkin juga ingin memeriksa suite cipher karena tidak semua mungkin didukung oleh keduanya Java dan OpenSSL).

  • Dari sudut pandang penggunaan keystore:

Jika Anda tidak ingin melakukan banyak pemrograman untuk menangani kunci, untuk pergi antara Java dan OpenSSL, akan lebih mudah untuk menggunakan format PKCS # 12.

Jika kunci dan sertifikat yang Anda buat dengan OpenSSL belum ada dalam wadah p12:

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

Secara umum, Anda dapat menggunakan secara langsung, menggunakan tipe keystore Java "PKCS12" (Bukan "JKS" secara default).

Jika perlu, Anda dapat mengubah keystore PKCS12 ini menjadi format lain (mis. JKS) menggunakan keytool (Java 6+):

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

(Pada dasarnya, operasi yang berlawanan seperti yang dijelaskan dalam pertanyaan ini .)

Apa pun itu, apakah dari menggunakan PEMReader atau dengan memuat kunci/cert Anda dari KeyStore, Anda harus bisa mendapatkan instance PrivateKey dan Certificate (atau PublicKey secara langsung).

Anda dapat memverifikasi tanda tangan dari Certificate telah dilakukan dengan menggunakan kunci pribadi yang cocok dengan kunci publik yang diberikan menggunakan metode verify(PublicKey).

Dengan mereka, Anda juga dapat menggunakan tanda tangan digital API . Ini adalah API yang lebih umum untuk tanda tangan dokumen apa pun, dan saya tidak perlu memverifikasi tanda tangan sertifikat dengannya (Saya lebih suka menggunakan API jalur sertifikasi untuk ini, karena juga akan membangun rantai).

10
Bruno