Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save franzwarning/1e5fab9d7d2e90086e567768e71904be to your computer and use it in GitHub Desktop.
Save franzwarning/1e5fab9d7d2e90086e567768e71904be to your computer and use it in GitHub Desktop.
Java, Python, and Javascript Encryption/Decryption with AES/CBC/PKCS5PADDING

Had some trouble in the past with equivalent encryption/decryption across these three languages so figured I'd share my findings.

Note: I'm aware the IV you choose shouldn't be static, but for this example it saved some string manipulation code. What I've seen people do is attach the IV to the front of the encrypted string (first 16 characters), then substring when you are decryption.

Would love to hear your thoughts / comments!

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.util.Base64;
public class HelloWorld {
public static void main(String []args) {
String key = "sixteencharacter";
String initVector = "jvHJ1XFt0IXBrxxx";
String value = "secret message of any length";
try {
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = cipher.doFinal(value.getBytes());
String encryptedResult = Base64.getUrlEncoder().encodeToString(encrypted);
System.out.println("Encrypted string: " + encryptedResult);
Cipher cipherd = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipherd.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] original = cipherd.doFinal(Base64.getUrlDecoder().decode(encryptedResult));
String decryptedResult = new String(original);
System.out.println("Decrypted string: " + decryptedResult);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
// Output:
// Encrypted string: gnLjDGBLvO3-SUu56-FPRDA33Wx-XNoqcoygdyjG3TD1W8NJOtXZPmm76JRJ36QI
// Decrypted string: secret message of any length
var aesjs = require('aes-js');
var base64url = require('base64url');
// INIT
var to_encrypt = "secret message of any length";
var key = "sixteencharacter";
var iv = "jvHJ1XFt0IXBrxxx";
var keyBytes = aesjs.utils.utf8.toBytes(key);
var ivBytes = aesjs.utils.utf8.toBytes(iv);
function encrypt(msg) {
var aesCbc = new aesjs.ModeOfOperation.cbc(keyBytes, ivBytes);
var textBytes = aesjs.utils.utf8.toBytes(msg);
var padded = aesjs.padding.pkcs7.pad(textBytes);
var encryptedBytes = aesCbc.encrypt(padded);
return base64url.encode(encryptedBytes)
}
function decrypt(encrypted) {
var aesCbc = new aesjs.ModeOfOperation.cbc(keyBytes, ivBytes);
var encryptedBytes = base64url.toBuffer(encrypted)
var decryptedBytes = aesCbc.decrypt(encryptedBytes);
return aesjs.utils.utf8.fromBytes(decryptedBytes);
}
var encrypted = encrypt(to_encrypt);
var decrypted = decrypt(encrypted);
// PROCESS
console.log('--------')
console.log(`Encrypted: ${encrypted}`);
console.log(`Decrypted: ${decrypted}`);
console.log('--------')
// Output
// --------
// Encrypted: gnLjDGBLvO3-SUu56-FPRDA33Wx-XNoqcoygdyjG3TD1W8NJOtXZPmm76JRJ36QI
// Decrypted: secret message of any length
// --------
from Crypto.Cipher import AES
from Crypto import Random
import base64
import random
block_size = AES.block_size
#unpad = lambda s : s[0:-ord(s[-1])]
def pad(plain_text):
"""
func to pad cleartext to be multiples of 8-byte blocks.
If you want to encrypt a text message that is not multiples of 8-byte blocks,
the text message must be padded with additional bytes to make the text message to be multiples of 8-byte blocks.
"""
number_of_bytes_to_pad = block_size - len(plain_text) % block_size
ascii_string = chr(number_of_bytes_to_pad)
padding_str = number_of_bytes_to_pad * ascii_string
padded_plain_text = plain_text + padding_str
return padded_plain_text
key='sixteencharacter'
plain='secret message of any length'
plain = pad(plain)
iv = 'jvHJ1XFt0IXBrxxx'
cipher = AES.new(key, AES.MODE_CBC, iv)
encrypted_bytes = cipher.encrypt(plain)
encrypted_text = base64.urlsafe_b64encode(encrypted_bytes).decode("utf-8")
print('Encrypted Text: ' + encrypted_text)
# Output
# Encrypted Text: gnLjDGBLvO3-SUu56-FPRDA33Wx-XNoqcoygdyjG3TD1W8NJOtXZPmm76JRJ36QI
@sonalidhanke
Copy link

Please add Decryption for python

@Ajay-Raj-S
Copy link

Python AES decryption with CBC mode.

Decode the encrypted text

decrypted_text = base64.urlsafe_b64decode(encrypted_text)

Create a decipher with same key and iv for CBC mode, "Don't forget to encode your key and iv"

decipher = AES.new(bytes(key, encoding='utf-8'), AES.MODE_CBC, bytes(iv, encoding='utf-8'))

Decrypt the decrypted_text

decrypted_bytes = decipher.decrypt(decrypted_text)

Decode them to get the plain with pad

decrypted_text = decrypted_bytes.decode('utf-8')

@Ajay-Raj-S
Copy link

Please encode the key and iv when encrypting.

@the-mgi
Copy link

the-mgi commented Apr 26, 2022

can you please, let us know which python package are you using. I am getting an error.
image

@DEV-XiA
Copy link

DEV-XiA commented Sep 23, 2022

Thank you for your work, but i got Encrypted Text: kD-rWmP1Oj7TX_EAcrwu2wNakol60RDq7D1DRkWQnbE=, not Encrypted Text: gnLjDGBLvO3-SUu56-FPRDA33Wx-XNoqcoygdyjG3TD1W8NJOtXZPmm76JRJ36QI in your comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment