How to add HMAC to CryptoJS AES encryption? - javascript

CryptoJS's convenience function CryptoJS.AES.encrypt("some plaintext", "password") doesn't seem to do any authentication.
I see CryptoJS provides an HMAC class, but I'm confused about how to use this to encrypt-then-authenticate.
I searched around for tutorials and other questions but couldn't find any.
How would I add authentication using the above CryptoJS HMAC class to authenticate the ciphertext produced by CryptoJS.AES.encrypt?

The idea with the HMAC provided by cryptoJS is to have you, the developer, pass it both the encrypted data and a key in order for it to spit out the MAC on the other end.
Below is an example of how you could use it to produce a MAC for your encrypted data. The idea here is that the key object is the shared secret used between you and trusted parties to verify the integrity of the encrypted data.
//Encrypt Data
var encryptObject = CryptoJS.AES.encrypt(content, key, { iv: yourIV });
//Calculate HMAC
var HMAC = CryptoJS.HmacSHA256(encryptObject.toString(), key);
A few things to keep in mind.
Always calculate the HMAC on the encrypted object before decryption. This prevents any manipulation of the encrypted data to cause harm after decryption.
Make sure the data encoding/format is the same when validating the HMAC. For example, above I used the toString() of my encrypted object, I did this becuase cryptoJS automatically serializes that object to only be the ciphertext. Upon decryption, I calculate the HMAC on the binary string of the encrypted blob I am presented with to make sure the HMAC calculates correctly.
With that I think you should be set to validate some data!
Also for a working example, you could check out http://meowcrypt.com/ which is my in browser file encryption service for google drive that uses cryptoJS.

Related

Encrypting form data with RSA at client side with javascript

I want to encrpyt my password and username from client side and decrypt it at server side(Asp.net core) with RSA(Or any other asymmetric algorithms). I am gonna send public key from server side so I don't need to create a public key at client side only need to encrypt it.
I am trying something like this..
var encrypt = new JSEncrypt();
encrypt.setPublicKey($('#pubkey').val());
var encrypted = encrypt.encrypt($('#input').val());
but it says JSEncrypt is not defined normally. But I don't know how to include this propery at my code.
https://github.com/travist/jsencrypt in here there is a good explanation but still I couldn't manage to do it. Also I really need a simple thing for just encryption with a known public key.
Edit 1: I am using https already but I still need to do it unfortunately.

Same encryption method of openssl_encrypt with CryptoJS

An API I am working with only accepts encrypted JSON object data with the openssl_encrypt formula below:
data = openssl_encrypt(body, 'aes-256-cbc', ciphertext+api_key, OPENSSL_RAW_DATA, ciphertext)
All responses from the API are also encrypted in this same way. Is it possible for me to achieve the same encryption format with CryptoJS so that the API will accept my encrypted data requests?
Here is what I have with CryptoJS at the moment.
var encryptedData = CryptoJS.AES.encrypt(JSON.stringify(body), 'aes-256-cbc', ciphertext + apikey, ciphertext);
var decryptedData = CryptoJS.AES.decrypt(encryptedData.toString(), 'aes-256-cbc', ciphertext + apikey, ciphertext);
var decryptedObjectData = JSON.parse(decryptedData.toString(CryptoJS.enc.Utf8));
console.log(decryptedObjectData);
When I encrypt my data and decrypt it with this code, it works. But when I receive encrypted data from the API and try to decrypt it with this CyptoJS, it tells me I have malformed UTF-8. Similarly, when I try to encrypt my data with CryptoJS to be accepted by the API, I get a 'Bad Request' response, meaning the encryption isn't accepted.
I am doing it via CryptoJS because I am new to encryption and do not know how to use openssl_encrypt with my application. But if someone can teach me, that would be great. I don't know how to run openssl_encrypt in php on my server and have my JS application run it. Is AJAX the way to call on a script on the server on your application?

Is my security design sound?

I have a specific need for security which means I'm writing more security-related code than I'm comfortable with. If what I'm doing is solved by a library somewhere, please, let me know and I'll drop my implementation immediately.
I have a server written in Java (actually Clojure) and a client written in JavaScript (actually ClojureScript) that runs as an Electron application. I need various clients applications to exchange information through the server ever being able to access that information: I need end to end encryption.
To implement end-to-end encryption I want to have a private public key-pair generated in the client and then the public key and an encrypted version of the private key will be uploaded to the server. Then, by doing a sort of challenge response in which the client signs a piece of random data and the server verifies it, the server would authenticate the user.
The registration process includes generating an Elliptic Curve Diffie Hellman key pair, specifically, P-521 (secp521r1) which seems to be a good choice according to https://security.stackexchange.com/questions/78621/which-elliptic-curve-should-i-use
After generating that, generate a 16 byte salt and then I pbkdf2 the password 872791 times with that salt, with a keylen of 32 and using sha512. Using the hashed key I encrypt the private key with aes-256-ctr. The last step is concatenating the salt length, the salt and the encrypted private key and send it to the server.
I'm assuming all of this happens over a TLS-secured channel, HTTPS, in which the validity of the certificate of the server is verified in the usual way, through the CAs. In the future I might use certificate pinning to increase security.
Is this a sound design? Does it look secure? Is there any or all of this that I could just delegate to a third party open source library that is well maintained?
My actual code:
(def elliptic-curve-name "secp521r1") ; https://security.stackexchange.com/questions/78621/which-elliptic-curve-should-i-use
(def encryption-algorithm "aes-256-ctr") ; http://lollyrock.com/articles/nodejs-encryption/
(def hash-bytes 32)
(def salt-bytes 16)
(def pbkdf-digest "sha512")
(def iterations 872791)
(defn encrypt-text [text key]
(let [salt (.randomBytes crypto salt-bytes)
salt-string (.toString salt "base64")
hashed-password (.pbkdf2Sync crypto key salt iterations hash-bytes pbkdf-digest)
text-cipher (.createCipher crypto encryption-algorithm hashed-password)
encrypted-text (gstring/format "%04d%s%s%s"
(count salt-string)
salt-string
(.update text-cipher text "utf8" "hex")
(.final text-cipher "hex"))]
encrypted-text))
(defn decrypt-text [encrypted-text key]
(let [salt-length (js/parseInt (subs encrypted-text 0 4) 10)
salt (.from js/Buffer (subs encrypted-text 4 (+ salt-length 4)) "base64")
hashed-key (.pbkdf2Sync crypto key salt iterations hash-bytes pbkdf-digest)
encrypted-text (subs encrypted-text (+ salt-length 4))
text-decipher (.createDecipher crypto encryption-algorithm hashed-key)]
(str (.update text-decipher encrypted-text "hex" "utf8")
(.final text-decipher "utf8"))))
(defn generate-key-pair [password]
(let [diff-hell (.createECDH crypto elliptic-curve-name)
public-key (.generateKeys diff-hell "base64")
private-key (.getPrivateKey diff-hell "base64")
encrypted-private-key (encrypt-text private-key password)]
[public-key private-key encrypted-private-key]))
This is an excellent start. These kind of questions are tricky and there is no way to prove these things secure. There are some good conceptual "pillars" to guide ones thoughs on it:
The pillars of security:
Privacy:
This code does not provide it. An attacker in the middle can read the structure of the message and can understand almost all of it. This gives them a strong stance. This system is open to replay attacks.
Authentication
By matching the password hash you are giving a strong assurance that this person does indeed know the password. PBKDF2 with a salt is state of the art and looks like you have this down.
Integrity:
This code does not provide it. the public key could be changed in flight. An attacker can substitute their own public key and cause the system to generate messages that they then could read. This attack is dependent on the rest of the system to detect the breach and respond to it, by comparing the public and private keys. This could open the system to known or unknown crypto attacks by allowing a "chosen key attack" which is generally considered dangerous. You really need to assure the integrity of the entire message. An attacker can take a password and key they do know along with a private key they do know, and switch them. Combined with replay attacks this will likely break the system.
Suggestions:
The structure of the entire message must be authenticated. There are two approaches to this. Either use a keyed MAC (Message Authentication Code) or use an "Authenticated Encryption" algorithm. MACs are included in more of the common crypto libraries. Don't roll your own MAC, and don't try to use a hash for this.
The privacy of the message should be ensured. This can be accomplished by ensuring that The message is send over TLS (you may already be doing this).
the message must include protection against replay attacks. This can be done in many ways. One strong way is to use a NONCE (Number used ONCe) so the server will only ever accept each message once. This must not be "per user" because many replay attacks are cross user.
The part you are absolutly doing correctly is asking for public scrutiny early in the process. This puts you way ahead of the industry norm. remember that
"Anyone, from the most clueless amateur to the best cryptographer, can create an algorithm that he himself can't break."
https://www.schneier.com/blog/archives/2011/04/schneiers_law.html
EDIT: make sure the password that protects them from you guessing their private key is not the same password you use to authenticate them (and that there is no way for them to use the same password)

Difference between RSAwithSHA256 and SHA256

I need to sign XML SAML message with the SAML 2.0 standardised algorithm (RSAwithSHA256). But my saml plugin (passport-saml) only seems to support sha1 and sha256. The SHA256 sounds pretty close to RSAwithSHA256, but probably is not the same thing? What is the difference, and how could I use RSAwithSHA256 instead? I probably need to edit the passport-saml library, to allow the use of RSAwithSHA256 algorithm?
I try to explain the differences, but not how to solve your issue.
RSA is a Public Key Cryptographic algorithm (Public and Private Key-Pair algorithm) and it assures Confidentiality, Authenticity (includes Identification) and Non-Repudiation.
SHA-256 is a Hashing algorithm, that produce a unique, fixed size 256-bit (32-byte) hash and it assures Message Integrity.
Hashing algorithm employed as follows,
Sender sends message and its hash to receiver. [Hashing employed]
Receiver hash the message to generate new hash. [Hashing employed]
Receiver check whether the new hash is equal to original hash.
If its equal, then message integrity is confirmed and receiver process the message further.
If its unequal, then message is tampered and receiver discard the message.
Here, how receiver confirms that message and its hash are indeed sent by expected sender? There is no authentication or identification of sender by receiver in the above case.
To do that, we have to use both Public Key Cryptography and Hashing Algorithms (like RSAWithSHA256) together to satisfy the above said requirement.
So, when employ Public Key Cryptography and Hashing Algorithms together,
Sender sends message and its encrypted hash (using private-key of sender) to receiver. [Encryption and Hashing employed]
Receiver decrypt the encrypted hash (using public-key of sender). [Decryption and Hashing employed]
Receiver hash the message to generate new hash. [Hashing employed]
Receiver check whether the new hash is equal to decrypted hash.
If its equal, then message integrity, authenticity and
identification of sender is confirmed and receiver process the
message further.
If its unequal, then message is tampered or not sent by intended
sender (since encrypted hash is not generated with private-key of expected sender) and receiver discard the message.

JavaScript message system encryption

I'm trying to create a message system with JavaScript and PHP / MySQL. I have a form with two input elements (recipient id, message content). I'm using MVC (Zend Framework 1). The form post data is send to my controller and stored in the database.
Now I want to encrypt the message before it is sent. I want to keep it user-friendly, so my idea was to use RSA (private / public key). The idea was that a private key was generated on user log in and stored in the cookies, to make sure that the private key is only on the user's machine. The public key could be stored in the user's table, so that any user, who want to send a message to him, can encrypt the data.
It is important that the key-pair is generated by the user's password. If it's random generated, it would not be possible to use multiple systems to log in, because the private key would change everytime. So that would be the mechanism to make sure, that he will always have the same private key, until he is changing his password.
I tried a few JavaScript libraries. cryptico seemed to be the right choice, because it generates private / public key by password. The problem here is, that I can not store the private key and not even look into the value.
They have an example on the website
// The passphrase used to repeatably generate this RSA key.
var PassPhrase = "The Moon is a Harsh Mistress.";
// The length of the RSA key, in bits.
var Bits = 1024;
var MattsRSAkey = cryptico.generateRSAKey(PassPhrase, Bits);
When I try to output MattsRSAkey, I only get [Object object]. It's the same when I store it in the Cookies. I tried to use JSON.stringify. With this function I can store and look inside MattsRSAKey. But when I want to use it later to decrypt the message, I get an error, that I have no valid public key. I think the private key got broken while storing it. When I read the private key from Cookies I use JSON.parse.
Is there any way to solve my problem? I just want to send encrypted messages from multiple users (public key) to one user (private key). My intention is not to have a secure transport but to store the messages encrypted in the database, so that unauthorized persons can not read it. It is important that I do not only have encryption for one-to-one messaging. This would be easy, because both users only would need to share a password for encryption.
There's a couple of things wrong here.
First, you're trying to store a Javascript object directly in a cookie. This won't work: cookies can only store string values. You will need to serialize the key to a string to store it in a cookie; unfortunately, it doesn't appear that the cryptico library exposes any methods to do this, so you will need to either implement a custom serializer, or use another cryptographic library.
Second, you are storing private cryptographic key data in cookies. This is perhaps the worst possible place to store this, as cookies are sent to the web server on every request. Local storage is much more appropriate here, as it is only accessible from Javascript code.

Categories