how to decrypt in SJCL using 256 bit key - javascript

i am new in SJCL crypto library, i am doing the following for encrypting the plain text using 256 bit key in
var h = sjcl.codec.hex ;
salt = h.fromBits(sjcl.random.randomWords('10','0'));
var encryptedMessage = sjcl.encrypt(password,message,{count:2048,salt:salt,ks:256});
but i am unable to decrypt the same cipher , i want to know how to decrypt this cipher .

well after so many hit and try i found this line working for me.
sjcl.decrypt(password,encMessage,{count:2048,ks:256});

Related

CryptoJS AES encryption seems to ignore IV value

I stumbled upon the problem that the IV value that you pass to CryptoJS.AES.encrypt function seems to be ignored. Following code:
import CryptoJS from "crypto-js";
const text = "This is secret text!";
const key = "abc";
const iv = CryptoJS.lib.WordArray.random(2);
const encryptedText = CryptoJS.AES.encrypt(text, key, { iv }).toString();
console.log(encryptedText);
const decryptedText = CryptoJS.AES.decrypt(encryptedText, key, { iv: 'whatever' }).toString(CryptoJS.enc.Utf8);
console.log(decryptedText);
Produces following output:
U2FsdGVkX1//3KxGM2FnVV4qR5KmWBxP/xyI1+YITvdQeXqrUBH7spIvi/Ny+7S2
This is secret text!
So it seems the function is able to decrypt the text no matter what IV value you are passing to the function.
What am I doing wrong here?
You can specify any IV in your code when encrypting and decrypting, because the IV is simply not used. Why is that?
Depending on the type of the key material, CryptoJS uses a key (if a WordArray is passed) or a password (if a string is passed). You pass a string, so the key material is interpreted as password (which is why key should better be called password). In this case, CryptoJS uses a key derivation function (EVP_BytesToKey()) to derive the key and the IV. The explicitly passed IV is completely ignored. This applies to both encryption and decryption. Therefore, if a password is applied, no IV should be used (and the one in the code should be removed).
The derived key and IV can be picked from the CipherParams object returned by CryptoJS.AES.encrypt() (s. here): The key can be read from the property key, the IV from the property iv and the ciphertext from the property ciphertext, s. here.
When you pass a key instead of a password, you must also pass an IV (otherwise an error message is displayed). If you specify a wrong IV during decryption, this will result in a corrupted first block for CBC (the default mode). The details are described in the other answer.
If you want to check this, you should use a Latin1 decoding (or hex encoding) instead of a UTF-8 decoding for the decrypted data, because the corrupted data is generally not Utf-8 compatible (and CryptoJS will display an error message).
Note that short plaintexts with a ciphertext of only one block in size will generally corrupt the padding, which in turn corrupts the data during unpadding, making the data non-displayable. However, it is possible to display the padded data by disabling the default PKCS#7 padding: padding: CryptoJS.pad.NoPadding).
The following code shows encryption/decryption with a password (1), with a key and IV (2) and the corruption of the first block for CBC when decrypting with a wrong IV (3):
var text = "The quick brown fox jumps over the lazy dog";
// (1) Encryption/Decryption using a password (key and IV implicitly derived via EVP_BytesToKey)
var password = "abc"; // This is a password, not a key!
var iv = CryptoJS.lib.WordArray.random(16);
var encryptedOpenSSLB64 = CryptoJS.AES.encrypt(text, password, {iv: iv}).toString(); // iv ignored (since derived via key derivation) and should be removed!
var decrypted = CryptoJS.AES.decrypt(encryptedOpenSSLB64, password, {iv: iv}); // iv ignored (since derived via key derivation) and should be removed!
console.log(encryptedOpenSSLB64);
console.log(decrypted.toString(CryptoJS.enc.Utf8));
// (2) Encryption/Decryption using a key and an IV
var key = CryptoJS.lib.WordArray.random(32);
var iv = CryptoJS.lib.WordArray.random(16);
var ciphertextB64 = CryptoJS.AES.encrypt(text, key, {iv : iv}).toString(); // iv required!
var decrypted = CryptoJS.AES.decrypt(ciphertextB64, key, {iv : iv}); // iv required!
console.log(ciphertextB64);
console.log(decrypted.toString(CryptoJS.enc.Utf8));
// (3) Corruption of the first block for CBC, if a wrong IV is applied during decryption
var wrongIv = CryptoJS.lib.WordArray.random(16);
var decrypted = CryptoJS.AES.decrypt(ciphertextB64, key, {iv : wrongIv}); // wrong IV corrupts first block for CBC
console.log(decrypted.toString(CryptoJS.enc.Latin1));
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
For completeness: In your code the CipherParams object is converted to the Base64 encoded OpenSSL format with toString(). The OpenSSL format consists of the ASCII encoding of Salted__ followed by an 8 bytes salt and the actual ciphertext. Because of the constant prefix Salted__ the Base64 encoded data always starts with U2FsdGVkX1 (like your ciphertext).
The random salt is generated during encryption. Based on salt and password, the key derivation function is used to derive key and IV. In order to be able to reconstruct key and IV during decryption, the salt is required. The salt is not secret, so it is usually concatenated with the ciphertext (as in the OpenSSL format described above). The salt is also contained in the salt property of the CipherParams object.
If no password but a key is applied, there is no salt and toString() returns only the Base64 encoding of the ciphertext property. This is also illustrated in the above code snippet.
CryptoJS.AES.decrypt() requires a CipherParams object (s. here). Alternatively (as in your code) the Base64 encoding created with toString() can be passed. This is implicitly converted into a CipherParams object.
CryptoJS is using AES-CBC. CBC is not an authenticated mode of operation, so it doesn't offer message integrity / authenticity. CBC only offers confidentiality, and only that while it is used correctly and doesn't allow for, for instance, padding oracle attacks.
Actually, the IV in CBC mode only changes the first block of plaintext during decryption, and only those bytes where the IV differs. So all the rest of the blocks simply decrypt as you'd expect. This is because the IV is only the initialization vector. The other "vectors" that are XOR'ed with the plaintext before AES block encryption are the previous blocks of ciphertext. Probably best to have a look at the Wikipedia page explaining the modes of operation.
Beware that the line:
const encryptedText = CryptoJS.AES.encrypt(text, key, { iv }).toString();
is not correct: iv should be a named field:
const encryptedText = CryptoJS.AES.encrypt(text, key, { iv: iv }).toString();
It's not entirely clear if this is deliberate or not from the rest of the context in the question.

Equivalent MD5 from CryptoJS and Python Hashlib

I try to bring some code from JS to Python.
I'm stuck with that code in JS :
const crypto = require('crypto')
var txtToHash = "Hello¤World¤";
var md5sum = crypto.createHash('md5');
md5sum.update(new Buffer(txtToHash, 'binary'));
md5val = md5sum.digest('hex');
// equivalent to
// crypto.createHash('md5').update(urlPart, 'binary').digest('hex'));
Returns :
3a091f847ee21c7c1927c19e0f29a28b
And, in Python 3.7 I have this code :
import hashlib
txtToHash = "Hello¤World¤"
md5val = hashlib.md5(txtToHash.encode()).hexdigest()
Returns : f0aef2e2e25ddf71473aa148b191dd70
Why are they different please ? I can't find an answer on Google or SO.
you are using two different character encodings during digest creation.
Make sure that you have the same type of character encoding. your node js implementation is using 'binary' alias 'latin1' encoding. Where as the code in python uses UTf8 character encoding.
When you specified txtToHash.encode() , this means that encode the text to utf-8.
So modify your digest creation to match the character encoding the same on both the environments.
either modify your nodejs code
md5sum.update(new Buffer(txtToHash, 'utf8'));
or modify your python code to
md5val = hashlib.md5(txtToHash.encode('latin1')).hexdigest()
the above should give the same result >> 3a091f847ee21c7c1927c19e0f29a28b
Note:
Although the python code gives the desired result. I wouldn't suggest this because latin1 encoding has only a small subset of characters compared to utf8. So I recommend that you change the encoding to utf-8 in your node js app and apply the same encoding in python too

Proper way to decrypt CryptoJS DES encoded string using Java?

In JavaScript side I use:
CryptoJS.DES.encrypt('Content', 'password').toString()
The result:
U2FsdGVkX1/25rW2q0X7/pOtExFyP7MD
In Java side I try to decrypt it:
public static void main(String[] args) throws Exception {
String password = "password";
String encryptedString = "U2FsdGVkX1/25rW2q0X7/pOtExFyP7MD";
DESKeySpec key = new DESKeySpec(password.getBytes());
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
SecureRandom secureRandom = new SecureRandom();
byte[] ivspec = new byte[cipher.getBlockSize()];
secureRandom.nextBytes(ivspec);
IvParameterSpec iv = new IvParameterSpec(ivspec);
cipher.init(Cipher.DECRYPT_MODE, keyFactory.generateSecret(key), iv);
byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedString.getBytes()));
System.out.println(new String(Base64.getEncoder().encode(decryptedBytes)));
}
But I'm getting the bad padding error:
Exception in thread "main" javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
Can anyone tell me what went wrong and what is the proper way to decrypt it? Assuming that the JavaScript side code cannot be changed (i.e the way to encrypt the string using DES). Thank you very much.
The IV must be the same for both encryption and decryption. in the example a new random IV is being created for decryption: secureRandom.nextBytes(ivspec);.
You need to carefully and fully review the CryptoJS documentation to determine how the IV is being handled. Often the IV is prepended to the encrypted data for use during decryption.
The encryptedString seems to be Base64 encoded and the decoded length is 32-bytes, just right for a 16-byte IV and 16-byte encrypted data+padding.

Decrypt message with encrypted salt string and secret passphrase using CryptoJS

I want decode an encrypted string using cryptoJS. I get how to decode the encrypted object but couldnt understand how to decrypt the string.
Heres what I tried:
var enc = CryptoJS.AES.encrypt('hellloooo', 'secretpassphrase');
console.log('encrypted', enc.salt.toString());
console.log('decrypted', CryptoJS.AES.decrypt(CryptoJS.enc.salt.parse(enc.salt.toString()), 'secretpassphrase').toString(CryptoJS.enc.Utf8));
The salt is some random value that is randomly generated during encryption in order to derive the actual key and IV from the given password. It doesn't hold the secret, so trying to decrypt it won't give you anything useful.
Here are two ways to decrypt the ciphertext
CryptoJS.AES.decrypt(enc, 'secretpassphrase').toString(CryptoJS.enc.Utf8);
CryptoJS.AES.decrypt(enc.toString(), 'secretpassphrase').toString(CryptoJS.enc.Utf8);
The salt is still present in the enc object, so the decrypt() function can use it to recreate the key and IV to decrypt the string.

AES encryption with pycrypto

I have a code snippet on javascript that I'm trying to convert to python
var cipherAlgorithm = 'aes256';
var decipher = crypto.createDecipher(cipherAlgorithm, cipher);
password = decipher.update(encryptedpass, 'hex', 'utf8')+ decipher.final('utf8');
I'm trying to rewrite that in python using pythoncrypto and I'm just getting the wrong values no matter what I do
cyphertext=faaafaaa"
cipher=AES.new(key, AES.MODE_CBC, "\0"*16)
cipher.decrypt(cypertext)
and it returns the wrong value. (didn't decrypt correctly)
in the javascript code (I'm not a js expert ) I noticed that the output encoding is utf8
so I tries something like this
unicode(cipher.decrypt(cyphertext), "utf-8")
but I'm getting an error
'utf8' codec can't decode byte 0x81 in position 6: invalid start byte
what's the solution?

Categories