我使用rsa密钥加密一个长字符串,我将发送到我的服务器(将使用服务器的公钥和我的私钥对其进行加密)但它会引发像javax.crypto.IllegalBlockSizeException: Data must not be longer than 256 bytes
这样的异常
我觉得到目前为止我还没有正确理解rsa的工作(使用内置库是导致这种情况的原因。)有人可以解释为什么抛出这个异常。是不是可以发送长字符串加密?
答案 0 :(得分:64)
RSA算法只能加密具有最大字节长度的数据 RSA密钥长度的比特除以8减去11个填充 字节数,即最大字节数=密钥长度(位/ 8 - 11)。
所以基本上你将密钥长度除以8 -11(如果你有填充)。例如,如果你有一个2048位密钥,你可以加密2048/8 = 256字节(如果你有填充,则为11字节)。因此,要么使用更大的密钥,要么使用对称密钥加密数据,并使用rsa加密该密钥(这是推荐的方法)。
这将要求你:
答案 1 :(得分:26)
基于@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);`
答案 2 :(得分:11)
您不应直接在您的秘密数据上使用RSA。您应该只在伪随机或完全随机数据上使用RSA,例如会话密钥或消息验证代码。
你得到了256字节的问题 - 这是因为你可能正在使用2048位密钥。密钥能够将0
到2^2048 - 1
范围内的任何整数加密到相同的范围,这意味着您的数据必须是256字节或更小。
如果您打算加密更多,请使用一个RSA加密来加密对称算法的会话密钥,并使用 加密您的数据。
答案 3 :(得分:3)
为了继续上面的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);
答案 4 :(得分:-4)
您需要通过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);
}