AES-CBC encryption and decryption Node.js version with Python will also be added.

Flow of sample program (AES encryption, decryption)

First, install the library

pip install pycrypto

Client side (encrypting side in the sample program)

Initialization vector (16 bytes), key When using + α PBKDF, a password for generating a derived key is also available. .Encryption → Binary data can be created Convert binary data (encrypted data) to Base64 or hexadecimal number, make it URL-encoded, and send it to the server

Server side (complex side in the sample program)

.URL decoding .Conversion of Base64 and hexadecimal numbers to binary . Prepare the same initial vector, key, etc. as the encrypted side. Rather than having the initial vector as a fixed value, it is safer to generate a different one each time by a method that only the encrypting side and the decrypting side can know. . Composite

Points and precautions

Prepare the initial vector, salt, and password. It is recommended that the initial vector be randomly generated each time rather than a fixed value.

Here, as an example, the initial vector is digested to the current time stamp → displayed in hexadecimal number → sha512. I thought about the generation method appropriately to grasp the whole flow.

*** Please do not use the initial vector, salt and password as they are. *** ***

Client side (encryptor)


# -*- coding: utf-8 -*-
import base64
import urllib.parse
from Crypto.Cipher import AES
from Crypto.Protocol.KDF import PBKDF2
from Crypto.Util import Padding
import requests
from datetime import datetime,timedelta,timezone
import hashlib

#Initialization vector creation(I thought about the generation method as if I used it for sha512.)Since it is converted to hexadecimal bytes type, the number of characters should be an even number.
JST = timezone(timedelta(hours=9),"JST")
now = hex(int(datetime.now(JST).timestamp()))
hs = hashlib.sha512(now.encode()).hexdigest()
hex_iv = hs[0:100]
#Since it is converted to salt hexadecimal bytes type, the number of characters should be an even number.
hex_salt = "39ccc779ab356eb43b4f37aedbc891d2f891756710b7856d21a2fd691483fb17"
secret_key = "asd@dfdfdsds"


def encrypt(plainText):
    #The length of the initial vector must be 16 bytes
    iv = bytes.fromhex(hex_iv)[:AES.block_size]
    #Number of stretches The larger this number, the stronger the encryption strength and the slower the encryption / decryption execution speed.
    secure_levels = 100
    #There are no particular restrictions on salt length
    salt = bytes.fromhex(hex_salt)
    
    #Derived key generation: In the case of AES, the key length is 16 bytes(AES-128), 24 bytes(AES-192), 32bytes(AES-256)Must be one of
    key = PBKDF2(password=secret_key, salt=salt, dkLen=16, count=secure_levels)
    
    #Cipher creation
    cipher = AES.new(key, AES.MODE_CBC, iv)

    #Padding
    data = plainText.encode()
    padding = AES.block_size - len(data) % AES.block_size
    data += (chr(padding) * padding).encode()

    #encryption
    encrypted = cipher.encrypt(data)
    
    print(f"encrypted = {encrypted}\n")
    
    #binary to HEX
    hex_data = encrypted.hex()
    print(f"hex_data : binary to HEX = {hex_data}\n")

    #Base64 encoding
    base64_encoded = base64.b64encode(hex_data.encode())
    print(f"base64_encoded : Hex to Base64 = {base64_encoded.decode()}\n")

    #URL encoding Not needed this time, but URL encoding whenever needed
    # url_encoded = urllib.parse.quote(base64_encoded)

    return base64_encoded


if __name__ == "__main__":
    plainText = "Test the encryption."
    print(f"\nPlain text = {plainText}\n")
    
    #encryption
    encrypted = encrypt(plainText)

    #Send
    requests.get("http://localhost:5000/get",params={"text" : encrypted,"now" : now})

Server side (complex)


# -*- coding: utf-8 -*-
import base64
import json
import urllib.parse
from Crypto.Cipher import AES
from Crypto.Protocol.KDF import PBKDF2
from Crypto.Util import Padding
from flask import Flask, render_template, request
import hashlib

app = Flask(__name__)


#Salt hexadecimal number. Since it will be converted to bytes type, the number of characters should be an even number.
hex_salt = "39ccc779ab356eb43b4f37aedbc891d2f891756710b7856d21a2fd691483fb17"
secret_key = "asd@dfdfdsds"


def decrypt(base64encoded_value,now):
    #URL decoding Not required this time, but URL decoding at any time if required in other languages, etc.
    # url_decoded = urllib.parse.unquote(base64encoded_value)
    # print(f"url_decoded = {url_decoded}")

    #Base64 decoding
    hex_data = base64.b64decode(base64encoded_value).decode()
    print(f"hex_data : Base64 to Hex = {hex_data}\n")

    # HEX → binary
    encrypted_data = bytes.fromhex(hex_data)
    print(f"encrypted_data : Hex to binary = {encrypted_data}\n")

    #The length of the initial vector must be 16 bytes
    hs = hashlib.sha512(now.encode()).hexdigest()
    hex_iv = hs[0:100]
    iv = bytes.fromhex(hex_iv)[:AES.block_size]
    #Number of stretches The larger this number, the stronger the encryption strength and the slower the encryption / decryption execution speed.
    secure_levels = 100
    #There are no particular restrictions on salt length
    salt = bytes.fromhex(hex_salt)

    #Derivation key generation
    key = PBKDF2(password=secret_key, salt=salt, dkLen=16, count=secure_levels)

    #Cipher creation
    cipher = AES.new(key, AES.MODE_CBC, iv)

    #Composite
    decrypted = cipher.decrypt(encrypted_data)

    #Unpadding
    response = decrypted[0: -int(decrypted[-1])].decode('utf-8')
    return response

#Get Parameter Get
@app.route('/get')
def get():
    text = ""
    if "text" not in request.args or "now" not in request.args:
        return json.dumps({"message": "send message"})

    base64encoded_value = request.args.get('text')
    now = request.args.get('now')
    print(f"\nbase64encoded_value = {base64encoded_value}\n")
       
    #Decryption
    decrypted_data = decrypt(base64encoded_value,now)
    print(f"decrypted_data = {decrypted_data}\n")        

    return json.dumps({"message": "OK"})


if __name__ == "__main__":
    app.run(host='0.0.0.0',port=5000)

Recommended Posts

AES-CBC encryption and decryption Node.js version with Python will also be added.
Encryption and decryption with Python
Understanding with mathematical formulas and Python LiNGAM (ICA version)
Version control of Node, Ruby and Python with anyenv
pycrypto encryption and decryption
Check version with python
Installation procedure for Python and Ansible with a specific version
Try encryption / decryption using OpenSSL key with Python3 pow function
Programming with Python and Tkinter
Python and hardware-Using RS232C with Python-
python with pyenv and venv
Specify python version with virtualenv
Works with Python and R
Encryption / decryption with GPG command