私はサーバーに送信する長い文字列を暗号化するためにRSAキーを使用しています(サーバーの公開鍵と秘密鍵で暗号化します)が、javax.crypto.IllegalBlockSizeException: Data must not be longer than 256 bytes
のような例外をスローしますこれまでのrsaの適切な機能(組み込みライブラリを使用することが原因です)。
この例外がスローされる理由を説明してください。長い文字列を暗号化して送信することはまったく不可能ですか?
RSAアルゴリズムでは、ビット単位のRSAキー長の最大バイト長を8マイナス11パディングバイトで割ったデータのみを暗号化できます。つまり、最大バイト数=ビット単位のキー長/ 8-11です。
したがって、基本的に、キーの長さを8〜11で除算します(パディングがある場合)。たとえば、2048ビットキーがある場合は、2048/8 = 256バイト(パディングがある場合は11バイト)を暗号化できます。そのため、より大きなキーを使用するか、対称キーでデータを暗号化し、そのキーをrsaで暗号化します(推奨されるアプローチです)。
それには次のことが必要になります。
@John Snowの回答に基づいて、私は例を行いました
対称キーの生成(128ビットのAES)
KeyGenerator generator = KeyGenerator.getInstance("AES");
generator.init(128); // The AES key size in number of bits
SecretKey secKey = generator.generateKey();
AESを使用してプレーンテキストを暗号化する
String plainText = "Please encrypt me urgently..."
Cipher aesCipher = Cipher.getInstance("AES");
aesCipher.init(Cipher.ENCRYPT_MODE, secKey);
byte[] byteCipherText = aesCipher.doFinal(plainText.getBytes());
RSA公開キーを使用してキーを暗号化する
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
KeyPair keyPair = kpg.generateKeyPair();
PublicKey puKey = keyPair.getPublic();
PrivateKey prKey = keyPair.getPrivate();
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.PUBLIC_KEY, puKey);
byte[] encryptedKey = cipher.doFinal(secKey.getEncoded()/*Seceret Key From Step 1*/);
暗号化されたデータ(byteCipherText)+暗号化されたAESキー(encryptedKey)を送信します
クライアント側で、RSA秘密鍵を使用して対称鍵を復号化します
cipher.init(Cipher.PRIVATE_KEY, prKey);
byte[] decryptedKey = cipher.doFinal(encryptedKey);
復号化された対称キーを使用して暗号を復号化します
//Convert bytes to AES SecertKey
SecretKey originalKey = new SecretKeySpec(decryptedKey , 0, decryptedKey .length, "AES");
Cipher aesCipher = Cipher.getInstance("AES");
aesCipher.init(Cipher.DECRYPT_MODE, originalKey);
byte[] bytePlainText = aesCipher.doFinal(byteCipherText);
String plainText = new String(bytePlainText);`
秘密データにRSAを直接使用しないでください。セッションキーやメッセージ認証コードなどのpseudo-randomまたはcompletely randomデータでのみRSAを使用する必要があります。
256バイトで問題が発生したのは、おそらく2048ビットキーで作業しているためです。キーは、0
から2^2048 - 1
の範囲の整数を同じ範囲に暗号化できます。つまり、データは256バイト以下でなければなりません。
これ以上暗号化する場合は、1つのRSA暗号化を使用して対称アルゴリズムのセッションキーを暗号化し、thatを使用してデータを暗号化してください。
上記のJohn Snowの回答をフォローするために、秘密鍵を使用して任意の長さのデータを単純に暗号化するために使用できる単純なランダム対称暗号ライブラリを作成しました。
ライブラリは GitHub-random-symmetric-crypto にあります。
final RandomSymmetricCipher cipher = new RandomSymmetricCipher();
// Encrypt the data and the random symmetric key.
final CryptoPacket cryptoPacket = cipher.encrypt(inputData, PRIVATE_KEY_BASE64);
// Convert the CryptoPacket into a Base64 String that can be readily reconstituted at the other end.
final CryptoPacketConverter cryptoPacketConverter = new CryptoPacketConverter();
final String base64EncryptedData = cryptoPacketConverter.convert(cryptoPacket);
System.out.println("Base64EncryptedData=" + base64EncryptedData);
// Decrypt the Base64 encoded (and encrypted) String.
final byte[] outputData = cipher.decrypt(base64EncryptedData, PUBLIC_KEY_BASE64);