获取非法块大小异常:使用 rsa 时,数据的长度不得超过 256 字节

2022-08-31 16:48:39

我正在使用rsa密钥来加密一个长字符串,我将发送到我的服务器(将使用服务器的公钥和我的私钥对其进行加密),但它会抛出一个异常,就像我觉得我直到现在还没有正确理解rsa的工作原理(使用内置库是导致这种情况的原因)。
有人可以解释为什么会引发此异常吗?难道根本不可能发送加密的长字符串吗?javax.crypto.IllegalBlockSizeException: Data must not be longer than 256 bytes


答案 1

RSA 算法只能加密具有 RSA 密钥长度的最大字节长度的数据,以位除以 8 减去 11 个填充字节,即最大字节数 = 密钥长度(以位 / 8 - 11 为单位)。

所以基本上你用8 -11(如果你有填充)来划分密钥长度。例如,如果您有一个 2048 位密钥,则可以加密 2048/8 = 256 字节(如果您有填充,则为 11 个字节)。因此,要么使用更大的密钥,要么使用对称密钥加密数据,并使用 rsa 加密该密钥(这是推荐的方法)。

这将要求您:

  1. 生成对称密钥
  2. 使用对称密钥加密数据
  3. 使用 rsa 加密对称密钥
  4. 发送加密密钥和数据
  5. 使用 rsa 解密加密的对称密钥
  6. 使用对称密钥解密数据
  7. 完成:)

答案 2

基于@John斯诺的回答,我做了一个例子

  1. 生成对称密钥(128 位的 AES)

    KeyGenerator generator = KeyGenerator.getInstance("AES");
    generator.init(128); // The AES key size in number of bits
    SecretKey secKey = generator.generateKey();
    
  2. 使用 AES 加密纯文本

    String plainText = "Please encrypt me urgently..."
    Cipher aesCipher = Cipher.getInstance("AES");
    aesCipher.init(Cipher.ENCRYPT_MODE, secKey);
    byte[] byteCipherText = aesCipher.doFinal(plainText.getBytes());
    
  3. 使用 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*/);
    
  4. 发送加密数据(字节密码文本)+ 加密的 AES 密钥(加密密钥)

  5. 在客户端,使用 RSA 私钥解密对称密钥

    cipher.init(Cipher.PRIVATE_KEY, prKey);
    byte[] decryptedKey = cipher.doFinal(encryptedKey);
    
  6. 使用解密的对称密钥解密密文

    //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);`
    

推荐