I have created a Python & Node JS encryption/decryption AES 256-CFB. The point of this little project is that I will encrypt a special URL with Python covered with base64 & URL encoding and then the Node JS will decrypt it.

For now the Node JS is working perfectly fine that can starts by decoding the URL, decoding the Base64 and then decrypt the AES with special password key. Meaning that I will have the same key for Node JS and Python to be able to decrypt. Something to add, this will not be added to any other clients/users meaning that covering the password is not needed since no one will reach the code ever but me :)

import base64
import hashlib
import urllib.parse

from Crypto import Random
from Crypto.Cipher import AES

key = "testing"  # Will of course be another password

def encrypt(url):
    Encrypting the given url
    :param url:
    private_key = hashlib.sha256(key.encode()).digest()
    rem = len(url) % 16
    padded = str.encode(url) + (b'\0' * (16 - rem)) if rem > 0 else str.encode(url)
    iv = Random.new().read(AES.block_size)
    cipher = AES.new(private_key, AES.MODE_CFB, iv, segment_size=128)
    enc = cipher.encrypt(padded)[:len(url)]
    return base64.b64encode(iv + enc).decode()

def main():
    encrypted = urllib.parse.quote(encrypt("https://stackoverflow.com/"))
    url_decode = urllib.parse.unquote(encrypted)

    print(f'Encrypted and URL encoded: {encrypted}\n')
    print(f'URL decoded: {urllib.parse.unquote(url_decode)}\n')

if __name__ == '__main__':

Now I wonder if there is anyhow where I can improve the code in any how? In my eyes I don't see any ways to improve anyhow but I always end up be wrong :D


2 Answers 2


The padding step is unnecessary - CFB works out of the box on any plaintext length since it XORS the plaintext with the AES output.

Lack of authentication means that the scheme is vulnerable to a bit flipping attack, where you can flip bits in the ciphertext and cause a corresponding bit flip in the plaintext.

Other nitpicks:

  • str.encode(url) should be url.encode()
  • your docstring has a :return: but it doesn't declare anything

Just a quick note on how you generate the key:

key = "testing"  # Will of course be another password
  • IMO, password would be a more descriptive variable name
  • there is no need to write a password in your source code. You can either read it from a file or from the console via the getpass module

    private_key = hashlib.sha256(key.encode()).digest()
  • when you derive a key from a password you shouldn't use sha256, since there are more specialized functions for this purpose. I would suggest you to use hashlib.scrypt.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.