ScryptSync Key Cannot Be Used in createCipheriv, Nodejs, Crypto lib - javascript

I am new to topics related to encoding and I am having troubles with being able to convert my scryptsync key into something createCipheriv (Crypto library integrated into Nodejs) can use in the iv parameter.
const algorithm = 'aes-256-gcm';
var text = 'default'
var encrypted = secret;
class Auth
{
SignUp(pass)
{
console.log(pass);
var pair = ec.genKeyPair();
text = pair.getPrivate.toString('hex');
var key = crypto.scryptSync(pass, 'baethrowssalt', 32);
console.log(`The key is:${key}`); //this is not a string
key=key.toString('hex');
var cipher = crypto.createCipheriv(algorithm, key);
var encrypted = cipher.update(text, 'hex', 'hex') + cipher.final('hex');
fs.writeFileSync(file, encrypted);
return alert(`Close and reopen your app to integrate your wallet securely`);
}
as you can see above, I tried converting the scryptSync return to string hex so that createCipheriv is willing to use it, but I get the following error:
pass is passrig
passrig
The key is:�→A�r;yR�����▲�h�8��f�����v�A�,
TypeError [ERR_INVALID_ARG_TYPE]: The "iv" argument must be of type string or an instance of Buffer, TypedArray, or DataView. Received undefined
at Cipheriv.createCipherWithIV (internal/crypto/cipher.js:120:29)
at new Cipheriv (internal/crypto/cipher.js:227:22)
at Object.createCipheriv (crypto.js:117:10)
So my question contains two parts: how can I use scryptSync with the createCipheriv? To help me understand, what are the reasons behind your solutions?

I've created an example that encrypts some data using the algorithm aes-256-gcm and uses crypto.scryptSync to derive the key from a password.
The steps are as follows:
Derive our key from our password using crypto.scryptSync.
Create an IV using crypto.randomBytes.
Use our key and iv to encrypt the plaintext using our encrypt function.
Test our encrypted data by decrypting using our decrypt function.
This code is as follows:
const crypto = require("crypto");
const Algorithm = "aes-256-gcm";
function encrypt(plainText, key, iv) {
const cipher = crypto.createCipheriv(Algorithm, key, iv);
return { encrypted: Buffer.concat([cipher.update(plainText), cipher.final()]), authTag: cipher.getAuthTag() }
}
function decrypt(encrypted, key, iv, authTag) {
const decipher = crypto.createDecipheriv(Algorithm, key, iv).setAuthTag(authTag);
return Buffer.concat([decipher.update(encrypted), decipher.final()]);
}
const password = "Speak Friend and Enter";
const plainText = "There is nothing either good or bad but thinking makes it so.";
const salt = crypto.randomBytes(32);
// Create an encryption key from our password, ensuring it is 32 bytes long - AES-256 needs a 256 bit (32 byte) key
const KEY = crypto.scryptSync(password, salt, 32);
const IV = crypto.randomBytes(16);
console.log("Key (derived from password, hex):", KEY.toString("hex"));
console.log("IV (hex):", IV.toString("hex"));
console.log("Plaintext:", plainText);
const { encrypted, authTag } = encrypt(plainText, KEY, IV);
console.log("Encrypted (hex):", encrypted.toString("hex"));
const decrypted = decrypt(encrypted, KEY, IV, authTag)
console.log("Decrypted:", decrypted.toString("utf-8"));

Related

CryptoJs decrypt function equivalent in Java

I'm trying to decrypt a token that the server I'm using brings in order to load correctly users access to the page.
I already achieved the goal using CryptoJs using JavaScript. However now I need to transfer that function to my java backend.
Look my code using CryptoJs which works correctly
const token = "U2FsdGVkX1+6YueVRKp6h0dZfk/a8AC9vyFfAjxD4nb7mXsKrM7rI7xZ0OgrF1sShHYNLMJglz4+67n/I7P+fg=="
const key = "p80a0811-47db-2c39-bcdd-4t3g5h2d5d1a"
// Decrypt
const iv = CryptoJS.enc.Utf8.parse(key);
const decryptedToken = CryptoJS.AES.decrypt(token, key, {
keySize: 16,
iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
});
const stringToken = decryptedToken.toString(CryptoJS.enc.Utf8);
const dataToUse = JSON.parse(stringToken)
console.log("decryptedToken => ", stringToken);
console.log("data => ",dataToUse);
And this is my code in Java using javax.crypto
public String decrypt() {
String finalToken = null;
Cipher cipher;
try {
String token = "U2FsdGVkX1+6YueVRKp6h0dZfk/a8AC9vyFfAjxD4nb7mXsKrM7rI7xZ0OgrF1sShHYNLMJglz4+67n/I7P+fg==";
String key = "p80a0811-47db-2c39-bcdd-4t3g5h2d5d1a";
Key skeySpec = new SecretKeySpec(Arrays.copyOf(key.getBytes(), 16), "AES");
byte[] iv = Arrays.copyOf(key.getBytes(StandardCharsets.UTF_8), 16);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
byte[] bytesToDecrypt = Base64.decodeBase64(token.getBytes());
cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivParameterSpec);
byte[] decrypted = cipher.doFinal(bytesToDecrypt);
finalToken = new String(decrypted);
log.info("Decrypt token succesfully {}", finalToken);
} catch (NoSuchAlgorithmException
| InvalidAlgorithmParameterException
| IllegalBlockSizeException
| NoSuchPaddingException
| BadPaddingException
| InvalidKeyException e) {
e.printStackTrace();
log.error("Error decrypting");
}
return finalToken;
}
I'm not sure I'm setting correctly the key and the iv. With the piece of code above I get this error:
javax.crypto.BadPaddingException: pad block corrupted
If I don't "cut" the key and the iv in order to have 16 bytes I get wrong length error.
Can someone help me to figure out what's wrong please!
The expected result is to get this info in java so then I can manipulate the object:
{name: "Burak", surName: "Bayraktaroglu"}
Decryption fails because CryptoJS interprets the key material as password when passed as string (as in the posted code).
In this case, the password and a salt are used to derive the key and IV applying the OpenSSL proprietary key derivation function EVP_BytesToKey().
The random 8 bytes salt is generated during encryption, which returns as result the Base64 encoding of the concatenation of a prefix, the salt and the actual ciphertext. The prefix consists of the ASCII encoding of Salted__.
Therefore, the following steps are necessary in the decryption process:
Determining salt and ciphertext from the CryptoJS return value
Deriving key and IV using password and salt
Decryption of the ciphertext with the derived key and IV
There are several ways to implement the last two steps in Java.
You can find various ports of EVP_BytesToKey() on the web which can be used in conjunction with the native JCA/JCE for decryption. These EVP_BytesToKey() ports are not always reliable, a solid port is this one.
A convenient (and reliable) alternative is BouncyCastle (with its own EVP_BytesToKey() port), described below:
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import org.bouncycastle.crypto.digests.MD5Digest;
import org.bouncycastle.crypto.engines.AESEngine;
import org.bouncycastle.crypto.generators.OpenSSLPBEParametersGenerator;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.bouncycastle.crypto.params.ParametersWithIV;
...
// Get salt and ciphertext
String saltCiphertextB64 = "U2FsdGVkX1+6YueVRKp6h0dZfk/a8AC9vyFfAjxD4nb7mXsKrM7rI7xZ0OgrF1sShHYNLMJglz4+67n/I7P+fg==";
byte[] saltCiphertext = Base64.getDecoder().decode(saltCiphertextB64);
ByteBuffer byteBuffer = ByteBuffer.wrap(saltCiphertext);
byte[] prefix = new byte[8];
byte[] salt = new byte[8];
byteBuffer.get(prefix);
byteBuffer.get(salt);
byte[] ciphertext = new byte[byteBuffer.remaining()];
byteBuffer.get(ciphertext);
// Key derivation via EVP_BytesToKey() (using BouncyCastle)
String passwordStr = "p80a0811-47db-2c39-bcdd-4t3g5h2d5d1a";
byte[] password = passwordStr.getBytes(StandardCharsets.UTF_8);
OpenSSLPBEParametersGenerator pbeGenerator = new OpenSSLPBEParametersGenerator(new MD5Digest());
pbeGenerator.init(password, salt);
ParametersWithIV parameters = (ParametersWithIV) pbeGenerator.generateDerivedParameters(256, 128); // keySize, ivSize in bits
// FYI: key: ((KeyParameter)parameters.getParameters()).getKey()
// IV : parameters.getIV()
// Decryption (using BouncyCastle)
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESEngine()));
cipher.init(false, parameters);
byte[] plaintext = new byte[cipher.getOutputSize(ciphertext.length)];
int length = cipher.processBytes(ciphertext, 0, ciphertext.length, plaintext, 0);
length += cipher.doFinal(plaintext, length);
String plaintextSr = new String(plaintext, 0, length, StandardCharsets.UTF_8);
System.out.println(plaintextSr); // {"name":"Burak","surName":"Bayraktaroglu"}

how to properly decrypt text via Subtle Crypto which was encrypted via CryptoJS

I have code that encrypts user's data using CryptoJS.AES, stores key, iv and encrypted content in different places.
Also it decrypts encrypted content using stored key and iv by user demand.
I want to use Subtle Crypto browser API for encryption,which is done.
But I also want to have possibility to decrypt old data (that was ecnrypted using CryptoJS.AES) using Subtle Crypto.
old data was generated with following code
var CryptoJS = require("crypto-js/core");
CryptoJS.AES = require("crypto-js/aes");
let encKey = generateRandomString();
let aesEncrypted = CryptoJS.AES.encrypt(content, encKey);
let encrypted = {
key: aesEncrypted.key.toString(),
iv: aesEncrypted.iv.toString(),
content: aesEncrypted.toString()
};
and I've tried to decrypt it as following
let keyArrayBuffer = hexArrayToArrayBuffer(sliceArray(encrypted.key, 2));
let decKey = await importKey(keyArrayBuffer);
let decIv = hexArrayToArrayBuffer(sliceArray(encrypted.iv, 2));
let encContent = stringToArrayBuffer(encrypted.content);
let decryptedByteArray = await crypto.subtle.decrypt(
{ name: "AES-CBC", iv: decIv },
decKey,
encContent
);
let decrypted = new TextDecoder().decode(decrypted);
I receive DOMException error without backtrace on await crypto.subtle.decrypt
complete reproduction can be found at https://codesandbox.io/s/crypto-js-to-subtle-crypto-u0pgs?file=/src/index.js
In the CryptoJS code the key is passed as string. Therefore it is interpreted as a password, from which in combination with a randomly generated 8 bytes salt, a 32 bytes key and a 16 bytes IV are derived, see here. The proprietary (and relatively insecure) OpenSSL key derivation function EVP_BytesToKey is used for this.
CryptoJS.AES.encrypt() returns a CipherParams object that encapsulates various parameters, such as the generated key and IV as WordArray, see here. toString() applied to the key or IV WordArray, returns the data hex encoded. toString() applied to the CipherParams object, returns the ciphertext in OpenSSL format, i.e. the first block (= the first 16 bytes) consists of the ASCII encoding of Salted__, followed by the 8 bytes salt and the actual ciphertext, all together Base64 encoded, see here. This means that the actual ciphertext starts (after Base64 decoding) with the second block.
The following code illustrates how the ciphertext generated with CryptoJS can be decrypted with the WebCrypto API
//
// CryptoJS
//
const content = "The quick brown fox jumps over the lazy dog";
const encKey = "This is my passphrase";
const aesEncrypted = CryptoJS.AES.encrypt(content, encKey);
const encrypted = {
key: aesEncrypted.key.toString(),
iv: aesEncrypted.iv.toString(),
content: aesEncrypted.toString()
};
//
// WebCrypto API
//
// https://stackoverflow.com/a/50868276
const fromHex = hexString => new Uint8Array(hexString.match(/.{1,2}/g).map(byte => parseInt(byte, 16)));
// https://stackoverflow.com/a/41106346
const fromBase64 = base64String => Uint8Array.from(atob(base64String), c => c.charCodeAt(0));
async function decryptDemo(){
const rawKey = fromHex(encrypted.key);
const iv = fromHex(encrypted.iv);
const ciphertext = fromBase64(encrypted.content).slice(16);
const key = await window.crypto.subtle.importKey(
"raw",
rawKey,
"AES-CBC",
true,
["encrypt", "decrypt"]
);
const decrypted = await window.crypto.subtle.decrypt(
{
name: "AES-CBC",
iv: iv
},
key,
ciphertext
);
const decoder = new TextDecoder();
const plaintext = decoder.decode(decrypted);
console.log(plaintext);
}
decryptDemo();
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>

How to implement this encryption related code in JavaScript?

I have following code in Java.
String secretString = 'AAABBBCCC'
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom securerandom = SecureRandom.getInstance("SHA1PRNG");
securerandom.setSeed(secretString.getBytes());
kgen.init(256, securerandom);
SecretKey secretKey = kgen.generateKey();
byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
Security.addProvider(new BouncyCastleProvider());
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] byteContent = content.getBytes("utf-8");
byte[] cryptograph = cipher.doFinal(byteContent);
String enc1 = Base64.getEncoder().encodeToString(cryptograph);
return enc1;
I need to implement it in JavaScript/Node.js, however I can only figure out the last half in js like below
'use strict';
const crypto = require('crypto');
const ALGORITHM = 'AES-256-ECB';
const secretString = 'AAABBBCCC'
// missing part in JS (how to convert secretString to key)
function encrypt(plaintext, key) {
const cipher = crypto.createCipheriv(ALGORITHM, key, Buffer.alloc(0));
return cipher.update(plaintext, 'utf8', 'base64') + cipher.final('base64');
}
For the previous Java part( from secretString to key generated by KeyGenerator), I don't know how to implement it in JavaScript, neither do I know whether there is a thing like KeyGenerator in JavaScript world could help me to do the heavy lifting work.
I think this is what you're after:
const crypto = require("crypto-js");
// Encrypt
const ciphertext = crypto.AES.encrypt('SOMETHING SECRET', 'secret key 123');
// Decrypt
const bytes = crypto.AES.decrypt(ciphertext.toString(), 'secret key 123');
const decryptedData = bytes.toString(crypto.enc.Utf8);
console.log(decryptedData);
https://runkit.com/mswilson4040/5b74f914d4998d0012cccdc0
UPDATE
JavaScript does not have a native equivalent for key generation. The answer is to create your own or use a third party module. I would recommend something like uuid for starters.
You can use crypto.randomBytes().
As per its documentation:
Generates cryptographically strong pseudo-random data. The size argument is a number indicating the number of bytes to generate.
Also, it uses openssl's RAND_bytes API behind scenes

How to generate crypto.createCipheriv arguments from static source

I am using the below code to encrypt strings in my node.js code.
I would like to understand how to generate KEY and HMAC_KEY from a static source. In my program, it's generated randomly as of now. As it's generated randomly, I am not able to encrypt my database password using the below algorithm.
crypto = require('crypto');
ALGORITHM = "AES-256-CBC";
HMAC_ALGORITHM = "SHA256";
KEY = crypto.randomBytes(32);
HMAC_KEY = crypto.randomBytes(32);
function (plain_text) {
var IV = new Buffer(crypto.randomBytes(16)); // ensure that the IV (initialization vector) is random
var cipher_text;
var hmac;
var encryptor;
encryptor = crypto.createCipheriv(ALGORITHM, KEY, IV);
encryptor.setEncoding('hex');
encryptor.write(plain_text);
encryptor.end();
cipher_text = encryptor.read();
hmac = crypto.createHmac(HMAC_ALGORITHM, HMAC_KEY);
hmac.update(cipher_text);
hmac.update(IV.toString('hex')); // ensure that both the IV and the cipher-text is protected by the HMAC
// The IV isn't a secret so it can be stored along side everything else
return cipher_text + "$" + IV.toString('hex') + "$" + hmac.digest('hex')
};
You have to split your code into two executions:
Code that generates your keys and presents them in a storable format
KEY = crypto.randomBytes(32);
HMAC_KEY = crypto.randomBytes(32);
console.log(KEY.toString('hex'));
console.log(HMAC_KEY.toString('hex'));
Code that uses the stored keys
KEY = Buffer.from('some key string', 'hex');
HMAC_KEY = Buffer.from('some other key string', 'hex');
You just have to make sure that your keys aren't actually in your code, but rather in some file, because hardcoding key in code and checking them into your version control system is a bad idea and might give your developers access to production systems which they probably shouldn't have.

CryptoJS and Pycrypto working together

I'm encrypting a string in a web application using CryptoJS (v 2.3), and I need to decrypt it on the server in Python, so I'm using PyCrypto. I feel like I'm missing something because I can't can it working.
Here's the JS:
Crypto.AES.encrypt('1234567890123456', '1234567890123456',
{mode: new Crypto.mode.CBC(Crypto.pad.ZeroPadding)})
// output: "wRbCMWcWbDTmgXKCjQ3Pd//aRasZ4mQr57DgTfIvRYE="
The python:
from Crypto.Cipher import AES
import base64
decryptor = AES.new('1234567890123456', AES.MODE_CBC)
decryptor.decrypt(base64.b64decode("wRbCMWcWbDTmgXKCjQ3Pd//aRasZ4mQr57DgTfIvRYE="))
# output: '\xd0\xc2\x1ew\xbb\xf1\xf2\x9a\xb9\xb6\xdc\x15l\xe7\xf3\xfa\xed\xe4\xf5j\x826\xde(m\xdf\xdc_\x9e\xd3\xb1'
Here is a version with CryptoJS 3.1.2. Always beware of the following things (use the same in both languages):
Mode of operation (CBC in this case)
Padding (Zero Padding in this case; better use PKCS#7 padding)
Key (the same derivation function or clear key)
Encoding (same encoding for key, plaintext, ciphertext, ...)
IV (generated during encryption, passed for decryption)
If a string is passed as the key argument to the CryptoJS encrypt() function, the string is used to derive the actual key to be used for encryption. If you wish to use a key (valid sizes are 16, 24 and 32 byte), then you need to pass it as a WordArray.
The result of the CryptoJS encryption is an OpenSSL formatted ciphertext string. To get the actual ciphertext from it, you need to access the ciphertext property on it.
The IV must be random for each encryption so that it is semantically secure. That way attackers cannot say whether the same plaintext that was encrypted multiple times is actually the same plaintext when only looking at the ciphertext.
Below is an example that I have made.
JavaScript:
var key = CryptoJS.enc.Utf8.parse('1234567890123456'); // TODO change to something with more entropy
function encrypt(msgString, key) {
// msgString is expected to be Utf8 encoded
var iv = CryptoJS.lib.WordArray.random(16);
var encrypted = CryptoJS.AES.encrypt(msgString, key, {
iv: iv
});
return iv.concat(encrypted.ciphertext).toString(CryptoJS.enc.Base64);
}
function decrypt(ciphertextStr, key) {
var ciphertext = CryptoJS.enc.Base64.parse(ciphertextStr);
// split IV and ciphertext
var iv = ciphertext.clone();
iv.sigBytes = 16;
iv.clamp();
ciphertext.words.splice(0, 4); // delete 4 words = 16 bytes
ciphertext.sigBytes -= 16;
// decryption
var decrypted = CryptoJS.AES.decrypt({ciphertext: ciphertext}, key, {
iv: iv
});
return decrypted.toString(CryptoJS.enc.Utf8);
}
Python 2 code with pycrypto:
BLOCK_SIZE = 16
key = b"1234567890123456" # TODO change to something with more entropy
def pad(data):
length = BLOCK_SIZE - (len(data) % BLOCK_SIZE)
return data + chr(length)*length
def unpad(data):
return data[:-ord(data[-1])]
def encrypt(message, key):
IV = Random.new().read(BLOCK_SIZE)
aes = AES.new(key, AES.MODE_CBC, IV)
return base64.b64encode(IV + aes.encrypt(pad(message)))
def decrypt(encrypted, key):
encrypted = base64.b64decode(encrypted)
IV = encrypted[:BLOCK_SIZE]
aes = AES.new(key, AES.MODE_CBC, IV)
return unpad(aes.decrypt(encrypted[BLOCK_SIZE:]))
Warning: Keep in mind that both python2 and pycrypto are obsolete, so the code has to be adjusted to fit python3 and pycryptodome.
Other considerations:
It seems that you want to use a passphrase as a key. Passphrases are usually human readable, but keys are not. You can derive a key from a passphrase with functions such as PBKDF2, bcrypt or scrypt.
The code above is not fully secure, because it lacks authentication. Unauthenticated ciphertexts may lead to viable attacks and unnoticed data manipulation. Usually the an encrypt-then-MAC scheme is employed with a good MAC function such as HMAC-SHA256.
I had to port a Javascript implementation of AES encryption/decryption which was using crypto-js library, to Python3.
Basically, my approach was to run the debugger on the existing JS code and look at variables getting filled in each step. I was able to figure out the equivalent methods to do the same in python as well.
Here is how I ported it using pycryptodome library which has some useful features.
AES.js
var CryptoJS = require("crypto-js");
var Base64 = require("js-base64");
function decrypt(str, secret) {
try {
var _strkey = Base64.decode(secret);
var reb64 = CryptoJS.enc.Hex.parse(str);
var text = reb64.toString(CryptoJS.enc.Base64);
var Key = CryptoJS.enc.Base64.parse(_strkey.split(",")[1]); //secret key
var IV = CryptoJS.enc.Base64.parse(_strkey.split(",")[0]); //16 digit
var decryptedText = CryptoJS.AES.decrypt(text, Key, { keySize: 128 / 8, iv: IV, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 });
return decryptedText.toString(CryptoJS.enc.Utf8); //binascii.unhexlify(decryptedText)
} catch (e) {
console.log("Error", e)
}
}
function encrypt(str, secret) {
str = Math.random().toString(36).substring(2, 10) + str;
var _strkey = Base64.decode(secret);
_strkey.split(",");
var text = CryptoJS.enc.Utf8.parse(str);
var Key = CryptoJS.enc.Base64.parse(_strkey.split(",")[1]); //secret key
var IV = CryptoJS.enc.Base64.parse(_strkey.split(",")[0]); //16 digit
var encryptedText = CryptoJS.AES.encrypt(text, Key, { keySize: 128 / 8, iv: IV, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 });
var b64 = encryptedText.toString();
var e64 = CryptoJS.enc.Base64.parse(b64);
var eHex = e64.toLocaleString(CryptoJS.enc.Hex);
return eHex.toUpperCase();
}
const secret = "V1VWTVRFOVhJRk5WUWsxQlVrbE9SUT09LFRrOUNUMFJaSUZkSlRFd2dTMDVQVnc9PQ=="
const data = "THIS IS MY SECRET MESSAGE!"
encData = EncryptText2(data, secret)
decData = DecryptText2(encData, secret)
console.log("encryptedData", encData)
console.log("decryptedData", decData)
AESify.py
import string
import random
import base64
import binascii
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
class AESify:
def __init__(self, key=None, iv=None,secret = None, block_len=16, salt_len= 8):
self.key = key
self.iv = iv
self.salt_len = salt_len
self.block_len = block_len
self.mode = AES.MODE_CBC
if(secret):
self.useSecret(secret)
if(self.key is None and self.iv is None):
raise Exception("No key , IV pair or secret provided")
#staticmethod
def makeSecret(key, iv):
if(len(key) % 8 != 0):
raise Exception("Key length must be a mutliple of 8")
if(len(iv) % 8 != 0):
raise Exception("Initial vector must be a multiple of 8")
key64 = base64.b64encode(key.encode()).decode()
iv64 = base64.b64encode(iv.encode()).decode()
secret = iv64 + "," + key64
secret64 = base64.b64encode(secret.encode()).decode()
return secret64
def useSecret(self, secret):
iv64, key64 = base64.b64decode(secret).decode().split(",") # decode and convert to string
self.iv = base64.b64decode(iv64)
self.key = base64.b64decode(key64)
return self
def encrypt(self, text):
text = self.add_salt(text, self.salt_len)
cipher = AES.new(self.key, self.mode, self.iv)
text = cipher.encrypt(pad(text.encode('utf-8'), self.block_len))
return binascii.hexlify(text).decode()
def decrypt(self, data):
text = binascii.unhexlify(data) # UNHEX and convert the encrypted data to text
cipher = AES.new(self.key, self.mode, self.iv)
return unpad(cipher.decrypt(text), self.block_len).decode('utf-8')[self.salt_len:]
def add_salt(self, text, salt_len):
# pre-pad with random salt
salt = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(salt_len))
text = salt + text
return text
main.py
from AESify import AESify
key , iv = "NOBODY WILL KNOW", "YELLOW SUBMARINE"
# contains IV and key
secret = AESify.makeSecret(key, iv)
aes = AESify(secret= secret, block_len=16, salt_len=4)
msg = "THIS IS MY SECRET MESSAGE"
encrypted = aes.encrypt(msg)
decrypted = aes.decrypt(encrypted)
print(f"{secret=}")
print(f"{encrypted=}")
print(f"{decrypted=}")
Note : salt , iv , padding should be same in js and python
generate salt and iv value and convert it into a byte string uisng CryptoJS.enc.Utf8.parse()
js file
var encrypted = CryptoJS.AES.encrypt(JSON.stringify(json_data), CryptoJS.enc.Utf8.parse(data['salt']) , { iv: CryptoJS.enc.Utf8.parse(data['iv']) , mode: CryptoJS.mode.CBC , padding: CryptoJS.pad.Pkcs7});
en_data = encrypted.ciphertext.toString(CryptoJS.enc.Base64)
send this encrypted data to the python file
python file
from Crypto.Util.Padding import pad, unpad
ct = request.POST['encrypted_data']
data = base64.b64decode(ct)
cipher1 = AES.new(salt, AES.MODE_CBC, iv)
pt = unpad(cipher2.decrypt(data), 16)
data = json.loads(pt.decode('utf-8'))
pad and upad in pycrypto by default uses pkcs#7
salt and iv value should in byte string

Categories