用RSA解密时,AES加密的密钥太大了。

3
我正在尝试编写一个程序,使用AES加密数据,然后使用RSA加密AES密钥,最后再进行解密。但是,一旦我加密了AES密钥,它就变成了128个字节。RSA只允许我解密117个字节或更少,所以当我尝试解密AES密钥时,会出现错误。
相关代码:
    KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
    kpg.initialize(1024);
    KeyPair kpa = kpg.genKeyPair();
    pubKey = kpa.getPublic();
    privKey = kpa.getPrivate();

    updateText("Private Key: " +privKey +"\n\nPublic Key: " +pubKey);

    updateText("Encrypting " +infile);
    //Genereate aes key
    KeyGenerator kgen = KeyGenerator.getInstance("AES");
    kgen.init(128); // 192/256
    SecretKey aeskey = kgen.generateKey();
    byte[] raw = aeskey.getEncoded();

    SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");

    updateText("Encrypting data with AES");
    //encrypt data with AES key
    Cipher aesCipher = Cipher.getInstance("AES");
    aesCipher.init(Cipher.ENCRYPT_MODE, skeySpec);
    SealedObject aesEncryptedData = new SealedObject(infile, aesCipher);

    updateText("Encrypting AES key with RSA");
    //encrypt AES key with RSA
    Cipher cipher = Cipher.getInstance("RSA");
    cipher.init(Cipher.ENCRYPT_MODE, pubKey);
    byte[] encryptedAesKey = cipher.doFinal(raw);

    updateText("Decrypting AES key with RSA. Encrypted AES key length: " +encryptedAesKey.length);
    //decrypt AES key with RSA       
    Cipher decipher = Cipher.getInstance("RSA");
    decipher.init(Cipher.DECRYPT_MODE, privKey);
    byte[] decryptedRaw = decipher.doFinal(encryptedAesKey); //error thrown here because encryptedAesKey is 128 bytes
    SecretKeySpec decryptedSecKey = new SecretKeySpec(decryptedRaw, "AES");

    updateText("Decrypting data with AES");
    //decrypt data with AES key
    Cipher decipherAES = Cipher.getInstance("AES");
    decipherAES.init(Cipher.DECRYPT_MODE, decryptedSecKey);
    String decryptedText = (String) aesEncryptedData.getObject(decipherAES);

    updateText("Decrypted Text: " +decryptedText);

有什么办法可以解决这个问题吗?

你对错误的描述不太清晰。你应该发布完整的堆栈跟踪信息。就目前而言,你的代码中 RSA 部分应该是可以正常工作的。我已经进行了测试,并且它在我的机器上运行得很好。 - President James K. Polk
3个回答

2

当您使用加密时,请始终指定填充。否则,您的明文将被填充到块大小。例如,

Cipher aes = Cipher.getInstance("AES/CBC/PKCS5Padding");

Cipher rsa = Cipher.getInstance("RSA/None/PKCS1Padding");

AES密钥仅为128位,只有16个字节。因此,它应该可以很好地适配于任何RSA块中。


谢谢,你有关于哪些填充方案适用于哪些算法的更多信息吗? - Petey B
每个算法支持的填充方式取决于JCE实现。我示例中的值是AES和RSA的推荐设置。 - ZZ Coder
2
-1 他的问题与所使用的填充类型完全无关。块密码始终会产生相同大小的数据块,并且填充是必需的。例如,AES 128始终会产生128位可被整除的密文。当然,除非您使用OFB模式。 - rook
无论我选择哪种填充方式(即使是NOPADDING),加密后的AES密钥似乎总是128字节。 - Petey B

1

编辑:我误解了问题。您应该使用更大的RSA密钥,例如RSA 4096允许您加密501个字节。

您可以尝试在OFB模式下使用AES,这将允许您加密任意大小的消息。或者,您可以使用像RC4这样的流密码,它也可以让您加密任意大小的消息。如果您选择RC4,请确保使用RC4-drop1024,这意味着您要丢弃密码文本的前1024个字节。RC4的前1024位是可预测的,这以及许多其他问题导致了用于保护WIFI的WEP的崩溃。RC4的另一个问题是您不能重复使用PRNG流,基本上您必须为每个消息使用不同的密钥,否则攻击者可以轻松地使用XOR破解系统。我会选择在OFB模式下使用AES,但RC4也可以安全使用。

所有其他的分组密码模式都会产生一个可以被它们的块大小整除的消息。例如,CBC模式下的AES 128总是会产生一个可以被128位整除的消息。如果消息小于128位,则通常用空值填充。如果这是一个字符串,则应该以空值结尾,您不必担心。

另外,请确保不要使用ECB模式。另一个问题是我没有看到您使用旋转或随机初始化向量(IV),这会显著削弱任何分组密码的安全性。未能正确实现IV是CWE-329所认可的一种漏洞。


感谢您的建议,特别是关于IV的建议。然而问题不在AES的实现上,而是RSA。每当我使用RSA加密16字节的AES密钥时,结果会变成128字节,这比RSA的117字节限制要大,因此我无法解密它。 - Petey B
@Petey B 噢,抱歉我误解了,这是一个更容易解决的问题,只需使用更大的RSA密钥即可。例如,RSA 4096允许您加密501个字节。 - rook
这太令人困惑了。原始RSA密钥的大小应该已经足够了。并且所报告的错误在发布的代码中并没有发生。 - President James K. Polk

1

您可以通过使用Cipher类的包装模式/函数来摆脱复杂性问题。您可以查看我的源代码,以了解如何实现。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接