Зашифрованный ключ AES слишком велик для расшифровки с помощью RSA (Java)

Я пытаюсь создать программу, которая шифрует данные с помощью AES, затем шифрует ключ AES с помощью RSA, а затем дешифрует. Однако после шифрования ключа 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);

Есть идеи, как это обойти?


person Petey B    schedule 03.05.2010    source источник
comment
Ваше описание ошибки не имеет смысла. Вы должны опубликовать полную трассировку стека. В его нынешнем виде часть кода RSA должна работать правильно. Я протестировал его, и он у меня отлично работает.   -  person President James K. Polk    schedule 04.05.2010
comment
А теперь я понимаю, ты ленивый ублюдок. Я вижу, вы разместили тот же код месяц назад на форумах sun и вам сказали, в чем была ваша ошибка. Затем вы просто репостили тот же код, чтобы зря тратить время. Если бы я запустил этот сайт, я бы удалил вашу учетную запись.   -  person President James K. Polk    schedule 04.05.2010


Ответы (3)


Изменить: я неправильно понял проблему. Вам следует использовать более крупный ключ RSA, например RSA 4096 позволяет зашифровать 501 байт.

Вы можете попробовать использовать AES в режиме OFB, который позволит вам зашифровать сообщение произвольного размера. В качестве альтернативы вы можете использовать потоковый шифр, например RC4, который также позволит вам зашифровать сообщение произвольного размера. Если вы используете RC4, убедитесь, что вы используете RC4-drop1024, что означает, что вы отбрасываете первые 1024 байта зашифрованного текста. Первые 1024 бита rc4 предсказуемы, и это, а также многие другие проблемы привели к краху WEP, используемого для защиты WIFI. Другая проблема с RC4 заключается в том, что вы не можете повторно использовать поток PRNG. В основном вы должны использовать разные ключи для каждого сообщения, иначе злоумышленник может довольно легко взломать систему, используя только XOR. Я бы выбрал AES в режиме OFB, но RC4 можно использовать безопасно.

Все остальные режимы блочного шифрования всегда создают сообщение, кратное их размеру блока. Например, AES 128 в режиме CBC всегда будет выдавать сообщение, кратное 128 битам. Если сообщение меньше 128 бит, оно часто дополняется нулями. Если это строка, то она должна оканчиваться нулем, и вам не о чем беспокоиться.

На стороне не убедитесь, что вы не используете режим ECB. Другая проблема заключается в том, что я не вижу, чтобы вы использовали вращающийся или рандомизированный вектор инициализации (IV), который значительно ослабляет любой блочный шифр. Неспособность правильно реализовать IV является уязвимостью, признанной CWE-329.

person rook    schedule 03.05.2010
comment
Спасибо за предложения, особенно по IV, однако проблема не в реализации AES, а скорее в RSA. Всякий раз, когда я шифрую 16-байтовый ключ AES (с помощью RSA), результат получается 128 байтов, что больше, чем 117-байтовый предел RSA, поэтому я не могу его расшифровать. - person Petey B; 03.05.2010
comment
@Petey B Ой, извините, я неправильно понял, эту проблему еще проще решить, просто используйте ключ RSA большего размера. Например, RSA 4096 позволяет зашифровать 501 байт. - person rook; 03.05.2010
comment
Это так сбивает с толку. Размер исходного ключа RSA должен был быть более чем достаточным. И сообщенная ошибка не возникает для опубликованного кода. - person President James K. Polk; 04.05.2010

Когда вы используете шифрование, всегда указывайте заполнение. В противном случае ваш открытый текст будет дополнен до размера блока. Например,

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

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

Ключ AES составляет всего 16 байт для 128-битного. Так что он должен хорошо вписаться в любой блок RSA.

person ZZ Coder    schedule 03.05.2010
comment
Спасибо, у вас есть дополнительная информация о том, какие схемы заполнения для каких алгоритмов возможны? - person Petey B; 03.05.2010
comment
Заполнение, поддерживаемое каждым алгоритмом, зависит от реализации JCE. Значения в моем примере - рекомендуемые настройки для AES и RSA. - person ZZ Coder; 03.05.2010
comment
-1 Его проблема не имеет абсолютно никакого отношения к используемому типу заполнения. Блочный шифр всегда будет создавать блоки одинакового размера, и заполнение является обязательным. Например, AES 128 всегда будет выдавать зашифрованный текст, кратный 128 битам. Если, конечно, вы не используете режим OFB. - person rook; 03.05.2010
comment
Кажется, что независимо от того, какое заполнение я указываю (даже NOPADDING), зашифрованный ключ AES всегда выходит на 128 байтов - person Petey B; 03.05.2010

Вы можете решить проблему сложности, просто используя режим / функцию переноса класса Cipher. Вы можете увидеть мой исходный код для примера того, как это сделать.

person Vincent Cantin    schedule 01.04.2012