web-dev-qa-db-ja.com

OpenSSLで生成されたキーをJavaで使用する方法

公開鍵と秘密鍵のペアと証明書を持っています。 OpenSSLで作成されたもの(なぜですか?OpenSSLで作成するように求められたため)。次に、これらを使用して、デジタル署名を使用するJavaアプリを作成します。秘密鍵と公開鍵を使用して情報を暗号化/復号化する方法(および証明書を使用してデータが有効ですか?Javaのクラスで、これを行うことができますか?

私のキーは次のようなプレーンテキストです:

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

[〜#〜]更新[〜#〜]

このコードを作成しましたが、秘密キーを使用して文字列に署名することはできません。

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

私が得ている例外は

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

この形式の(証明書内ではない)公開キーがある場合は、 BouncyCastlePEMReaderを使用することをお勧めします。そのreadObject()メソッドは、フォーマット(公開鍵、証明書、秘密鍵)の多くを読み取ることができます(ただし、パスワードでメソッドを使用する必要がある場合があります)...

BouncyCastleを使用したくない場合は、 CertificateFactory を使用して証明書を読み取ることができます(例を参照)。 InputStreamにPEM形式の証明書がある場合:

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

秘密鍵の場合、秘密鍵がDER形式のPKCS#8構造の場合、 PKCS8EncodedKeySpec を使用して直接読み取ることができます。例えば:

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

openssl pkcs8 -topk8を使用して秘密鍵をPKCS#8に変換できます(-outform DERを覚えておいてください。すべてのJavaとOpenSSLでサポートされていない可能性があるため、暗号スイートを確認することもできます)。

  • キーストアの使用の観点から:

JavaとOpenSSLの間を行き来するために、キーを処理するためのプログラミングをあまりしたくない場合は、PKCS#12形式を使用すると便利です。

OpenSSLで作成したキーと証明書がまだp12コンテナーにない場合:

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

一般に、Javaの「PKCS12」キーストアタイプ(デフォルトでは「JKS」の代わり)を使用して、直接使用できます。

必要に応じて、keytool(Java 6+)を使用して、このPKCS12キーストアを別の形式(JKSなど)に変換できます。

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

(基本的に、 この質問 で説明されている操作とは逆の操作です。)

どちらの方法でも、PEMReaderを使用する場合でも、KeyStoreからキー/証明書をロードする場合でも、 PrivateKey のインスタンスを取得できるはずです。 Certificate (または PublicKey 直接)。

verify(PublicKey)メソッドを使用して、特定の公開鍵と一致する秘密鍵によってCertificateの署名が行われたことを確認できます。

それらを使用すると、 デジタル署名API も使用できます。これはあらゆるドキュメント署名のより一般的なAPIであり、証明書の署名を必ずしも検証する必要はありません(チェーンも構築するため、これには証明書パスAPIを使用します)。

10
Bruno