Рекурсивное шифрование с CipherOutputStream дает пустой байт [] - PullRequest
2 голосов
/ 21 сентября 2019

Я хотел бы зашифровать строку несколько раз.Но я не знаю, почему я заканчиваю с пустым байтовым массивом.Один открытый ключ в порядке, но добавление другого возвращает пустой результат. Кто-нибудь знает почему?

private static byte[] encrypt(LinkedList<PublicKey> keys, byte[] input) throws Exception {
    System.out.println("Input length : " + input.length);
    if (keys.isEmpty()) {
        return input;
    }
    PublicKey publicKey = keys.poll();
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    Cipher cipher = Cipher.getInstance("RSA");
    cipher.init(Cipher.ENCRYPT_MODE, publicKey);
    try (CipherOutputStream cipherOutputStream = new CipherOutputStream(byteArrayOutputStream, cipher)) {
        cipherOutputStream.write(input);
    }
    byteArrayOutputStream.flush();
    byteArrayOutputStream.close();
    return encrypt(keys, byteArrayOutputStream.toByteArray());
}

public static void main(String[] args) throws Exception {
    KeyPair pair1 = createPair();
    KeyPair pair2 = createPair();
    LinkedList<PublicKey> keys = new LinkedList<>();
    keys.add(pair1.getPublic());
    keys.add(pair2.getPublic());
    byte[] result = encrypt(keys, "Just testing".getBytes(Charset.forName("UTF-8")));
    System.out.println(new String(result, Charset.forName("UTF-8")));
}

public static KeyPair createPair() throws NoSuchAlgorithmException {
    KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
    keyPairGen.initialize(2048);
    return keyPairGen.generateKeyPair();

}

Вывод:

Input length : 12
Input length : 256
Input length : 0

После ответа Topaco '..рабочая версия:

private static BufferedInputStream encryptS(LinkedList<PublicKey> keys, BufferedInputStream inputStream) throws Exception {
    if (keys.isEmpty()) {
        return inputStream;
    }
    PublicKey publicKey = keys.poll();
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
    cipher.init(Cipher.ENCRYPT_MODE, publicKey);
    int currentPos = 0;
    while (inputStream.available() > 0) {
        int sizeToRead = Math.min(inputStream.available(), 245);
        try (CipherOutputStream cipherOutputStream = new CipherOutputStream(byteArrayOutputStream, cipher)) {
            byte[] array = new byte[sizeToRead];
            inputStream.read(array, 0, sizeToRead);
            cipherOutputStream.write(array);
            currentPos += sizeToRead;
        }
    }
    byteArrayOutputStream.close();
    return encryptS(keys, new BufferedInputStream(new ByteArrayInputStream(byteArrayOutputStream.toByteArray())));
}

1 Ответ

5 голосов
/ 21 сентября 2019

Для RSA необходимо учитывать следующее:

  • Длина сообщения плюс заполнение не должны превышать длину ключа (= размер модуля) [0] , [1] , [2] , [3] .Заполнение означает, что дополнительные байты добавляются к сообщению по определенной схеме [4] .
  • Длина зашифрованного текста соответствует длине ключа (= размер модуля), [5] .

Это означает, что уже после первого шифрования достигнута максимально допустимая длина.Таким образом, без заполнения максимальная длина не будет превышена, с заполнением она будет превышена.

Создание экземпляра шифра с

Cipher.getInstance("RSA") 

соответствует

Cipher.getInstance("RSA/ECB/PKCS1Padding") 

дляПоставщик SunJCE ( [6] , [7] ), т. Е. Заполнение PKCS1 v1.5 используется с заполнением не менее 11 символов, так что сразмер ключа 256 байт, максимальный размер сообщения не должен превышать 245 байт.

По этой причине рекурсивное шифрование в текущем коде не работает.Если экземпляр шифра создается с

Cipher.getInstance("RSA/ECB/NoPadding") 

(заполнение не используется), текущий код работает.

Однако по соображениям безопасности на практике всегда следует использовать !

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...