繁体   English   中英

Java 中的 RSA 加密:IllegalBlockSizeException

[英]RSA Encryption in Java: IllegalBlockSizeException

我正在尝试在我的 Java 项目中设置 RSA 加密。 我在终端中使用以下命令生成了一个非对称密钥:

keytool -genkey -keyalg RSA -alias mykey -keystore mykey.jks -storepass mykeypass -keypass mykeypass

现在我使用以下方法加载密钥库:

public void loadKeyStore() throws KeyStoreException, CertificateException, IOException, 
NoSuchAlgorithmException {
    keyStore = KeyStore.getInstance(KEY_TYPE);
    char[] storePwdArray = STORE_PASS.toCharArray();
    FileInputStream fis = new FileInputStream(KEY_STORE_PATH);
    keyStore.load(fis, storePwdArray);
}

现在,我有两种方法,一种用于加密,一种用于解密:

public String encrypt(String data) throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
    if (keyStore == null) {
        loadKeyStore();
    }
    Certificate cert = keyStore.getCertificate(ALIAS);
    Cipher rsa = Cipher.getInstance("RSA/ECB/PKCS1Padding");
    rsa.init(Cipher.ENCRYPT_MODE, cert.getPublicKey());
    byte[] encryptedBytes = rsa.doFinal(data.getBytes(StandardCharsets.UTF_8));
    return Base64.getEncoder().encodeToString(encryptedBytes);
}

public String decrypt(String encryptedData) throws UnrecoverableKeyException, CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, NoSuchPaddingException {
    if (keyStore == null) {
        loadKeyStore();
    }
    Cipher rsa = Cipher.getInstance("RSA/ECB/PKCS1Padding");
    char[] keyPwdArray = KEY_PASS.toCharArray();
    Key key = keyStore.getKey(ALIAS, keyPwdArray);
    rsa.init(Cipher.DECRYPT_MODE, key);
    byte[] decryptedBytes = rsa.doFinal(encryptedData.getBytes());
    return new String(decryptedBytes, StandardCharsets.UTF_8);
}

在主要方法中,我尝试加密和解密字符串并打印它,如下所示:

public static void main(String[] args) throws UnrecoverableKeyException, NoSuchPaddingException, IllegalBlockSizeException, CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
    RSAEncryptionService encryptionService = new RSAEncryptionService();
    String secretMessage = "Hello World!";
    String encryptedMessage = encryptionService.encrypt(secretMessage);
    System.out.println(encryptedMessage);
    String decryptedMessage = encryptionService.decrypt(encryptedMessage);
    System.out.println(decryptedMessage);
}

The encryption works fine and returns something like that: B61g7zzXDNW9AO/Idc/OBZOCDOJpQTwgchD9uJisEBgxy8HV1XPYZZaLEnxkJHed2sBAQXEIyCDcIAHWk5rxn40tVd4NwlIUya1rB6WNvRFLrrN30G7VjMU6NNUdwJ55n7is2Ylfu0SkwNpy/o4e9LaZyzCyr4lJsTbFEXJQJKqLsOC+ysHYdhzx61Y8UJw6mUhleju7h11OcdDBdGEtAtBcKx9WDt2cgHrdtYUgUkwmEy3vTuuyUwVVpjA4QwUsjXnN+i19FQBZt67sMYIpUT4x4yJ8egqN4mJ2N8aNLwF7m/FS7EZphXdna4KN0srKBbPquB1ER5be6RnoyMFDsg==

但是当涉及到解密时,我得到以下异常:

Exception in thread "main" javax.crypto.IllegalBlockSizeException: Data must not be longer than 256 bytes
    at java.base/com.sun.crypto.provider.RSACipher.doFinal(RSACipher.java:349)
    at java.base/com.sun.crypto.provider.RSACipher.engineDoFinal(RSACipher.java:406)
    at java.base/javax.crypto.Cipher.doFinal(Cipher.java:2205)

我尝试了什么:

我在 StackOverflow 上的某个地方读到我需要增加密钥的大小。 但是,这也会产生更长的加密字符串,然后异常只是指出“数据不得长于 512/1024/... 字节”。

我尝试使用代码中生成的密钥对,如下所示。 那行得通,但我不知道如何将该 KeyPair 放入我的密钥库。

public void initKeyStore() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, KeyStoreException, IOException, CertificateException {
    KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
    generator.initialize(2048);
    KeyPair pair = generator.generateKeyPair();
    Cipher encryptCipher = Cipher.getInstance("RSA");
    encryptCipher.init(Cipher.ENCRYPT_MODE, pair.getPublic());
    byte[] secretMessageBytes = "secretMessage".getBytes(StandardCharsets.UTF_8);
    byte[] encryptedMessageBytes = encryptCipher.doFinal(secretMessageBytes);
    String encodedMessage = Base64.getEncoder().encodeToString(encryptedMessageBytes);
    System.out.println(encodedMessage);

    Cipher decryptCipher = Cipher.getInstance("RSA");
    decryptCipher.init(Cipher.DECRYPT_MODE, pair.getPrivate());
    byte[] decryptedMessageBytes = decryptCipher.doFinal(encryptedMessageBytes);
    String decryptedMessage = new String(decryptedMessageBytes, StandardCharsets.UTF_8);
    System.out.println(decryptedMessage);
}

原因很简单。 您正在使用 2048 位证书。 它不能加密任何大于 256 字节的数据,因为它需要小于 RSA 模数。

在 RSA 加密中,您通常需要使用信封来支持任意数据大小的加密。 简而言之,这意味着您需要使用随机对称密钥和对称算法(如 AES)加密数据,然后使用 RSA 加密其密钥并将两者发送到另一端。 对方先解密对称密钥,然后用它解密原始数据。 所以它会是这样的:

Encryption side
-----------------
1- Generate random AES key
2- Encrypt data with AES and generated key
3- Encrypt Key with RSA public key
4- Send 2 encrypted data to the other side

Decryption side
-----------------
1- Split received data to encrypted key and encrypted data
1- Decrypt AES Key with RSA private key
2- Decrypt data with AES and decrypted AES key

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM