Я использую ключ rsa для шифрования длинной строки, которую я пошлю на свой сервер (зашифрует его с помощью открытого ключа сервера и моего закрытого ключа). Но он генерирует исключение, например javax.crypto.IllegalBlockSizeException: Data must not be longer than 256 bytes
Я чувствую, что до сих пор я не понимал работу rsa (использование встроенных библиотек является причиной этого). Может кто-нибудь объяснить, почему это исключение выбрасывается. Невозможно ли отправить длинную строку зашифрованной?
Получение исключения IllegalBlockSizeException: данные не должны превышать 256 байтов при использовании rsa
Ответ 1
Алгоритм RSA может только шифровать данные с максимальной длиной байта длины ключа RSA в битах, разделенных на восемь минус одиннадцать отступов байты, то есть количество максимальных байтов = длина ключа в битах /8-11.
Итак, вы разделите длину ключа на 8 -11 (если у вас есть отступы). Например, если у вас есть 2048-битный ключ, вы можете зашифровать 2048/8 = 256 байт (- 11 байтов, если у вас есть отступы). Таким образом, используйте либо более крупный ключ, либо шифруйте данные симметричным ключом, и зашифруйте этот ключ с помощью rsa (это рекомендуемый подход).
Это потребует от вас:
- создать симметричный ключ
- Шифровать данные с помощью симметричного ключа
- Зашифровать симметричный ключ с помощью rsa
- отправить зашифрованный ключ и данные
- Расшифровать зашифрованный симметричный ключ с помощью rsa
- расшифровать данные с помощью симметричного ключа
- done:)
Ответ 2
Вы не должны использовать RSA непосредственно в своих секретных данных. Вы должны использовать RSA только для псевдослучайных или полностью случайных данных, таких как ключи сеанса или коды аутентификации сообщений.
У вас проблема с 256 байтами - это потому, что вы, вероятно, работаете с 2048-битными ключами. Клавиши могут шифровать любое целое число в диапазоне от 0
до 2^2048 - 1
в том же диапазоне, а это значит, что ваши данные должны быть 256 байт или меньше.
Если вы намерены зашифровать больше, чем это, используйте один шифр RSA для шифрования ключа сеанса для симметричного алгоритма и используйте его для шифрования ваших данных.
Ответ 3
Чтобы следовать дальше от Джона Света, я создал простую библиотеку случайных симметричных крипов, которую вы можете использовать для простого шифрования любых данных длины с помощью закрытого ключа.
Вы можете найти библиотеку в GitHub - произвольно-симметричное криптование
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);
Ответ 4
Основываясь на ответе @John Snow, я сделал пример
-
Создать симметричный ключ (AES с 128 бит)
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(byteCipherText);
-
Отправить зашифрованные данные (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);`
Ответ 5
вам нужно разделить свои данные с помощью publicKey
int keyLength = publicKey.getModulus().bitLength() / 16;
String[] datas = splitString(data, keyLength - 11);
String mi = ""//the data after encrypted;
for (String s : datas) {
mi += bcd2Str(cipher.doFinal(s.getBytes()));
}
return mi;
public static String bcd2Str(byte[] bytes) {
char temp[] = new char[bytes.length * 2], val;
for (int i = 0; i < bytes.length; i++) {
val = (char) (((bytes[i] & 0xf0) >> 4) & 0x0f);
temp[i * 2] = (char) (val > 9 ? val + 'A' - 10 : val + '0');
val = (char) (bytes[i] & 0x0f);
temp[i * 2 + 1] = (char) (val > 9 ? val + 'A' - 10 : val + '0');
}
return new String(temp);
}