Skip to content

Instantly share code, notes, and snippets.

@CoderJava
Last active June 16, 2024 18:59
Show Gist options
  • Save CoderJava/5da28312758f8b4c4b4d9327ab838994 to your computer and use it in GitHub Desktop.
Save CoderJava/5da28312758f8b4c4b4d9327ab838994 to your computer and use it in GitHub Desktop.
CryptoJS encryption decryption in Vue, PHP, and Dart based on this solution (https://stackoverflow.com/a/64330804/10308290)
import 'dart:convert';
import 'dart:math';
import 'dart:typed_data';
import 'package:crypto/crypto.dart';
import 'package:tuple/tuple.dart';
import 'package:encrypt/encrypt.dart' as encrypt;
// Thanks to https://medium.com/@chingsuehok/cryptojs-aes-encryption-decryption-for-flutter-dart-7ca123bd7464
class AES {
String encryptAESCryptoJS(String plainText, String passphrase) {
try {
final salt = genRandomWithNonZero(8);
var keyndIV = deriveKeyAndIV(passphrase, salt);
final key = encrypt.Key(keyndIV.item1);
final iv = encrypt.IV(keyndIV.item2);
final encrypter = encrypt.Encrypter(encrypt.AES(key, mode: encrypt.AESMode.cbc, padding: "PKCS7"));
final encrypted = encrypter.encrypt(json.encode(plainText), iv: iv);
return '{"ct":"${encrypted.base64}","iv":"${iv.base16}","s":"${bin2hex(salt)}"}';
} catch (error) {
throw error;
}
}
String decryptAESCryptoJS(String jsonEncrypted, String passphrase) {
try {
final jsonData = json.decode(jsonEncrypted) as Map<String, dynamic>;
final salt = hex2bin(jsonData['s']);
final ct = base64.decode(jsonData['ct']);
final ivHex = hex2bin(jsonData['iv']);
final keyndIV = deriveKeyAndIV(passphrase, salt);
final key = encrypt.Key(keyndIV.item1);
final iv = encrypt.IV(ivHex);
final encrypter = encrypt.Encrypter(encrypt.AES(key, mode: encrypt.AESMode.cbc, padding: "PKCS7"));
final decrypted = encrypter.decrypt64(base64.encode(ct), iv: iv);
return json.decode(decrypted);
} catch (error) {
throw error;
}
}
Tuple2<Uint8List, Uint8List> deriveKeyAndIV(String passphrase, Uint8List salt) {
var password = createUint8ListFromString(passphrase);
Uint8List concatenatedHashes = Uint8List(0);
Uint8List currentHash = Uint8List(0);
bool enoughBytesForKey = false;
Uint8List preHash = Uint8List(0);
while (!enoughBytesForKey) {
int preHashLength = currentHash.length + password.length + salt.length;
if (currentHash.length > 0)
preHash = Uint8List.fromList(currentHash + password + salt);
else
preHash = Uint8List.fromList(password + salt);
currentHash = Uint8List.fromList(md5.convert(preHash).bytes);
concatenatedHashes = Uint8List.fromList(concatenatedHashes + currentHash);
if (concatenatedHashes.length >= 48) enoughBytesForKey = true;
}
var keyBtyes = concatenatedHashes.sublist(0, 32);
var ivBtyes = concatenatedHashes.sublist(32, 48);
return new Tuple2(keyBtyes, ivBtyes);
}
Uint8List createUint8ListFromString(String s) {
var ret = new Uint8List(s.length);
for (var i = 0; i < s.length; i++) {
ret[i] = s.codeUnitAt(i);
}
return ret;
}
Uint8List genRandomWithNonZero(int seedLength) {
final random = Random.secure();
const int randomMax = 245;
final Uint8List uint8list = Uint8List(seedLength);
for (int i = 0; i < seedLength; i++) {
uint8list[i] = random.nextInt(randomMax) + 1;
}
return uint8list;
}
String bin2hex(Uint8List bytes, {String? separator, int? wrap}) {
var len = 0;
final buf = StringBuffer();
for (final b in bytes) {
final s = b.toRadixString(16);
if (buf.isNotEmpty && separator != null) {
buf.write(separator);
len += separator.length;
}
if (wrap != null && wrap < len + 2) {
buf.write('\n');
len = 0;
}
buf.write('${(s.length == 1) ? '0' : ''}$s');
len += 2;
}
return buf.toString();
}
Uint8List hex2bin(String hexStr) {
if (hexStr.length % 2 != 0) {
throw const FormatException('not an even number of hexadecimal characters');
}
final result = Uint8List(hexStr.length ~/ 2);
for (var i = 0; i < result.length; i++) {
result[i] = int.parse(hexStr.substring(2 * i, 2 * (i + 1)), radix: 16);
}
return result;
}
}
var CryptoJSAesJson = {
stringify: function (cipherParams) {
var j = {ct: cipherParams.ciphertext.toString(CryptoJS.enc.Base64)};
if (cipherParams.iv) j.iv = cipherParams.iv.toString();
if (cipherParams.salt) j.s = cipherParams.salt.toString();
return JSON.stringify(j);
},
parse: function (jsonStr) {
var j = JSON.parse(jsonStr);
var cipherParams = CryptoJS.lib.CipherParams.create({ciphertext: CryptoJS.enc.Base64.parse(j.ct)});
if (j.iv) cipherParams.iv = CryptoJS.enc.Hex.parse(j.iv)
if (j.s) cipherParams.salt = CryptoJS.enc.Hex.parse(j.s)
return cipherParams;
}
}
// <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
var key = "key123456";
var encrypted = CryptoJS.AES.encrypt(JSON.stringify("plaintext"), key, {format: CryptoJSAesJson}).toString();
console.log(encrypted);
var decrypted = JSON.parse(CryptoJS.AES.decrypt(encrypted, key, {format: CryptoJSAesJson}).toString(CryptoJS.enc.Utf8));
console.log("decryyepted: "+decrypted);
<?php
/**
*-------------PHP code example-----------------
*/
/**
* Decrypt data from a CryptoJS json encoding string
*
* @param mixed $passphrase
* @param mixed $jsonString
* @return mixed
*/
function cryptoJsAesDecrypt($passphrase, $jsonString){
$jsondata = json_decode($jsonString, true);
$salt = hex2bin($jsondata["s"]);
$ct = base64_decode($jsondata["ct"]);
$iv = hex2bin($jsondata["iv"]);
$concatedPassphrase = $passphrase.$salt;
$md5 = array();
$md5[0] = md5($concatedPassphrase, true);
$result = $md5[0];
for ($i = 1; $i < 3; $i++) {
$md5[$i] = md5($md5[$i - 1].$concatedPassphrase, true);
$result .= $md5[$i];
}
$key = substr($result, 0, 32);
$data = openssl_decrypt($ct, 'aes-256-cbc', $key, true, $iv);
return json_decode($data, true);
}
/**
* Encrypt value to a cryptojs compatiable json encoding string
*
* @param mixed $passphrase
* @param mixed $value
* @return string
*/
function cryptoJsAesEncrypt($passphrase, $value){
$salt = openssl_random_pseudo_bytes(8);
$salted = '';
$dx = '';
while (strlen($salted) < 48) {
$dx = md5($dx.$passphrase.$salt, true);
$salted .= $dx;
}
$key = substr($salted, 0, 32);
$iv = substr($salted, 32,16);
$encrypted_data = openssl_encrypt(json_encode($value), 'aes-256-cbc', $key, true, $iv);
$data = array("ct" => base64_encode($encrypted_data), "iv" => bin2hex($iv), "s" => bin2hex($salt));
return json_encode($data);
}
// Example
$key = "key123456";
$encrypted = '{"ct":"XMW1sLzwrSv3b+aGyaT0UQ==","iv":"e4871f22e7fd444a01b624f8d27c0381","s":"aace984f071407b1"}';
$decrypted = cryptoJsAesDecrypt($key, $encrypted);
echo "decrypted: $decrypted";
?>
import 'aes.dart';
void main(List<String> args) {
String ct = AES().encryptAESCryptoJS(
'plaintext',
'key123456',
);
print('ct: $ct');
String pt = AES().decryptAESCryptoJS(
ct,
'key123456',
);
print('pt: $pt');
}
name: belajar_aes
description: A simple command-line application.
version: 1.0.0
# homepage: https://www.example.com
environment:
sdk: '>=2.14.2 <3.0.0'
dependencies:
encrypt: ^5.0.1
tuple: ^2.0.0
dev_dependencies:
lints: ^1.0.0
@CoderJava
Copy link
Author

Here is the output

Screen.Recording.2021-10-16.at.15.28.08.mov

@Yagniksojitra
Copy link

Thanks its very much helpfule to understand, it's very confusing to undestand Crypto js directly. I am trying to recreate in python but not able to get any luck.

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