有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java使用RSA公钥加密AES密钥

我正在编写一个用于传输文件的小应用程序,或多或少是为了了解更多编程加密基础。其想法是生成一个RSA密钥对,交换公钥,并将AES iv和密钥发送给用户进行进一步解密。我想用RSA公钥加密AES密钥,如下所示:

// encode the SecretKeySpec
private byte[] EncryptSecretKey ()
{
    Cipher cipher = null;
    byte[] key = null;

    try
    {
        cipher = Cipher.getInstance("RSA/ECB/NOPADDING");
        // contact.getPublicKey returns a public key of type Key
        cipher.init(Cipher.ENCRYPT_MODE, contact.getPublicKey() );
        // skey is the SecretKey used to encrypt the AES data
        key = cipher.doFinal(skey.getEncoded());
    }
    catch(Exception e )
    {
        System.out.println ( "exception encoding key: " + e.getMessage() );
        e.printStackTrace();
    }
    return key;
}

然后我把密钥值写给接收者,然后像这样解密:

private SecretKey decryptAESKey(byte[] data )
{
    SecretKey key = null;
    PrivateKey privKey = null;
    Cipher cipher = null;

    System.out.println ( "Data as hex: " + utility.asHex(data) );
    System.out.println ( "data length: " + data.length );
    try
    {
        // assume this loads our private key
        privKey = (PrivateKey)utility.loadLocalKey("private.key", false);

        cipher = Cipher.getInstance("RSA/ECB/NOPADDING");
        cipher.init(Cipher.DECRYPT_MODE, privKey );
        key = new SecretKeySpec(cipher.doFinal(data), "AES");

        System.out.println ( "Key decrypted, length is " + key.getEncoded().length );
        System.out.println ( "data: " + utility.asHex(key.getEncoded()));
    }
    catch(Exception e)
    {
        System.out.println ( "exception decrypting the aes key: " + e.getMessage() );
        e.printStackTrace();
        return null;
    }

    return key;
}

在控制台的另一侧,我得到以下输出:

read_bytes for key: 16
data length: 16
Data as hex: <hex string>
Key decrypted, length is 256
java.security.InvalidKeyException: Invalid AES key length: 256 bytes

此外,如果我创建一个大小为16的字节数组,并放入密码。如果将最终(数据)输出到其中,数组的大小似乎调整为256字节(至少长度是这样)。为什么会这样,更进一步,我做错了什么

编辑
我解决了这个问题,我想我会发布这个问题,以防有人遇到这个问题。事实证明,问题在于RSA/ECB/NOP。出于某种奇怪的原因,当我把秘钥转交给客户时,它把我的秘钥制作搞砸了。这可能与我如何生成密钥对有关(我使用getInstance(“RSA”)来实现),但我不完全确定


共 (3) 个答案

  1. # 1 楼答案

    不能只使用“原始”RSA加密数据而不进行任何填充。你需要某种填充方案,哪怕只是出于安全考虑。通常使用“RSA/ECB/PKCS1添加”。这可以加密比密钥大小小11字节的数据。它确保数据符合模数,并添加至少8字节的随机数据,以确保两次加密(例如“是”一词)不会产生两个相同的密码文本。最后,它确保您可以找到加密数据的大小(以八位字节为单位),因此您可以简单地加密构成AES密钥的16、24或32字节

  2. # 2 楼答案

    One thing to remember is that with RSA and actually many other algorithms including AES usually, the "useful" data that you supply isn't literally the data that's encrypted. Usually, some extra data needs to be included, for example, indicating the actual length of the data in some way, data for any integrity checking... To the user, the number of input bytes doesn't necessarily equal the number of bytes following encryption.

    Comment Source

    要获得正确的密钥大小,可以对密钥(SHA)使用哈希算法,这将为您提供固定的输出大小。否则,您可以只使用前16个字节作为键,而忽略其余的?祝你好运

  3. # 3 楼答案

    正如owlstead提到的,您不能只使用“原始”RSA,而不使用填充进行加密/解密。一方面它非常不安全,另一方面,Java库甚至不支持它。下面是使用RSA密钥对加密/解密AES密钥的工作代码

    private byte[] EncryptSecretKey ()
    {
        Cipher cipher = null;
        byte[] key = null;
    
        try
        {
            // initialize the cipher with the user's public key
            cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(Cipher.ENCRYPT_MODE, contact.getPublicKey() );
            key = cipher.doFinal(skey.getEncoded());
        }
        catch(Exception e )
        {
            System.out.println ( "exception encoding key: " + e.getMessage() );
            e.printStackTrace();
        }
        return key;
    }
    

    AES密钥的解密如下所示:

    private SecretKey decryptAESKey(byte[] data )
    {
        SecretKey key = null;
        PrivateKey privKey = null;
        Cipher cipher = null;
    
        try
        {
            // this is OUR private key
            privKey = (PrivateKey)utility.loadLocalKey(
                                    ConfigFrame.privateKeyLocation, false);
    
            // initialize the cipher...
            cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(Cipher.DECRYPT_MODE, privKey );
    
            // generate the aes key!
            key = new SecretKeySpec ( cipher.doFinal(data), "AES" );
        }
        catch(Exception e)
        {
            System.out.println ( "exception decrypting the aes key: " 
                                                   + e.getMessage() );
            return null;
        }
    
        return key;
    }