【问题标题】:IllegalBlockSize Exception When Doing RSA on bytes of Strings对字符串字节执行 RSA 时出现 IllegalBlockSize 异常
【发布时间】:2015-10-06 16:27:01
【问题描述】:

我正在尝试在 Java 中为客户端将来回传递字符串的服务器编写 RSA 加密和解密类。我有以下类代码:

public class RSAEncryption {
public static final String KEYGENALGORITHM = "RSA";
public static final String ALGORITHM = "RSA/ECB/PKCS1Padding";

public static KeyPairContainer generateKey() {
      KeyPairGenerator keyGen;
      KeyPair key;
    try {
        keyGen = KeyPairGenerator.getInstance(KEYGENALGORITHM);
        keyGen.initialize(1024);
        key = keyGen.generateKeyPair();
        return new KeyPairContainer(key.getPublic(), key.getPrivate());
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
        System.out.println("Error: No such algorithm");
    }
    return null;
 }

public static String pubkeyToString(PublicKey key){
    byte[] array = key.getEncoded();
    BASE64Encoder encoder = new BASE64Encoder();
    String tempstring = encoder.encode(array);
    return tempstring;
}

public static PublicKey stringToPubKey(String string){
    BASE64Decoder decoder = new BASE64Decoder();
    try {
        byte[] array = decoder.decodeBuffer(string);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(array);
        KeyFactory keyFact = KeyFactory.getInstance(KEYGENALGORITHM);
        PublicKey pubKey = keyFact.generatePublic(x509KeySpec);
        return pubKey;
    } catch (IOException | NoSuchAlgorithmException | InvalidKeySpecException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } return null;
}

public static byte[] rSAencrypt(byte[] plaintext, String keystring) {
    Cipher cipher;
    try {
        PublicKey key = stringToPubKey(keystring);
        cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, key);
        byte[] cipherText = cipher.doFinal(plaintext);
        //String cipherText = new String(cipherTextbytes);
        return cipherText;
    } catch (NoSuchAlgorithmException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (NoSuchPaddingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IllegalBlockSizeException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (BadPaddingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return null;

}

public static byte[] rSAdecrypt(byte[] ciphertext, PrivateKey key){
    Cipher cipher;
    try {
        //byte[] ciphertext = ciphertextstring.getBytes();
        cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, key);
        byte[] decryptedText = cipher.doFinal(ciphertext);
        return decryptedText;
    } catch (NoSuchAlgorithmException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (NoSuchPaddingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IllegalBlockSizeException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (BadPaddingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return null;
}
}

我有以下代码用于测试类:

public class RSAEncryptionKeyDemo {
public static void main(String[] args){
    KeyPairContainer keyPair = RSAEncryption.generateKey();
    PublicKey pubKey = keyPair.getPublicKey();
    String pubKeytext = RSAEncryption.pubkeyToString(pubKey);
    System.out.println(pubKeytext);

    String plaintext = "Hello world!";
    byte[] ciphertext = RSAEncryption.rSAencrypt(plaintext.getBytes(), pubKeytext);
    String ciphertextString = new String(ciphertext);
    System.out.println(ciphertextString);

    PrivateKey privkey = keyPair.getPrivateKey();
    byte[] decryptedText = RSAEncryption.rSAdecrypt(ciphertextString.getBytes(), privkey);

    String decryptedTextstring = new String(decryptedText);

    System.out.println(decryptedTextstring);


}
}

但是,当我尝试运行测试类时,密钥生成和加密工作正常,但是当我尝试解密时出现错误。报错是javax.crypto.IllegalBlockSizeException: Data must not be long than 128 bytes,但是,我的数据肯定小于128 bytes。

我可以确认将公钥转换为字符串并返回相同的公钥。我也尝试过仅使用字节测试代码,这很好用。该错误显然是在尝试解密从字符串中获取的字节。

有什么方法可以解密从字符串中获取的字节而不引发此错误?提前感谢,非常感谢。

编辑:我想我可能已经隔离了这个问题。我正在尝试将加密的字节数组转换为字符串,然后从中提取字节,但是加密的字节数组无论如何都不能正确转换为字符串,所以当我得到字节时,它不会提取原始加密的字节数组是什么.是否正确,如果正确,如何将字节数组正确转换为字符串以便我们进行交换?

【问题讨论】:

  • 尝试设置为 NoPadding
  • 将其设置为 RSA/ECB/NoPadding 会引发同样的错误。
  • 检查this的答案。

标签: java encryption jce


【解决方案1】:

如果你这样做

byte[] ciphertext = RSAEncryption.rSAencrypt(plaintext.getBytes(), pubKeytext);
//String ciphertextString = new String(ciphertext);
//System.out.println(ciphertextString);

PrivateKey privkey = keyPair.getPrivateKey();
byte[] decryptedText = RSAEncryption.rSAdecrypt(ciphertext, privkey);

代码运行良好。您不能将字节数组转换为字符串,因为字节被转换为字符并返回字节(使用 getBytes()) - 取决于您的默认字符集。 new String(ciphertext) 去除无法打印的字符,这会改变密文,从而使明文无法恢复。 (感谢 Artjom B. 指出这一点。)

只需使用 Base64 或二进制来传输您的密文,例如:

byte[] ciphertext = RSAEncryption.rSAencrypt(plaintext.getBytes(), pubKeytext);
String ciphertextString = Base64.toBase64String(ciphertext);
System.out.println(ciphertextString);

PrivateKey privkey = keyPair.getPrivateKey();
byte[] decryptedText = RSAEncryption.rSAdecrypt(Base64.decode(ciphertextString), privkey);

(我这里使用的是 BouncyCastle Base64 编码器。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-08-11
    • 1970-01-01
    • 2010-10-01
    • 2019-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多