В 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.