Python and java AES/ECB/PKCS5 encryption
Question:
JAVA VERSION:
public class EncryptUtil {
public static String AESEncode(String encodeRules, String content) {
try {
KeyGenerator keygen = KeyGenerator.getInstance("AES");
keygen.init(128, new SecureRandom(encodeRules.getBytes()));
SecretKey original_key = keygen.generateKey();
byte[] raw = original_key.getEncoded();
SecretKey key = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] byte_encode = content.getBytes("utf-8");
byte[] byte_AES = cipher.doFinal(byte_encode);
return new String(Base64.getEncoder().encode(byte_AES));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
}
When i run this code:
System.out.println(EncryptUtil.AESEncode("1234567812345678", python&java"));
I’ve got:
V5FFUgDi7VZaJ0qGzDISoA==
PYTHON VERSION:
import base64
from Crypto.Cipher import AES
BLOCK_SIZE = 16 # Bytes
pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) *
chr(BLOCK_SIZE - len(s) % BLOCK_SIZE)
unpad = lambda s: s[:-ord(s[len(s) - 1:])]
class AESUtil:
__BLOCK_SIZE_16 = BLOCK_SIZE_16 = AES.block_size
def __init__(self, key):
self.key = key
def encrypt(self, raw):
raw = pad(raw)
cipher = AES.new(self.key, AES.MODE_ECB)
return base64.b64encode(cipher.encrypt(raw))
def decrypt(self, enc):
enc = base64.b64decode(enc)
cipher = AES.new(self.key, AES.MODE_ECB)
return unpad(cipher.decrypt(enc))
I know java use AES/ECB/PKCS#5 by default, but when I run the encrypt
method :
cipher_text = AESUtil("1234567812345678").encryt('python&java')
got:b'3mjygpK1d7ThCRK98ssZhA=='
The pad and unpad i found them in Googles.
How do I edit my PYTHON code make the cipher_text equals JAVA encryption.
Can somebody know how to fix it?
Answers:
You use different encryption keys
In Java
System.out.println(EncryptUtil.AESEncode(“1234567812345678”, “python&java”));
See the code:
KeyGenerator keygen = KeyGenerator.getInstance("AES");
keygen.init(128, new SecureRandom(encodeRules.getBytes()));
SecretKey original_key = keygen.generateKey();
byte[] raw = original_key.getEncoded();
If you print the raw
key, you will get fd839759956ba4a47922e8ee7c902f52
(HEX encoded), that’s the encryption key
If you would like to use the provided key directy, you should use
byte[] raw = encodeRules.getBytes();
// (assuming encodeRules has 16 bytes)
How do I edit my PYTHON code make the cipher_text equals JAVA encryption
That’s tricky.. you may have a look how SecureRandom works, but IMHO it’s easier to fix the Java implementation to create a key you expect
Regardless that I’d consider the implementation not secure enough – using ECB and simple key.
Check this utility out– https://github.com/EverWinter23/aes-ecb-pkcs5.
It uses the python standard library for AES/ECB/PKCS5 cipher with variable size key– try with key_size=BLOCK_SIZE.
import hashlib
from base64 import b64decode as b64D
from base64 import b64encode as b64E
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import padding
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
UTF_8 = "utf-8"
def make_aes_ecb_cipher(secret: str, key_size: int = 16) ->
return Cipher(
algorithms.AES(make_key(secret, key_size)),
modes.ECB(),
backend=default_backend(),
)
def make_key(secret: str, key_size: int) -> str:
if key_size <= 0:
AssertionError("key_size cannot be <=0.")
return hashlib.sha256(secret.encode(UTF_8)).digest()[:key_size]
def encrypt_to_base64(plain_text: str, secret: str, key_size: int) -> str:
padder = padding.PKCS7(algorithms.AES.block_size).padder()
padded_bytes = padder.update(plain_text.encode(UTF_8)) + padder.finalize()
cipher = make_aes_ecb_cipher(secret, key_size)
encryptor = cipher.encryptor()
encrypted_bytes = encryptor.update(padded_bytes) + encryptor.finalize()
return b64E(encrypted_bytes).decode(UTF_8)
def decrypt_from_base64(encrypted_text: str, secret: str, key_size: int) -> str:
encrypted_bytes = b64D(encrypted_text)
cipher = make_aes_ecb_cipher(secret, key_size)
decryptor = cipher.decryptor()
padded_bytes = decryptor.update(encrypted_bytes) + decryptor.finalize()
unpadder = padding.PKCS7(algorithms.AES.block_size).unpadder()
unpadded_bytes = unpadder.update(padded_bytes) + unpadder.finalize()
return unpadded_bytes.decode(UTF_8)
JAVA VERSION:
public class EncryptUtil {
public static String AESEncode(String encodeRules, String content) {
try {
KeyGenerator keygen = KeyGenerator.getInstance("AES");
keygen.init(128, new SecureRandom(encodeRules.getBytes()));
SecretKey original_key = keygen.generateKey();
byte[] raw = original_key.getEncoded();
SecretKey key = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] byte_encode = content.getBytes("utf-8");
byte[] byte_AES = cipher.doFinal(byte_encode);
return new String(Base64.getEncoder().encode(byte_AES));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
}
When i run this code:
System.out.println(EncryptUtil.AESEncode("1234567812345678", python&java"));
I’ve got:
V5FFUgDi7VZaJ0qGzDISoA==
PYTHON VERSION:
import base64
from Crypto.Cipher import AES
BLOCK_SIZE = 16 # Bytes
pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) *
chr(BLOCK_SIZE - len(s) % BLOCK_SIZE)
unpad = lambda s: s[:-ord(s[len(s) - 1:])]
class AESUtil:
__BLOCK_SIZE_16 = BLOCK_SIZE_16 = AES.block_size
def __init__(self, key):
self.key = key
def encrypt(self, raw):
raw = pad(raw)
cipher = AES.new(self.key, AES.MODE_ECB)
return base64.b64encode(cipher.encrypt(raw))
def decrypt(self, enc):
enc = base64.b64decode(enc)
cipher = AES.new(self.key, AES.MODE_ECB)
return unpad(cipher.decrypt(enc))
I know java use AES/ECB/PKCS#5 by default, but when I run the encrypt
method :
cipher_text = AESUtil("1234567812345678").encryt('python&java')
got:b'3mjygpK1d7ThCRK98ssZhA=='
The pad and unpad i found them in Googles.
How do I edit my PYTHON code make the cipher_text equals JAVA encryption.
Can somebody know how to fix it?
You use different encryption keys
In Java
System.out.println(EncryptUtil.AESEncode(“1234567812345678”, “python&java”));
See the code:
KeyGenerator keygen = KeyGenerator.getInstance("AES");
keygen.init(128, new SecureRandom(encodeRules.getBytes()));
SecretKey original_key = keygen.generateKey();
byte[] raw = original_key.getEncoded();
If you print the raw
key, you will get fd839759956ba4a47922e8ee7c902f52
(HEX encoded), that’s the encryption key
If you would like to use the provided key directy, you should use
byte[] raw = encodeRules.getBytes();
// (assuming encodeRules has 16 bytes)
How do I edit my PYTHON code make the cipher_text equals JAVA encryption
That’s tricky.. you may have a look how SecureRandom works, but IMHO it’s easier to fix the Java implementation to create a key you expect
Regardless that I’d consider the implementation not secure enough – using ECB and simple key.
Check this utility out– https://github.com/EverWinter23/aes-ecb-pkcs5.
It uses the python standard library for AES/ECB/PKCS5 cipher with variable size key– try with key_size=BLOCK_SIZE.
import hashlib
from base64 import b64decode as b64D
from base64 import b64encode as b64E
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import padding
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
UTF_8 = "utf-8"
def make_aes_ecb_cipher(secret: str, key_size: int = 16) ->
return Cipher(
algorithms.AES(make_key(secret, key_size)),
modes.ECB(),
backend=default_backend(),
)
def make_key(secret: str, key_size: int) -> str:
if key_size <= 0:
AssertionError("key_size cannot be <=0.")
return hashlib.sha256(secret.encode(UTF_8)).digest()[:key_size]
def encrypt_to_base64(plain_text: str, secret: str, key_size: int) -> str:
padder = padding.PKCS7(algorithms.AES.block_size).padder()
padded_bytes = padder.update(plain_text.encode(UTF_8)) + padder.finalize()
cipher = make_aes_ecb_cipher(secret, key_size)
encryptor = cipher.encryptor()
encrypted_bytes = encryptor.update(padded_bytes) + encryptor.finalize()
return b64E(encrypted_bytes).decode(UTF_8)
def decrypt_from_base64(encrypted_text: str, secret: str, key_size: int) -> str:
encrypted_bytes = b64D(encrypted_text)
cipher = make_aes_ecb_cipher(secret, key_size)
decryptor = cipher.decryptor()
padded_bytes = decryptor.update(encrypted_bytes) + decryptor.finalize()
unpadder = padding.PKCS7(algorithms.AES.block_size).unpadder()
unpadded_bytes = unpadder.update(padded_bytes) + unpadder.finalize()
return unpadded_bytes.decode(UTF_8)