AES Java to Python

Question:

This is an AES encryption code I’ve gotten from a Java source. This bugs me, as the Cipher itself doesn’t use any initial vector in it’s initialization – thus I can’t seem to to the same thing in Python. Can anyone with a Java background help me understand what this actually does?

byte key[] = {0x13, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, (byte) 0xB4, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00};
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] myIv = {70, 114, 122, 82, 70, 114, 122, 82, 70, 114, 122, 82, 70, 114, 122, 82}
byte[] newIv = cipher.doFinal(myIv);
Asked By: Martol1ni

||

Answers:

Java has providers which implement some schemes. A scheme is chosen from a string, in your case Cipher.getInstance("AES"). Since it is not possible to run plain AES in Java, it selects some defaults to make it a complete scheme.

It is necessary to determine the mode of operation and optionally the padding mode. Most providers in Java default to "AES/ECB/PKCS5Padding" when they see "AES".

Now for byte[] newIv = cipher.doFinal(myIv). This line encrypts the plaintext (myIv) with AES in ECB mode and applies PKCS#7 padding. ECB mode doesn’t use an IV, so this is bad variable naming, because myIv is not an IV for the encryption.

This is a post that shows how padding and unpadding can be done.

Answered By: Artjom B.

The code uses "AES" as algorithm string, which (indeed) resolves to "AES/ECB/PKCS5Padding". It seems you can use AES.MODE_ECB in python using PyCrypto, so it should be no problem replicating that. You may have to implement PKCS#7 padding/unpadding yourself though (or use one of the many examples on the internet). You would not need any IV because ECB doesn’t use an IV.

As why a static key is used and why a static IV is being encrypted (with padding) is unknown to me. That can only be clarified by the author of the code. It certainly does not follow best practice.

Answered By: Maarten Bodewes

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)
Answered By: frozenOne
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.