crypto/crypto/ AESRecipes1
Python
from Crypto.Cipher import AES
def pad_pcs7(x):
l = len(x)
a = l % 16
b = 16 - a
c = bytes([b]*b)
return x + c
def enc(plaintext,phrase,iterations=1234):
salt = os.urandom(256)
iv = os.urandom(16)
key = hashlib.pbkdf2_hmac("sha512",phrase.encode("utf8"),salt,iterations,32)
aes = AES.new(key, AES.MODE_CBC, IV=iv)
bplaintext = plaintext.encode("utf8")
bplaintext = pad_pcs7(bplaintext)
ciphertext = aes.encrypt(bplaintext)
ciphertext_b64 = b64e(ciphertext)
obj = {
"ciphertext": ciphertext_b64.decode("utf8"),
"salt": salt.hex(),
"iv": iv.hex(),
"iterations": iterations
}
return obj
I use this, for example, to create SelfDecryptingWebpage's in Python which can be decrypted with Javascript (using CryptoJS).
Javascript
This is compatible with the Python encrypt above. Using cryptojs on my gitub
<script src="aes.js"></script>
<script src="sha512.js"></script>
<script src="pbkdf2.js"></script>
...
const enc = (passphrase,plaintext,iterations=1977) => {
const salt = CryptoJS.lib.WordArray.random(256)
const iv = CryptoJS.lib.WordArray.random(16)
const key = CryptoJS.PBKDF2(passphrase, salt, { hasher: CryptoJS.algo.SHA512, keySize: 64/8, iterations})
const encrypted = CryptoJS.AES.encrypt(plaintext, key, { iv })
const ciphertext = encrypted.toString()
const obj = { ciphertext, salt: salt.toString(CryptoJS.enc.Hex),
iv: iv.toString(CryptoJS.enc.Hex), iterations }
return obj
}
const decrypt = (passphrase,obj) => {
const { ciphertext, iterations } = obj
const salt = CryptoJS.enc.Hex.parse(obj.salt)
const iv = CryptoJS.enc.Hex.parse(obj.iv)
const key = CryptoJS.PBKDF2(passphrase, salt, { hasher: CryptoJS.algo.SHA512, keySize: 64/8, iterations})
const decrypted = CryptoJS.AES.decrypt(ciphertext, key, { iv })
return decrypted.toString(CryptoJS.enc.Utf8)
}
Php
This may not be compatible with the above
This also generates a hash, and stores the iv and hash in the ciphertext.
function encrypt($plaintext, $password) {
$method = "AES-256-CBC";
$key = hash('sha256', $password, true);
$iv = openssl_random_pseudo_bytes(16);
$ciphertext = openssl_encrypt($plaintext, $method, $key, OPENSSL_RAW_DATA, $iv);
$hash = hash_hmac('sha256', $ciphertext . $iv, $key, true);
return $iv . $hash . $ciphertext;
}
function decrypt($ivHashCiphertext, $password) {
$method = "AES-256-CBC";
$iv = substr($ivHashCiphertext, 0, 16);
$hash = substr($ivHashCiphertext, 16, 32);
$ciphertext = substr($ivHashCiphertext, 48);
$key = hash('sha256', $password, true);
if (!hash_equals(hash_hmac('sha256', $ciphertext . $iv, $key, true), $hash)) return null;
return openssl_decrypt($ciphertext, $method, $key, OPENSSL_RAW_DATA, $iv);
}
Slightly less secure but slightly less data
This is perhaps slightly less secure, for situations where you want some crypto, but it's not critical enough to warrant generating a cryptographically random iv and storing a hmac.
<?php
function make_random_iv() {
$iv = openssl_random_pseudo_bytes(16);
return $iv;
}
function iv_from_hash($x) {
$a = hash("sha256",$x,true);
$b = substr($a,0,16);
return $b;
}
function encrypt($plaintext, $password, $iv) {
$method = "AES-256-CBC";
$key = hash('sha256', $password, true);
$ciphertext = openssl_encrypt($plaintext, $method, $key, OPENSSL_RAW_DATA, $iv);
return $ciphertext;
}
function decrypt($ciphertext, $password, $iv) {
$method = "AES-256-CBC";
$key = hash('sha256', $password, true);
return openssl_decrypt($ciphertext, $method, $key, OPENSSL_RAW_DATA, $iv);
}
and a simple test of the above
<?php
include_once("aescm.php");
$iv = make_random_iv();
$a = encrypt("hello","world",$iv);
$b = decrypt($a,"world",$iv);
$x = base64_encode($a);
echo "$x\n\n$b\n\n";
echo "-----\n";
$iv = iv_from_hash("boing");
$a = encrypt("hello","world",$iv);
$b = decrypt($a,"world",$iv);
$x = base64_encode($a);
echo "$x\n\n$b\n\n";
The main aim for this is to store encrypted data in cookies, and cookies have limited space, so we save the bytes from storing the iv and hmac in the ciphertext, and instead eschewing hmac and generating the iv using a hash. Potentially this is cryptographically weaker, but in its intended use it is secure enough, and is far from worth the effort to crack. (This is for things like making an adventure game in PHP where we use hashing and encrypting so as to store keys and inventories in the user's cookies but in such a way as to make them indecipherable and impossible to manipulate – nothing life and death or financial.)