javascript - JS Decrypt Laravel Encrypted String
Solution:
This is how you decrypt a text in javascript encoded with Laravel using AES-256-CBC as the cipher.
CryptoJS 4.0 is used...
// Created using Crypt::encryptString('Hello world.') on Laravel.
// If Crypt::encrypt is used the value is PHP serialized so you'll
// need to "unserialize" it in JS at the end.
var encrypted = 'eyJpdiI6ImRIN3QvRGh5UjhQNVM4Q3lnN21JNFE9PSIsInZhbHVlIjoiYlEvNzQzMnpVZ1dTdG9ETTROdnkyUT09IiwibWFjIjoiM2I4YTg5ZmNhOTgyMzgxYjcyNjY4ZGFkNTc4MDdiZTcyOTIyZjRkY2M5MTM5NTBjMmMyZGMyNTNkMzMwYzY3OCJ9';
// The APP_KEY in .env file. Note that it is base64 encoded binary
var key = 'E2nRP0COW2ohd23+iAW4Xzpk3mFFiPuC8/G2PLPiYDg=';
// Laravel creates a JSON to store iv, value and a mac and base64 encodes it.
// So let's base64 decode the string to get them.
encrypted = atob(encrypted);
encrypted = JSON.parse(encrypted);
console.log('Laravel encryption result', encrypted);
// IV is base64 encoded in Laravel, expected as word array in cryptojs
const iv = CryptoJS.enc.Base64.parse(encrypted.iv);
// Value (chipher text) is also base64 encoded in Laravel, same in cryptojs
const value = encrypted.value;
// Key is base64 encoded in Laravel, word array expected in cryptojs
key = CryptoJS.enc.Base64.parse(key);
// Decrypt the value, providing the IV.
var decrypted = CryptoJS.AES.decrypt(value, key, {
iv: iv
});
// CryptoJS returns a word array which can be
// converted to string like this
decrypted = decrypted.toString(CryptoJS.enc.Utf8);
console.log(decrypted); // Voilà! Prints "Hello world!"
Answer
Solution:
Like @Dusan Malusev already mentioned:
You should not use Laravel APP_KEY in frontend code. NEVER, Laravel uses APP_KEY to encrypt everything including cookies (Session cookie and csrf cookie).
Your application could be hacked if it's in your html code! To answer your question a bit: use Crypt::decrypt($encrypted)
on the server side of your application (within Laravel).
Answer
Solution:
Never use your Laravel APP_KEY in frontend. It is a big software vulnerability.
You should create a trait that encrypts and decrypts data before setting and getting data.
To use Laravel Crypt add Encryptable.php
<?PHP
namespace App;
use Illuminate\Support\Facades\Crypt;
trait Encryptable
{
public function getAttribute($key)
{
$value = parent::getAttribute($key);
if (in_array($key, $this->encryptable)) {
$value = Crypt::decrypt($value);
}
return $value;
}
public function setAttribute($key, $value)
{
if (in_array($key, $this->encryptable)) {
$value = Crypt::encrypt($value);
}
return parent::setAttribute($key, $value);
}
}
After that you can use this trait in your models. Add a $encryptable property. Array of columns to be encrypted and decrypted.
class User extends Model
{
use Encryptable;
protected $encryptable = [
'column',
'anotherColumn',
];
}
After that use model as you use before.
Answer
Solution:
I have used in ReactJs
CryptoJS 4.1
let key = process.env.REACT_APP_ENCRYTO_KEY
let encrypted = atob(response.data)
encrypted = JSON.parse(encrypted)
const iv = CryptoJS.enc.Base64.parse(encrypted.iv)
const value = encrypted.value
key = CryptoJS.enc.Base64.parse(key)
let decrypted = CryptoJS.AES.decrypt(value, key, {
iv
})
decrypted = decrypted.toString(CryptoJS.enc.Utf8)
return {
...response,
data: JSON.parse(decrypted)
}
Laravel 8.x using Encrypter
$encrypter = new Encrypter(Encrypter::generateKey('supported_any_cipher'));
return response($encrypter->encryptString(json_encode($response)), 200);
The supported cipher algorithms and their properties.
['aes-128-cbc' => ['size' => 16, 'aead' => false],
'aes-256-cbc' => ['size' => 32, 'aead' => false],
'aes-128-gcm' => ['size' => 16, 'aead' => true],
'aes-256-gcm' => ['size' => 32, 'aead' => true]]
Source