AES
Wikipedia: https://en.wikipedia.org/wiki/Advanced_Encryption_Standard. AES needs Key, IV and PKCS.
- Use 256 bits key length, Python/Go can auto choice by key length your passed. Named `MCRYPT_RIJNDAEL_128` in PHP5, Nodejs/PHP7.1 is aes-256-cbc.
- Use CBC mode due to ECB no IV.
- Key is `AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA` (256 bits),IV is `AAAAAAAAAAAAAAAA`(128bits).
- Python use pycrypto(pip install pycrypto),NodeJS require crypto(npm install crypto),PHP5 need `mcrypt`.
Python
from Crypto.Cipher import AES
import base64
def _pad(s): return s + (AES.block_size - len(s) % AES.block_size) * chr(AES.block_size - len(s) % AES.block_size)
def _cipher():
key = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
iv = 'AAAAAAAAAAAAAAAA'
return AES.new(key=key, mode=AES.MODE_CBC, IV=iv)
def encrypt_token(data):
return _cipher().encrypt(_pad(data))
def decrypt_token(data):
return _cipher().decrypt(data)
if __name__ == '__main__':
print('Python encrypt: ' + base64.b64encode(encrypt_token('dmyz.org')))
print('Python decrypt: ' + decrypt_token(base64.b64decode('FSfhJ/gk3iEJOPVLyFVc2Q==')))
Go
package main
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"fmt"
)
var (
key = []byte("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
iv = []byte("AAAAAAAAAAAAAAAA")
block cipher.Block
)
func init() {
block, _ = aes.NewCipher(key)
}
func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
func EncryptToken(key, iv, data []byte) string {
paddingData := PKCS5Padding(data, block.BlockSize())
cipherData := make([]byte, len(paddingData))
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(cipherData, paddingData)
encoded := base64.StdEncoding.EncodeToString(cipherData)
return encoded
}
func DecryptToken(key []byte, iv []byte, data string) string {
decoded, err := base64.StdEncoding.DecodeString(data)
if err != nil {
panic(err)
}
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(decoded, decoded)
if err != nil {
panic(err)
}
return string(decoded)
}
func main() {
fmt.Printf("Go encrypt: %s\n", EncryptToken(key, iv, []byte("dmyz.org")))
fmt.Printf("Go decrypt: %s\n", DecryptToken(key, iv, "FSfhJ/gk3iEJOPVLyFVc2Q=="))
}
Javascript(NodeJS)
var crypto = require('crypto'),
key = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
iv = 'AAAAAAAAAAAAAAAA';
function encrypt_token(data) {
var cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
cipher.update(data, 'binary', 'base64');
return cipher.final('base64');
}
function decrypt_token(data) {
var decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
decipher.update(data, 'base64', 'binary');
return decipher.final('binary');
}
console.log('NodeJS encrypt: ', encrypt_token('dmyz.org'));
console.log('NodeJS decrypt: ', decrypt_token('FSfhJ/gk3iEJOPVLyFVc2Q=='));
// NodeJS V0.8+ https://github.com/joyent/node/wiki/Api-changes-between-v0.8-and-v0.10
var crypto = require('crypto'),
key = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
iv = 'AAAAAAAAAAAAAAAA';
function encrypt_token(data) {
var encipher = crypto.createCipheriv('aes-256-cbc', key, iv),
buffer = Buffer.concat([
encipher.update(data),
encipher.final()
]);
return buffer.toString('base64');
}
function decrypt_token(data) {
var decipher = crypto.createDecipheriv('aes-256-cbc', key, iv),
buffer = Buffer.concat([
decipher.update(Buffer.from(data, 'base64')),
decipher.final()
]);
return buffer.toString();
}
console.log('NodeJS encrypt: ', encrypt_token('dmyz.org'));
console.log('NodeJS decrypt: ', decrypt_token('FSfhJ/gk3iEJOPVLyFVc2Q=='));
PHP
<?php
class AES
{
var $key = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
var $iv = 'AAAAAAAAAAAAAAAA';
function encryptToken($data)
{
// Mcrypt library has been DEPRECATED since PHP 7.1, use openssl:
// return openssl_encrypt($data, 'aes-256-cbc', $this->key, OPENSSL_RAW_DATA, $this->iv);
$padding = 16 - (strlen($data) % 16);
$data .= str_repeat(chr($padding), $padding);
return mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $this->key, $data, MCRYPT_MODE_CBC, $this->iv);
}
function decryptToken($data)
{
// Mcrypt library has been DEPRECATED since PHP 7.1, use openssl:
// return openssl_decrypt(base64_decode($data), 'aes-256-cbc', $this->key, OPENSSL_RAW_DATA, $this->iv);
$data = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $this->key, base64_decode($data), MCRYPT_MODE_CBC, $this->iv);
$padding = ord($data[strlen($data) - 1]);
return substr($data, 0, -$padding);
}
}
if (php_sapi_name() === 'cli')
{
$aes = new AES();
echo ('PHP encrypt: '.base64_encode($aes->encryptToken('dmyz.org')))."\n";
echo ('PHP decrypt: '.$aes->decryptToken('FSfhJ/gk3iEJOPVLyFVc2Q=='))."\n";
}
Testing
Environment:
- Ubuntu 14.04.2
- Go 1.5
- Python 2.7.6
- NodeJS v0.10.25
- PHP 5.5.9
python test.py && go run main.go && nodejs test.js && php test.php
# Python encrypt: FSfhJ/gk3iEJOPVLyFVc2Q==
# Python decrypt: dmyz.org
# Go encrypt: FSfhJ/gk3iEJOPVLyFVc2Q==
# Go decrypt: dmyz.org
# Nodejs encrypt: FSfhJ/gk3iEJOPVLyFVc2Q==
# Nodejs decrypt: dmyz.org
# PHP encrypt: FSfhJ/gk3iEJOPVLyFVc2Q==
# PHP decrypt: dmyz.org
The best resource it works really well, thanks a lot
Excellent post, I was searched 4 days for this solution. I have found one drawback though. unpad is missing in the python function.
def unpad(s): return s[:-ord(s[len(s) – 1:])]
Small modification in the main function.
if __name__ == ‘__main__’:
encrypted = base64.b64encode(encrypt_token(‘TestingPython’))
encrypted = encrypted.decode(‘utf-8’)
print(‘Python encrypt: ‘ , encrypted )
print(‘Python decrypt: ‘ , unpad(decrypt_token(base64.b64decode(encrypted)).decode(‘utf-8’)))
Thans for your modification! :D