web-dev-qa-db-ja.com

指定された公開鍵を使用したRSA暗号化(Java)

私はJavaサンプルの与えられた公開鍵でRSA暗号化を行う方法のサンプルを探していますbase64形式、1024ビット長のようです)。

以下は私のコードですが、InvalidKeySpec例外があります。

String publicKey = "AJOnAeTfeU4K+do5QdBM2BQUhfrRI2rYf/Gk4a3jZJB2ewekgq2VgLNislBdql/glA39w0NjXZyTg0mW917JdUlHqKoQ9765pJc4aTjvX+3IxdFhteyO2jE3vKX1GgA3i3n6+sMBAJiT3ax57i68mbT+KAeP1AX9199aj2W4JZeP";
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] res = new Base64Encoder().decode(publicKey.getBytes());
X509EncodedKeySpec KeySpec = new X509EncodedKeySpec(res);
RSAPublicKey pubKey = (RSAPublicKey)keyFactory.generatePublic(KeySpec);

// here the exception occurs..

Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] cipherData = cipher.doFinal(input.getBytes());
return cipherData;

サンプルをください

30
david.papirov

RSA公開キーのみで文字列を暗号化する方法は次のとおりです。

最初に、公開鍵をPEM形式でファイル名pubkey.pemに保存します

-----BEGIN PUBLIC KEY-----
AJOnAeTfeU4K+do5QdBM2BQUhfrRI2rYf/Gk4...
-----END PUBLIC KEY-----

RSA公開鍵モジュラスを見つける

$ openssl rsa -pubin -in pubkey.pem -modulus -noout
Modulus=F56D...

RSA公開鍵指数を見つける

$ openssl rsa -pubin -in pubkey.pem -text -noout
...
Exponent: 65537 (0x10001)

次に、それらを次のコードに挿入します。

BigInteger modulus = new BigInteger("F56D...", 16);
BigInteger pubExp = new BigInteger("010001", 16);

KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(modulus, pubExp);
RSAPublicKey key = (RSAPublicKey) keyFactory.generatePublic(pubKeySpec);

Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key);

byte[] cipherData = cipher.doFinal(text.getBytes());
42
nevcx

「キー」は有効な公開キーではありません。これはBase64文字列であり、デコードされると129バイトのシーケンスを生成します。最初は0x00で、その後に0x93が続きます。これはRSA公開鍵の有効な形式ではありませんが、疑わしいことに1024ビット整数のビッグエンディアン符号化エンコード(つまり、BigInteger.toByteArray()によって返され、ASN.1で使用されるエンコードの種類)のように見えます「INTEGER」値)。 RSA公開鍵は、名目上は2つの整数で構成されます。1つはモジュラスで、もう1つは公開指数です。典型的なRSAモジュラスの長さは1024ビットなので、ここにモジュラスがある可能性があります。キーを完成させるためには、まだ公開指数が必要です。

_X509EncodedKeySpec_は、アルゴリズムがRSAであると識別するASN.1構造のDERエンコードを期待し、RSA公開キーの2つの整数を含むネストされたエンコードされた構造を含みます。このような構造を手作業で組み立てることは困難な場合があります(それは実行可能ですが、ASN.1のある程度の深い理解が必要です)。より簡単な方法は、RSAPublicKeySpecを使用することです。

_String modulusBase64 = "..."; // your Base64 string here
BigInteger modulus = new BigInteger(1,
        new Base64Encoder.decode(modulusBase64.getBytes("UTF-8")));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPublicKeySpec ks = new RSAPublicKeySpec(modulus, pubExp);
RSAPublicKey pubKey = (RSAPublicKey)keyFactory.generatePublic(KeySpec);
_

上記の「pubExp」は、公開指数を含むBigIntegerである必要がありますが、これは指定しません。 3と65537は公開指数の従来の値ですが、他の値も可能です。また、公開指数を区別するのに十分な情報を提供しません(つまり、正しい指数を使用しなくてもコードは機能しているように見えます)。基本的に、公開鍵の半分しかありません。その半分を与えた人に、他の半分も送るように頼む必要があります。

注:String.getBytes()はプラットフォームのデフォルトエンコーディングを使用しますが、常に同じとは限りません。文字列をバイトシーケンスに変換する場合は、_"UTF-8"_などの明示的な文字セット名を使用する必要があります。そうしないと、たとえばロシアや中国のシステムでコードが実行されると問題が発生する可能性があります。また、_Base64Encoder_クラスがどこから来たのかわかりません(標準Java API)の一部ではありませんが、String、またはStringReaderは、変換ステップを不要にします。

14
Thomas Pornin

あなたの公開鍵は本当にX509でエンコードされていますか?そうでない場合は、エンコードされていないKeyspecが役立ちます。

0
dunni

公開鍵は、Base64でエンコードされた1024ビット値のようには見えません。 1024ビット値には172文字が必要です(最後の文字はフィラー=)ここには175文字があります。

テストの場合、文字列の最後の4文字a single=そして、これが例外を排除するかどうかをテストします。これは問題を解決しませんが、正しい方向を指す場合があります。

0
Andreas_D