公開鍵と秘密鍵のペアと証明書を持っています。 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
この形式の(証明書内ではない)公開キーがある場合は、 BouncyCastle のPEMReader
を使用することをお勧めします。その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を使用します)。