JS Decrypt Laravel Encrypted String - javascript

I have to decrypt laravel 6 encrypted string with javascript.
Key in laravel .env file
APP_KEY=base64:Rva4FZFTACUe94+k+opcvMdTfr9X5OTfzK3KJHIoXyQ=
And in config/app.php file cipher is set to following...
'cipher' => 'AES-256-CBC',
What I have tried so far is given below...
Laravel Code
$test = 'this is test';
$encrypted = Crypt::encrypt($test);
HTML and Javascript Code
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/aes.js"></script>
var encrypted = 'eyJpdiI6IlB4NG0ra2F6SE9PZmVcL0lpUEFIeVlnPT0iLCJ2YWx1ZSI6IlVMQWJyVjcrcUVWZE1jQ25LbG5NTGRla0ZIOUE2MFNFXC9Ed2pOaWJJaXIwPSIsIm1hYyI6IjVhYmJmZDBkMzAwYzMzYzAzY2UzNzY2';
var key = 'Rva4FZFTACUe94+k+opcvMdTfr9X5OTfzK3KJHIoXyQ='; // this is laravel key in .env file
var decrypted = CryptoJS.AES.decrypt(encrypted, key);
console.log(decrypted);
Console out put of the above code is given below in screenshot...
I have tried so many other JS pieces of code from google and stack overflow, but no luck.
Update
This is requirement to decrypt string in separate offline system. I am not going to dcrypt with javascript on live website. Rather decryption with java script will be done on offline system.

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!"

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).

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.

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]]

Related

How to decrypt AES256 data which was encrypted on PHP and get value in Javascript?

I have encrypted some value using aes-256-cbc mode on PHP like this:
public function encrypt(string $data): string
{
$iv = $this->getIv();
$encryptedRaw = openssl_encrypt(
$data,
$this->cryptMethod, //aes-256-cbc
$this->key,
OPENSSL_RAW_DATA,
$iv
);
$hash = hash_hmac('sha256', $encryptedRaw, $this->key, true);
return base64_encode( $iv . $hash . $encryptedRaw );
}
Then I tried to decrypt it on PHP and it works fine:
public function decrypt(string $data): string
{
$decoded = base64_decode($data);
$ivLength = openssl_cipher_iv_length($this->cryptMethod);
$iv = substr($decoded, 0, $ivLength);
$hmac = substr($decoded, $ivLength, $shaLength = 32);
$decryptedRaw = substr($decoded, $ivLength + $shaLength);
$originalData = openssl_decrypt(
$decryptedRaw,
$this->cryptMethod,
$this->key,
OPENSSL_RAW_DATA,
$iv
);
So I'm new to JavaScript and I don't know how to realize the same decrypt method as on php.
Example of encrypted string and it's key:
encrypted string lUIMFpajICh/e44Mwkr0q9xdyJh5Q8zEJHi8etax5BRl78Vsyh+wDknmBga1L8p8SDZA6WKz1CvAAREFGreRAQ== secret key - 9SJ6O6IwmItSRICbXgdJ
Example what I found returns empty string:
const decodedString = base64.decode(
`lUIMFpajICh/e44Mwkr0q9xdyJh5Q8zEJHi8etax5BRl78Vsyh+wDknmBga1L8p8SDZA6WKz1CvAAREFGreRAQ==`
);
const CryptoJS = require("crypto-js");
var key = CryptoJS.enc.Latin1.parse("9SJ6O6IwmItSRICbXgdJ");
var iv = CryptoJS.enc.Latin1.parse(decodedString.slice(0, 16));
var ctx = CryptoJS.enc.Base64.parse(
"lUIMFpajICh/e44Mwkr0q9xdyJh5Q8zEJHi8etax5BRl78Vsyh+wDknmBga1L8p8SDZA6WKz1CvAAREFGreRAQ=="
);
var enc = CryptoJS.lib.CipherParams.create({ ciphertext: ctx });
console.log(
CryptoJS.AES.decrypt(enc, key, { iv: iv }).toString(CryptoJS.enc.Utf8)
);
}
What I did wrong?
The key used in the PHP code is only 20 bytes in size and thus too small for AES-256 (AES-256 requires a 32 bytes key). PHP/OpenSSL implicitly pads the key with 0x00 values to the required key length. In the CryptoJS code, this must be done explicitly.
Furthermore, in the CryptoJS code, IV (the first 16 bytes), HMAC (the following 32 bytes) and ciphertext (the rest) are not separated correctly.
Also, the authentication is missing. To do this, the HMAC for the ciphertext must be determined using the key and compared with the HMAC sent. Decryption only takes place if authentication is successful.
If all of this is taken into account, the posted code can be fixed e.g. as follows:
var key = CryptoJS.enc.Utf8.parse("9SJ6O6IwmItSRICbXgdJ".padEnd(32, "\0")); // pad key
var ivMacCiphertext = CryptoJS.enc.Base64.parse("lUIMFpajICh/e44Mwkr0q9xdyJh5Q8zEJHi8etax5BRl78Vsyh+wDknmBga1L8p8SDZA6WKz1CvAAREFGreRAQ==")
var iv = CryptoJS.lib.WordArray.create(ivMacCiphertext.words.slice(0, 4)); // get IV
var hmac = CryptoJS.lib.WordArray.create(ivMacCiphertext.words.slice(4, 4 + 8)); // get HMAC
var ct = CryptoJS.lib.WordArray.create(ivMacCiphertext.words.slice(4 + 8)); // get Ciphertext
var hmacCalc = CryptoJS.HmacSHA256(ct, key);
if (hmac.toString() === hmacCalc.toString()) { // authenticate
var dt = CryptoJS.AES.decrypt({ciphertext: ct}, key, { iv: iv }).toString(CryptoJS.enc.Utf8); // decrypt
console.log(dt);
} else {
console.log("Decryption failed");
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
A few thoughts for you:
Check that your encoding/decoding is working properly. For each stage
of the process, endode/decode, then console log the output and
compare input to output, and also between PHP and javascript.
CBC mode uses padding to fill out the blocks. Check that both stacks
are using the same padding type.
Rather than using CBC and a separate HMAC, how about jumping to AEAD (like AES
GCM) which avoids the padding issue, and also incorporates the MAC
into the encryption, so is a more simple interface?

Different AES Encrypt in JavaScript and PHP

I want to encrypt a data with PHP.
I before used from a javascript code to encrypt.
JavaScript Code:
const SHARED_KEY="XXelkee4v3WjMP81fvjgpNRs2u2cwJ7n3lnJzPt8iVY=";
const ZERO_IV=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
let data="6104337983063890";
aesEncrypt = async (data) => {
try{
let key = new Uint8Array(this.base64ToArray(SHARED_KEY));
let aes = new aesJs.ModeOfOperation.cbc(key, ZERO_IV)
let bData = aesJs.utils.utf8.toBytes(data);
let encBytes = aes.encrypt(aesJs.padding.pkcs7.pad(bData))
return this.arrayToHex(encBytes)
}catch(err) {
console.error(err)
return null
}
}
PHP Code:
$sharedSecret=base64_decode('XXelkee4v3WjMP81fvjgpNRs2u2cwJ7n3lnJzPt8iVY=');
$iv = '0000000000000000';
$data="6104337983063890";
$output = openssl_encrypt(
$data,
'AES-128-CBC',
$sharedSecret,
OPENSSL_RAW_DATA,
$iv
);
$output=bin2hex($output);
Output in two languages is:
JavaScript: 4b685c988d9e166efd0bc5830e926ae0d60111d9dd73d7b4f3c547282994546f (Correct)
PHP: 091da5cf4ffd853e58f5b4f0a07902219ce7ac9647801af5b3e8f755d63b71b4
I need encrypt with PHP that give me same with JavaScript.
You must use aes-256-cbc as algorithm in the PHP code, because the key is 32 bytes large.
Also you have to apply a zero vector as IV in the PHP code, which you can create with:
$iv = hex2bin('00000000000000000000000000000000');
This way, the PHP code provides the same ciphertext as the JavaScript code.
Note that a static IV is insecure. The correct way is to generate a random (non-secret) IV for each encryption and pass this IV along with the ciphertext to the decrypting side (typically concatenated).

Achieve same encryption using CryptoJS (JAVASCRIPT) and OpenSSL (PHP)

I would like to implement a PhP encryption function in a ReactJS application. I need to send the token in the specific format which was created with the OpenSSL library function (openssl_encrypt).
The PHP function produces a few character shorter string in comparison to the JAVASCRIPT function. Of course, both get the same attributes and properties.
PHP:
protected static function encrypt($stringData) {
$encrypted = false;
$encrypt_method = 'AES-256-CBC';
$iv = substr(hash('sha256', static::$ivMessage), 0, 16);
$encrypted= openssl_encrypt($stringData, $encrypt_method, static::$apiSecret, 0, $iv);
return $encrypted;
}
JAVASCRIPT:
export const encrypt = (stringData) => {
const iv = CryptoJS.SHA256(IV_MESSAGE).toString(CryptoJS.enc.Hex).substring(0, 16);
const encrypted = CryptoJS.AES.encrypt(stringData, API_SECRET, {
iv,
mode: CryptoJS.mode.CBC,
pad: CryptoJS.pad.ZeroPadding,
});
return encrypted;
};
Sample constants:
const stringData = "{"uid":19,"price":10000000,"duration":240,"credit_purpose":5,"new_tab":false,"cssFile":"kalkulatorok","css":[],"supported":false,"email":"test#test.hu","productType":"home_loan","method":"calculator","calculatorType":"calculator","unique":true}";
const IV_MESSAGE = "a";
const API_SECRET = "secret_key";
(same for PHP function --> $stringData, $ivMessage; $apiSecret)
How can I achieve to "replicate" the PHP function in JAVASCRIPT? What did I miss so far?
The following changes in the CryptoJS code are necessary to generate the ciphertext of the PHP code:
The key must be passed as WordArray. If it is passed as a string, it is interpreted as a passphrase from which a 32 bytes key is derived.
PHP pads too short keys with 0x00 values up to the specified length. CryptoJS does not do this and (due to a bug) generally uses undefined round numbers for AES in case of invalid keys, so that no matching ciphertext is to be expected.
PKCS7 padding is used in the PHP code (see comment). This must also be applied in CryptoJS code, which however is the default (as well as the CBC mode).
The following PHP code:
function encrypt($stringData) {
$ivMessage = "a";
$apiSecret = "secret_key";
$encrypted = false;
$encrypt_method = 'AES-256-CBC';
$iv = substr(hash('sha256', $ivMessage), 0, 16);
$encrypted= openssl_encrypt($stringData, $encrypt_method, $apiSecret, 0, $iv);
return $encrypted;
}
$stringData = '{"uid":19,"price":10000000,"duration":240,"credit_purpose":5,"new_tab":false,"cssFile":"kalkulatorok","css":[],"supported":false,"email":"test#test.hu","productType":"home_loan","method":"calculator","calculatorType":"calculator","unique":true}';
print(encrypt($stringData) . "\n");
returns the result:
d/H+FfTaT/3tIkaXtIix937p6Df/vlnxagNJGJ7ljj48phT7oA7QssTatL3WNZY0Igt0r5ObGyCt0AR0IccVTFVZdR+nzNe+RmKQEoD4dj0mRkZ7qi/y3bAICRpFkP3Nz42fuILKApRtmZqGLTNO6dwlCbUVvjg59fgh0wCzy15g51G6CYLsEHa89Dt193g4qcXRWFgI9gyY1Gq7FX0G6Ers0fySQjjNcfDJg0Hj5aSxbPU6EPn14eaWqkliNYSMqzKhe0Ev7Y54x2YlUCNQeLZhwWRM2W0N+jGU7W+P/bCtF4Udwv4cweUESXkHLGtlQ0K6O5etVJDtb7ZtdEI/sA==
The CryptoJS code below generates the same ciphertext:
const IV_MESSAGE = "a";
const API_SECRET = "secret_key\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
function encrypt(stringData){
const iv = CryptoJS.SHA256(IV_MESSAGE).toString(CryptoJS.enc.Hex).substring(0, 16);
const encrypted = CryptoJS.AES.encrypt(
stringData,
CryptoJS.enc.Utf8.parse(API_SECRET),
{
iv: CryptoJS.enc.Utf8.parse(iv)
});
return encrypted;
};
const stringData = {"uid":19,"price":10000000,"duration":240,"credit_purpose":5,"new_tab":false,"cssFile":"kalkulatorok","css":[],"supported":false,"email":"test#test.hu","productType":"home_loan","method":"calculator","calculatorType":"calculator","unique":true};
const ciphertextB64 = encrypt(JSON.stringify(stringData)).toString();
console.log(ciphertextB64.replace(/(.{64})/g,'$1\n'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
The following should also be taken into account:
It is more reliable to avoid encoding the IV as hex string when generating the IV and to directly use the binary data. Otherwise, you also have to keep in mind that depending on the platform, different upper/lower case of the hex numbers can generally be applied. Here this is not critical, since in both cases lower case is used.
If you should really apply a passphrase like secret_key as key, you should also use a reasonable key derivation function (e.g. PBKDF2 in combination with a randomly generated salt) because of the low entropy. The default KDF used in CryptoJS, the proprietary OpenSSL function EVP_BytesToKey, should not be applied because it is not a standard and is also deemed relatively insecure.
For security reasons no static IV may be used. Instead, a randomly generated IV should be applied for each encryption. The IV is not secret and is usually concatenated with the ciphertext in the order IV, ciphertext (see comment).

Encryption on crypto-js and decryption on node crypto using CTR mode issue

I am trying to encrypt data using crypto-js javascript library and trying to decrypt the same encrypted text on nodejs side using node crypto library. I am using AES 256 encryption algo with CTR mode with no padding. I am able to encrypt properly but the description on nodejs crypto module is not producing same plain text.
If I try to encrypt or decrypt using the same crypto-js and node crypto library, it works fine but encryption on crypto-js and description on crypto is not working as expected. I have tried to confirm if I encrypt and decrypt in the same library than it works or not and it works perfectly fine. Can someone please check what mistake I am making here?
Please find below code samples.
Encryption:
var key = CryptoJS.enc.Hex.parse('F29BA22B55F9B229CC9C250E11FD4384');
var iv = CryptoJS.enc.Hex.parse('C160C947CD9FC273');
function encrypt(plainText) {
return CryptoJS.AES.encrypt(
plainText,
key,
{
iv: iv,
padding: CryptoJS.pad.NoPadding,
mode: CryptoJS.mode.CTR
}
);
}
Descryption using NodeJS crypo module:
var algorithm = 'aes-256-ctr';
var key = 'F29BA22B55F9B229CC9C250E11FD4384';
var iv = 'C160C947CD9FC273';
var outputEncoding = 'hex';
var inputEncoding = 'hex';
const decipher = crypto.createDecipheriv(algorithm, key, iv);
let decrypted = decipher.update('8df5e11f521cf492437a95', inputEncoding, 'utf8');
decrypted += decipher.final('utf8');
console.log(decrypted);
As I have mentioned above, I have JavaScript crypo-js and NodeJS crypo module sessions working fine if I encrypt and decrypt using the same lib but doesn't work otherwise. Please check the working code as below.
JavaScript: http://jsfiddle.net/usr_r/2qwt8jsh/2/
NodeJS: https://repl.it/repls/AchingRegalPhp
I think your CryptoJS code isn't using AES-256, as the key and IV are too short and hence it's implicitly using AES-128. if you get the blockSize from the CryptoJS.AES object it says 4 for me. that said I don't know CryptoJS very well and that might not mean "4 words".
To bypass this implementation uncertainty, it's good to have a "gold standard" to replicate. NIST provides lots of test vectors, some of which apply to your CTR mode AES-256. First I pull out a set of (hex encoded) test vectors from that document:
const key = (
'603deb1015ca71be2b73aef0857d7781' +
'1f352c073b6108d72d9810a30914dff4'
)
const ctr = 'f0f1f2f3f4f5f6f7f8f9fafbfcfdff00'
const output = '5a6e699d536119065433863c8f657b94'
const cipher = 'f443e3ca4d62b59aca84e990cacaf5c5'
const plain = 'ae2d8a571e03ac9c9eb76fac45af8e51'
next I try and recover these from Node's crypto module:
const crypto = require('crypto')
function node_crypto(text) {
const dec = crypto.createDecipheriv(
'aes-256-ctr',
Buffer.from(key, 'hex'),
Buffer.from(ctr, 'hex')
);
const out = dec.update(Buffer.from(text, 'hex'))
return out.toString('hex')
}
now I can write a simple test harness for testing the above and use it with that function:
const zero = '00'.repeat(16);
function test_crypto(fn) {
return {
'zero => output': fn(zero) == output,
'cipher => plain': fn(cipher) == plain,
'plain => cipher': fn(plain) == cipher,
}
}
console.log(test_crypto(node_crypto))
which gives me true for all tests.
finally, the equivalent code for CryptoJS is:
const CryptoJS = require("crypto-js");
function cryptojs(text) {
const out = CryptoJS.AES.encrypt(
CryptoJS.enc.Latin1.parse(Buffer.from(text, 'hex').toString('binary')),
CryptoJS.enc.Hex.parse(key),
{
iv: CryptoJS.enc.Hex.parse(ctr),
mode: CryptoJS.mode.CTR,
padding: CryptoJS.pad.NoPadding,
}
);
return out.ciphertext.toString();
}
console.log(test_crypto(cryptojs))
which also works for me.
It's important to note that CryptoJS just silently accepts arbitrarily sized keys, with the docs saying:
CryptoJS supports AES-128, AES-192, and AES-256. It will pick the variant by the size of the key you pass in. If you use a passphrase, then it will generate a 256-bit key.
In contrast to the NodeJS-code (Crypto), the JavaScript-code (CryptoJS) interprets keys and IV as hexadecimal strings. Therefore, in the JavaScript-Code AES-128 is used and in the NodeJS-Code AES-256. To solve the problem, both codes must use the same encryption.
Option 1: Change the JavaScript-code to AES-256: Replace in the JavaScript-code
var key = CryptoJS.enc.Hex.parse('F18AB33A57F9B229CC9C250D00FC3273');
var iv = CryptoJS.enc.Hex.parse('D959B836CD9FB162');
by
var key = CryptoJS.enc.Utf8.parse('F18AB33A57F9B229CC9C250D00FC3273');
var iv = CryptoJS.enc.Utf8.parse('D959B836CD9FB162');
Option 2: Change the NodeJS-code to AES-128: Replace in the NodeJS-code
var algorithm = 'aes-256-ctr';
var key = 'F18AB33A57F9B229CC9C250D00FC3273';
var iv = 'D959B836CD9FB162';
by
var algorithm = 'aes-128-ctr';
var key = Buffer.from('F18AB33A57F9B229CC9C250D00FC3273', 'hex');
var iv = Buffer.from('D959B836CD9FB1620000000000000000', 'hex');
With one of each of the two changes, the codes of both links produce the same result.
If AES-256 should be used and key and IV should be specified as hexadecimal strings, a correspondingly large key and IV must be used, e.g. on the JavaScript-side:
var key = CryptoJS.enc.Hex.parse('F18AB33A57F9B229CC9C250D00FC3273F18AB33A57F9B229CC9C250D00FC3273');
var iv = CryptoJS.enc.Hex.parse('D959B836CD9FB16200000000000000');
and on the NodeJS-side:
var algorithm = 'aes-256-ctr';
var key = Buffer.from('F18AB33A57F9B229CC9C250D00FC3273F18AB33A57F9B229CC9C250D00FC3273', 'hex');
var iv = Buffer.from('D959B836CD9FB1620000000000000000', 'hex');

python decrypt a text encrypted in jsencrypt

In a web form the answers (packed in a jsonstring) are encrypted in several steps. First a random key is generated. Second the random key is used for AES encryption of the jsonstring. The random key is encrypted as well. Both are send in the body of a mail.
// Generate Random key
var rand_key = ('0000' + Math.random().toString(36).replace('.', '')).substr(-10);
console.log('rand_key', rand_key)
//var pubkey = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALDjeFwFNhMCjMwcRVVKG1VvfsntEVPR3lNTujJnNk1+iSqZ4Tl5Lwq9GbwO+qlYVwXHNmeqG7rkEhL9uyDIZVECAwEAAQ=="
// rsa_key_public07012016.bin
//var pubkey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCv8FVei4Q2ehmYsSCv/uODSojIOGHwfQe686S1cEH5i/1mGME5ZzNqyy0d+lhMRD0tr7Sje7JoCEC/XRIZaiKJjpl1+3RXotf/Cx3bd9H7WtitshZB1m38ZZFsrX4oigMpUPFbCefMeBS4hvvNnmtl08lQGhfIXdXeflZsgWRHtQIDAQAB";
// my_pub_key.pem
var pubkey ="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA38gtENP9/hpirSCIsPh6CAVm0UmME4XBlPyK8yhwk079EUJpNzlEhu9HKcA/B7Fxo2lNoY9Tb9e+PYtJ6+VOB4+Y6zgGMX7cchYmumKRTbbQ6FNfBE5Q8XnOAUlgC7gNrs0e5lW7JH1kWlK+eTT4TANT7F3US09aXmym+fZaRInbXmJujGnDIbRIIbzr5FE82EeMpw2TqRWV466wz5EeFWSSQ8EqV1pSox8B1ywb6cnB/Vofs2qR9Zf2efi9TMcSGm/ij/p9IZcbLeep9qfGsv29lbLNMfwNwQyH0JU27eAM4tPdirceZPxfD6iiILmKzN253BMoAeQCp6us53CnGQIDAQAB"
// Make form_data a JSON string
var jsonstring = JSON.stringify(form_data);
// Create AES encrypted object
var aes_encrypted_json = CryptoJS.AES.encrypt(jsonstring, rand_key);
// Encrypt rand_key
var encrypt = new JSEncrypt();
//console.log('encrypt obj', encrypt);
encrypt.setPublicKey(pubkey);
var encrypted_rand_key = encrypt.encrypt(rand_key);
//var encrypted = encrypt.encrypt(jsonstring);
console.log('encypted', encrypted_rand_key);
var mail_body = encrypted_rand_key + aes_encrypted_json
console.log('body', mail_body)
var mailto_string = "mailto:info#xyz.com?subject=FORM&body=" + encodeURIComponent(mail_body);
$('#mailtosend').attr('href', mailto_string);
At the recipient mail server side I want to decrypt the random generated key and the jsonstring using a private key using the pycryptodome package.
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
from base64 import *
def decrypt(key, text):
if type(key) == str:
key = key.encode()
if type(text) == str:
text = text.encode()
rsakey = RSA.importKey(key)
rsakey = PKCS1_v1_5.new(rsakey)
d = rsakey.decrypt(text, 'bolloux')
return d
# rand_key am2mhiwwmi
text = "ZvcrluUmZLY3lRRw01W9mQnhMn7zzpIWn1Bo3csM/ZZ0pWY/8H2dCB9fZDi9/cmp0UtIqDXhLd7SIwyxqrFgPcHUuEHlZl0WQcjSty8PjadG2Abulk1XqEQV4u0Gb/bFGDBMcf5tV1G0d4FFcBPE8r8inrxUjSj2CSffVL8gIGq3ZfY5g7t5FOZV8npBCEONgOLKYnzIiHrHUuXWsOaMAqxMFOLd5DTDLKAkyMybDClsLW9ka+CvWd5fnZBCvO2ziehFp7b9PG4QPSnQpdC8jNLGZB2h0FI8YQD6IyUwmVluUbAlPMqwd6A2CBdGCbfbMChaA5R7bJgKkYhPOQTjaQ=="
text = b64decode(text.encode())
with open('my_priv_key.pem', 'rb') as f:
key = f.read()
decrypt(key, text)
I run into a encoding problem. "UnicodeDecodeError: 'ascii' codec can't decode byte 0xf7 in position 1: ordinal not in range(128)" The encoding is complicating the issue beyond my capabilities.
My questions:
1. How can I resolve the encoding problem ?
2. How can I make the decryption work ?
Thanks
The issue is more than likely caused by b64decode(text) returning a str that contains values such as \xf7 and then attempting to .encode() those values within your decrypt function. encode will use the default encoding which in this case is ascii. I would personally remove the calls to encode unless you specifically have a reason you are doing so.

Categories

Resources