Problems with AES in crypto-js and pycrypto - javascript

I try to implement a communication between
crypto-js (a javascript crypto library)
and pycrypto (a python crypto library)
On the python server side I encrypt a string with an iv and a passphrase and send the iv with the encrypted text base64 encoded to the javascript client side. Then I want to decrypt the string with the passphrase the user can enter.
python - server
from Crypto.Cipher import AES
from Crypto import Random
iv = Random.get_random_bytes(16)
key = "1234567812345678"
aes = AES.new(key, AES.MODE_CFB, iv)
encrypted_text = base64.b64encode(aes.encrypt("this is a test.."))
iv = base64.b64encode(iv)
# send iv, encrypted_text to client
javascript - client
// <script type="text/javascript"
src="http://crypto-js.googlecode.com/files/2.5.3-crypto-sha1-hmac-pbkdf2-blockmodes-aes.js">
</script>
// text, and iv is base64encoded from the python script
// key is a string from an <input type='text'>
decrypted = Crypto.AES.decrypt(text, key, {iv: iv, mode: new Crypto.mode.CFB});
With this example I get a javascript error
Uncaught URIError: URI malformed
But this is just one example - I tried every constellation of base64 encodings/decodings I could think of. I also tried to changed the Mode. But these are all random tests and I want to understand what I really have to do.
What encoding does the crypt-js want?
Which mode should I chose?
Is there something I should change on the python server side?
what is about padding? Could there be the fault?
any other javascript libraries you can recommend?
thank you very much and kind reagards,
samuirai

Before You encode to base64 You must sum iv and encrypted_text:
encrypted_text = base64.b64encode(iv + aes.encrypt("this is a test.."))
From the official documentation (https://www.dlitz.net/software/pycrypto/doc/) :
As an example, encryption can be done as follows:
from Crypto.Cipher import AES
from Crypto import Random
key = b'Sixteen byte key'
iv = Random.new().read(AES.block_size)
cipher = AES.new(key, AES.MODE_CFB, iv)
msg = iv + cipher.encrypt(b'Attack at dawn')

Related

Not able to login after encrypting the username

I have 2 fields username and password, while registering the user I am encrypting the username with AES and store into database, now I am unable to login because the plain text is not matching with encrypted data.
How can I resolve this problem?
P.s.-
1)I am using Crypto.js library
2)While login I can't again encrypt the username again as it is giving different encrypted data.
What you are trying to achieve is usually done with a hash. A hash function of the username will always return the same hash value.
If there is a specific reason for encrypting the username rather than hashing (which you haven’t explained though), then you will need to decrypt it in order to compare the values or use an encryption mode that is deterministic and does not involve a random initialization vector. See this question and its answers for details.
On your login logic, you should use the same AES encryption to encrypt the user 's input username during their login.
If the username is actually in your database, using that encrypted username should be able to query/locate the username in your database.
Below are for your reference on how the encrypt and decrypt works (copied from HERE):
var CryptoJS = require("crypto-js");
// Encrypt
var ciphertext = CryptoJS.AES.encrypt('my message', 'secret key 123').toString();
// Decrypt
var bytes = CryptoJS.AES.decrypt(ciphertext, 'secret key 123');
var originalText = bytes.toString(CryptoJS.enc.Utf8);
console.log(originalText); // 'my message'

Encrypt in nodeJS and Decrypt in Javascript

I am encrypting text in node JS by using node-RSA and passing it to client(javascript), in which JSEncrypt library is using,but all the time the decrypted message is coming null. Public key and private Key is developing on nodeJS server, encrypting with Public key and decrypting on javascript side with Private Key .
This is not happening right!!!!
Can anyone tell which library i should use in javascript to decrypt the message coming from nodejs(using Node-RSA).OR any other IDEA!!
We are already using HTTPS but our use case is such that we have a broker between it.. and its not trusted broker, and we are forced to use it.. so we would like to use encryption decryption.. Although we have trusted people in our client side, so we are decrypting at client side.
I used CryptoBrowserify to encrypt at javascript (client side)
import CryptoBrowserify from 'crypto-browserify';
public encryptStringWithRsaPublicKey(data: string, publicKey: string): string {
var encrypted = CryptoBrowserify.publicEncrypt( publicKey,new Buffer(data));
return encrypted.toString('Base64');
}
And crypto to dedcrypt at Nodejs
decrypt = function(privateKey, data) {
var crypto = require('crypto');
var buffer = new Buffer(data, 'base64');
var decrypted = crypto.privateDecrypt(privateKey, buffer);
return decrypted.toString('utf8')
};
Nodejs has its builtin cryto library,it is optimized and tested, recommend to use that: https://nodejs.org/api/crypto.html

Decrypt AES 256 CBC javascript

I am a newbie angular front end developer and now I need to access to a Java spring REST api of the other developer team.
In order to get api http://apps.api.com/api/user/login , I need to send that request with Headers : Authorization : Bearer b517241b-e81d-430e-afb6-773527989b47 and Content-Type : application/json.
To get the token b517241b-e81d-430e-afb6-773527989b47 , I have to request to another api http://apps.api.com/api/auth/token, then the result that I get from that api is something like :
{ "token": "eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE0NTQwMzI5MDk2NzYsInN1YiI6InRva2VuIiwidG9rZW4iOiIrbjZEd1NDUGVMbXd0SGpCT2ZzZUhVRlwvS2NOMzBBTDRkXC9sWDlSVlI1UWxnXC9wV2M1VVNNREpCVDVSUnNWNHpadUFtNExWc3BIeDl1SmtESGhvZTI0dWhMcUNzeUFmZklYMTBkalVqVzFnOSt5QTN4eEg4TElQbzBoTDR5V0JhNnplWm9lVFcrZFE0dzd3MVhCazhLZFZwWGFmRmJMZ3RoXC9OdVE5REM1c3QxTllnSDB2aHRWZ0lha3VnZVlhOEFPU1c3eWVsOWFHcXhJN1hHM1FrbVwvYUE9PSIsImlzcyI6Imh0dHBzOlwvXC93d3cud2luZ21vbmV5LmNvbSJ9.uBQYvfTwadTG2QZ76tQN6-ETT1M8X72ltDe7xBCvEhA"
}
What I need to do is, decode that token using jwt then decrypt it using AES 256 CBC (I got stuck here).
I got the code of decryption from back-end developer and the code is in java :
private static final String AES_KEY = "HG47YZ3CR8";
public static String decrypt(String orignalText) throws ApplicationException {
try {
final MessageDigest md = MessageDigest.getInstance("SHA-256");
final byte[] digestOfPassword = md.digest(AES_KEY.getBytes("utf-8"));
final SecretKey key = new SecretKeySpec(digestOfPassword, "AES");
final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(new byte[16]));
final byte[] plainTextBytes = Base64.decodeBase64(orignalText);
final byte[] encodeTextBytes = cipher.doFinal(plainTextBytes);
return new String(encodeTextBytes);
} catch (NoSuchAlgorithmException |
UnsupportedEncodingException |
IllegalBlockSizeException |
InvalidKeyException |
BadPaddingException |
NoSuchPaddingException | InvalidAlgorithmParameterException e) {
throw new ApplicationException(ErrorCode.GENERAL_FAIL, e);
}
}
I've been trying to search for javascript library to write the decryption same as that java code but I could not find the right one.
I appreciate if any one has any idea about which javascript library that is similar to this java code.
I'm not sure I'd really recommend using your front end to decrypt anything since this would require your key to be in the javascript library which would essentially allow EVERYONE to decrypt your token. Which would beg the question why are you encrypting to begin with. But if you really need to do this in javascript you can check out the SO answers here.

Problems when using AES crypto between Node and CryptoJS in browser

I want encrypt a string with Node, and decrypt the string with CryptoJS in browser.
Encrypt:
var crypto = require('crypto');
function encrypt(txt, cryptkey) {
var cipher = crypto.createCipher('aes-256-cbc', cryptkey);
var crypted = cipher.update(txt, 'utf8', 'hex');
crypted += cipher.final('hex');
return crypted;
}
encrypt('1', 'key'); // 83684beb6c8cf063caf45cb7fad04a50
Include:
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/aes.js"></script>
Decrypt:
var decrypted = CryptoJS.AES.decrypt('83684beb6c8cf063caf45cb7fad04a50', 'key');
console.log(decrypted.toString(CryptoJS.enc.Utf8)); // empty string
The actual result is empty string.
What is the right way to decrypt data from node?
CryptoJS supports the same password-based encryption mode that the crypto module in node.js supports which is implemented as the equivalent to EVP_BytesToKey. CryptoJS generates a random salt by default, but node.js doesn't and uses an empty salt. An empty salt is bad and should not be used. Also, it's not secure to derive a key from a password with this method. One needs to use PBKDF2 (supported by CryptoJS and node.js) or similar with a lot of iterations and a random salt.
var ctHex = '83684beb6c8cf063caf45cb7fad04a50';
var ct = CryptoJS.enc.Hex.parse(ctHex);
var salt = CryptoJS.lib.WordArray.create(0); // empty array
var decrypted = CryptoJS.AES.decrypt({ciphertext: ct, salt: salt}, 'key');
document.querySelector("#dec").innerHTML = decrypted.toString(CryptoJS.enc.Utf8);
<script src="https://cdn.rawgit.com/CryptoStore/crypto-js/3.1.2/build/rollups/aes.js"></script>
Expected: "1"<br/>Got: "<span id="dec"></span>"
You said that this will be done over HTTP.
If you want to use transport security without user intervention, then this is completely insecure, because the key needs to be transmitted alongside of the ciphertext which makes this at best obfuscation.
If the user and the server both know the password before communication, then this is still insufficient, because the key derivation that both CryptoJS and node.js provide is insufficient and something like PBKDF2 must be used. MD5 is easily brute-forceable.
You would need to use asymmetric cryptography to protect this communication against a passive attacker (one that cannot inject arbitrary packets into the stream between server and client). I suggest that you generate an RSA key pair and sent the public key to the client so that the client can encrypt a message to the server. You can use forge for that.
Encryption would look like this:
var salt = CryptoJS.lib.WordArray.create(0); // empty array
var params = CryptoJS.kdf.OpenSSL.execute('key', 256/32, 128/32, salt);
var pt = '1';
var encrypted = CryptoJS.AES.encrypt(pt, params.key, {iv: params.iv});
document.querySelector("#enc").innerHTML = encrypted.ciphertext.toString();
<script src="https://cdn.rawgit.com/CryptoStore/crypto-js/3.1.2/build/rollups/aes.js"></script>
Expected: "83684beb6c8cf063caf45cb7fad04a50"<br/>Got: "<span id="enc"></span>"

How to decipher string in node js which is encrypted in crypto js in javascript

My client side code:
data.username = CryptoJS.AES.encrypt(user.username, "password");
data.password = CryptoJS.AES.encrypt(user.password, "password");
Then I am sending 'data' to server which is express.js
var user = req.body;
var decipher = crypto.createDecipher('aes256', "password");
var decrypted = decipher.update(user.username, 'hex', 'utf-8');
decrypted += decipher.final('utf-8');
I am getting this error:
Error: DecipherInit error
at new Decipher (crypto.js:368:17)
at Object.Decipher (crypto.js:365:12)
CryptoJS' encrypt function with a password uses the same EVP_BytesToKey function node.js' createCipher, with the important difference that CryptoJS uses a random salt to derive whereas node does not (emphasis mine):
Note: createCipher derives keys with the OpenSSL function EVP_BytesToKey with the digest algorithm set to MD5, one iteration, and no salt.
Either you directly use CryptoJS in node which is possible, because CryptoJS doesn't have any dependencies, or you do the key derivation yourself on both ends and use crypto.createCipheriv. If you do the former, you would have to additionally pass the salts of the username and password encryptions to node.
Note that data.username is the CryptoJS cipherParams object which contains the salt and the IV, but when you convert this to string with data.username.toString(), the salt is not included anymore, but the IV is. This is not the data that you would put into the node.js functions. Send data.username.ciphertext instead.

Categories

Resources