Я использую ключ rsa для шифрования длинной строки, которую я отправлю на свой сервер (зашифрую ее с помощью открытого ключа сервера и моего закрытого ключа), но он выдает исключение типа javax.crypto.IllegalBlockSizeException: Data must not be longer than 256 bytes
. Я чувствую, что не понял работу rsa должным образом до тех пор, пока сейчас (причиной этого является использование встроенных библиотек).
Кто-нибудь, пожалуйста, объясните, почему возникает это исключение. Разве невозможно отправить длинную строку в зашифрованном виде?
получение исключения IllegalBlockSizeException: данные не должны быть длиннее 256 байт при использовании rsa
Ответы (5)
Алгоритм RSA может шифровать только данные, которые имеют максимальную длину байта длины ключа RSA в битах, разделенных на восемь минус одиннадцать байтов заполнения, то есть количество максимальных байтов = длина ключа в битах / 8-11.
Итак, в основном вы делите длину ключа на 8-11 (если у вас есть отступы). Например, если у вас есть 2048-битный ключ, вы можете зашифровать 2048/8 = 256 байтов (- 11 байтов, если у вас есть заполнение). Итак, либо используйте больший ключ, либо вы зашифруете данные симметричным ключом и зашифруете этот ключ с помощью rsa (что является рекомендуемым подходом).
Это потребует от вас:
- сгенерировать симметричный ключ
- Зашифруйте данные симметричным ключом
- Зашифруйте симметричный ключ с помощью rsa
- отправить зашифрованный ключ и данные
- Расшифруйте зашифрованный симметричный ключ с помощью rsa
- расшифровать данные симметричным ключом
- сделано :)
key length in bits / 8 - 11
действует только при использовании PKCS1Padding
. Например, при NoPadding
ограничение будет key length in bits / 8
.
- person divanov; 19.11.2013
Основываясь на ответе @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(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 для своих секретных данных. Вы должны использовать RSA только для псевдослучайных или полностью случайных данных, таких как ключи сеанса или коды аутентификации сообщений.
У вас проблема с 256 байтами - это потому, что вы, вероятно, работаете с 2048-битными ключами. Ключи могут зашифровать любое целое число в диапазоне от 0
до 2^2048 - 1
в тот же диапазон, и это означает, что ваши данные должны быть 256 байтов или меньше.
Если вы намереваетесь зашифровать больше, используйте одно шифрование RSA, чтобы зашифровать сеансовый ключ для симметричного алгоритма, и используйте это для шифрования ваших данных.
[0, 2^2048-1]
включительно. Любое сообщение длиной более 2048 бит представляет собой число за пределами этого диапазона и должно быть закодировано либо двумя блоками, либо - если вы хотите безопасности - все сообщение должно быть зашифровано с помощью сеансового ключа. Реально развернутый RSA должен защищать от множественных атак и никогда не работать над необработанный открытый текст - одна из важных составляющих безопасного использования RSA.
- person sarnold; 09.04.2012
Следуя приведенному выше ответу Джона Сноу, я создал простую библиотеку случайных симметричных крипт, которую вы можете использовать для простого шифрования данных любой длины с помощью закрытого ключа.
Вы можете найти библиотеку на странице GitHub - random-symric-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);
вам нужно разделить свои данные по 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);
}
bcd2Str
действительно выполняет шестнадцатеричное кодирование [0-9A-Z]. 3. Возможно, нет необходимости кодировать двоичный вывод с помощью шифрования RSA, и если кодирование необходимо, в то время как шестнадцатеричный код в порядке, обычно используется кодирование Base64, оно более компактно.
- person zaph; 19.07.2016