Encrypt in nodeJS and Decrypt in Javascript - 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

Related

Node HmacSHA1 Seed

I'm trying to send a SOAP request via Node, talking to a service which is secured with WSS.
I need to sign the XML response with a SignedInfo element which requires me combining a Nonce Binary secret I generated, with a Nonce binary secret returned from the initial token request - PSHA1 format.
I've been able to validate this using Java, by utilising the following class (Where the secret is my client nonce and the seed is the server nonce):
https://github.com/apache/wss4j/blob/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/derivedKey/P_SHA1.java#L57
With the following Java code:
Mac mac = Mac.getInstance("HmacSHA1");
SecretKeySpec key = new SecretKeySpec(getSharedKey(), "HmacSHA1");
mac.init(key);
String bytesToSign = "<XML_TO_SIGN_GOES_HERE>";
String signature = Base64.encodeBytes(mac.doFinal(bytesToSign.getBytes()));
I need to do this in a Node project though, I've looked at the Crypto API and numerous plugins but I'm unable to generate the same signature.
How do I specify a seed for a HmacSHA1 using node?
I managed to get there in the end, there's an NPM module called psha1 (https://www.npmjs.com/package/psha1).
Using that library I created the following a generateSignature module which looks as follows:
const crypto = require('crypto');
const psha1 = require('psha1');
export const generateSignatureValue = ({
clientSecret,
serverSecret,
messageToSign,
}) => {
const secretKey =
psha1(clientSecret, serverSecret, 256);
const hash =
crypto
.createHmac('sha1', Buffer.from(secretKey, 'base64'))
.update(messageToSign)
.digest('binary');
return Buffer
.from(hash, 'binary')
.toString('base64');
};
export default generateSignatureValue;
This gives me the desired output :)

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 can I get a certificate to verify my RSA digital signature using jsrsasign?

I am using jsrsasign and I have an RSA public and private key that I generated earlier. I used the following code to generate a signature.
var key = new RSAKey();
key.readPrivateKeyFromPEMString($("#private")[0].value); // "private" is a textarea containing the PEM encoded private key.
var sig = new KJUR.crypto.Signature({"alg": "SHA1withRSA", "prov": "cryptojs/jsrsa"});
sig.initSign(key);
sig.updateString('message');
var sigValueHex = sig.sign();
This produced the expected hex signature. The documentation for jsrsasign provides the following code to verify signatures.
var sig = new KJUR.crypto.Signature({"alg": "SHA1withRSA", "prov": "cryptojs/jsrsa"});
sig.initVerifyByCertificatePEM("-----BEGIN CERTIFICATE-----(snip)");
sig.updateString('message');
var isValid = sig.verify(sigValueHex);
My problem is that I do not have a certificate to verify with. sig.sign() only gives the signature, no certificate. There is also sig.initVerifyByPublicKey(RSAKey) which seemed promising at first. However, RSAKey only has ways to get the private key, not public key.
So, my question is how can I get this certificate? And if I can't, how can I get an RSAKey object from my public key? And if I can't do that, is there a better way to do digital signatures with javascript?
I am using jsrsasign and jQuery. http://kjur.github.io/jsrsasign/
If there is no way to do this with the methods I am using, is there a better way? My main goal here is to be able to send a message to a server and be sure that the message wasn't tampered with and that it came from the correct place. SSL is not an option here. The message does not need to be encrypted, only protected.
You can create the public key with KEYUTIL.getKey(param), where "param" can be a string with either your certificate or your public key.
Here are the docs for that method
Example:
var publicKey = KEYUTIL.getKey(publicKeyString);
var sig = new r.Signature({"alg": "SHA256withRSA", "prov": "cryptojs/jsrsa"});
sig.initVerifyByPublicKey(publicKey);
sig.updateString(message);
var isValid = sig.verify(signature);
Hope that helps.
You could generate an X.509 self-signed key/certificate pair by using openssl.
openssl req -newkey rsa:4096 -x509 -nodes -keyout key.pem -out certificate.pem
Then upload certificate.pem to the server, and use key.pem to sign messages on the client.
The message and signature can be verified on the server.
Here is the sample code of using jsrsasign:
const jsrsasign = require("jsrsasign");
const fs = require('fs');
// sign
let key = fs.readFileSync("./key.pem", "utf-8");
let sig = new jsrsasign.KJUR.crypto.Signature({"alg": "SHA1withRSA"});
sig.init(key);
sig.updateString("message");
const signature = sig.sign();
// verify
let certificate = fs.readFileSync("./certificate.pem", "utf-8");
let ver = new jsrsasign.KJUR.crypto.Signature({"alg": "SHA1withRSA"});
ver.init(certificate);
ver.updateString("message");
ver.verify(signature); // return true
For your reference.

Problems with AES in crypto-js and pycrypto

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

Categories

Resources