Шифрование в Java с использованием «AES / CFB / NoPadding» и дешифрование в Python с использованием AES.MODE_CFB дают разные результаты. - PullRequest
0 голосов
/ 19 июня 2020

В Java приведенный ниже код может шифровать строки любой длины и расшифровывать без каких-либо проблем.

Java код:

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class AesEncryption {
    public static void main(String[] args) throws NoSuchAlgorithmException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, InvalidAlgorithmParameterException, NoSuchPaddingException {
        AesEncryption ae = new AesEncryption();
        byte[] secret = ae.encrypt("Hello World!");
        for (byte b : secret)
            System.out.print(String.format("%d, ", b));
        System.out.print("\n");
        System.out.print(String.format("%s\n", ae.decrypt(secret)));
    }

    private final IvParameterSpec iv;
    private final SecretKeySpec keySpec;

    public AesEncryption() throws NoSuchAlgorithmException {
        byte[] key = "thisisasecretkey".getBytes(StandardCharsets.UTF_8);
        MessageDigest md = MessageDigest.getInstance("MD5");
        md.update(key);
        this.iv = new IvParameterSpec(md.digest());
        this.keySpec = new SecretKeySpec(key, "AES");
    }

    public byte[] encrypt(String content) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        Cipher cipher = Cipher.getInstance("AES/CFB/NoPadding");
        cipher.init(Cipher.ENCRYPT_MODE, this.keySpec, this.iv);
        return cipher.doFinal(content.getBytes());
    }

    public String decrypt(byte[] secret) throws InvalidAlgorithmParameterException, InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException, BadPaddingException, IllegalBlockSizeException {
        Cipher cipher = Cipher.getInstance("AES/CFB/NoPadding");
        cipher.init(Cipher.DECRYPT_MODE, this.keySpec, this.iv);
        return new String(cipher.doFinal(secret));
    }
}

Python код:

import array
import hashlib
from Crypto.Cipher import AES

class AesEncryption:
    def __init__(self):
        key = 'thisisasecretkey'.encode('UTF-8')
        md = hashlib.md5()
        md.update(key)
        iv = md.digest()
        self.__cryptor = AES.new(key, AES.MODE_CFB, iv, segment_size=128)
    
    def encrypt(self, content):
        return self.__cryptor.encrypt(AesEncryption.r_pad(content.encode('UTF-8')))[:len(content.encode('UTF-8'))]
    
    def decrypt(self, secret):
        return self.__cryptor.decrypt(secret)
    
    @staticmethod
    def r_pad(payload):
        length = 16 - (len(payload) % 16)
        return payload + (chr(length) * length).encode('UTF-8')


if __name__ == '__main__':
    secretstr = array.array('b', [-108, 20, -91, -103, 13, 59, 94, -51, 17, -104, -30, -83]).tostring()
    ae = AesEncryption()
    print(ae.decrypt(secretstr).decode('UTF-8'))

Однако, когда я передаю секретный массив байтов, созданный кодом Java, в PyCrypto, дешифрование не выполняется. В коде Python используются AES.MODE_CFB и segment_size = 128 для соответствия режиму AES в Java, но длина простого текста не будет соответствовать требованиям к 16-байтовому блоку. Изменение segment_size также никогда не даст такого же результата. Итак, я полагаю, что NoPadding может быть проблемой. Какой алгоритм используется режимом AES/CFB/NoPadding в Java? И чем он отличается от алгоритма, используемого в PyCrypto? Спасибо.

Изменить: Спасибо Topaco и Robert . В качестве потокового шифра режим CFB с segment_size=128 должен работать правильно. Проблема вызвана ошибкой в ​​устаревшей версии PyCrypto. Вместо этого используйте последнюю версию PyCryptodome.

...