I'm trying to set up a bidirectional encryption scheme between a client and server using the OpenSSL crypto API.
I have generated an RSA public/private key pair for the server. I wanted to use the EVP_Seal/Open functions to generate a symmetric key to be used for session encryption. The client uses the public key to encrypt a symmetric key and send it to the server using EVP_Seal. The server then uses EVP_Open to decrypt messages... but how do I now encrypt messages to send back to the client?
I don't actually have access to unencrypted the symmetric key, so I can't make calls to EVP_EncryptInit and the like. How do I encrypt information to send back to the client? I was under the impression I was generating a bi-directional symmetric key with these functions, but I can't figure out how to use it.
I considered sending a second symmetric key that I just generate myself (using, say, RAND_bytes) as a "message" that the server could then decrypt, but it seems like I should be able to use the symmetric key that was already generated instead of making a new one.
I also considered using the encrypted symmetric key output from EVP_Seal as my actual symmetric key and passing that as the message for the server to use for encryption, but that also seemed really weird and incorrect.
Related
I have messages I need to be able to encrypt when being sent. They should only be able to be decrypted by the receiver.
Initially, I had a structure where the message is encrypted using the receiver's public key, and the receiver then uses their private key to decrypt their messages. However, since I was using RSA, the size of the message was quite limited.
I'm imagining two potential solutions, but am not quite sure how to implement the better one (option 2).
(Easy) just split up each message into many smaller parts, encrypt and store those. This would only change the query structure of my app but not the encryption structure.
I could encrypt the messages with symmetric keys, which is faster and works on any size. However, I would then need to encrypt that symmetric key with an asymmetric one. The problem then becomes that I can only decrypt the symmetric key when the asymmetric private one is provided, ie when the receiver wants to read their messages. So in that case, how would I actually encrypt the messages? Since I don't want the sender to be able to access a key used for decryption as well.
The problem then becomes that I can only decrypt the symmetric key when the asymmetric private one is provided, ie when the receiver wants to read their messages. So in that case, how would I actually encrypt the messages?
That's simple, you use an ephemeral, message specific, fully random symmetric key for data encryption before you encrypt it with the public key. Preferably you should explicitly destroy the symmetric key after that. You can prefix the wrapped (encrypted) symmetric key before the ciphertext of the message, as it will always have the same size in bytes as the modulus (i.e. the RSA key size in bytes).
The system you are thinking about, which is much better than splitting up messages for RSA, is called a hybrid cryptosystem. There are various other ways to accomplish the same thing such as RSA-KEM and - for elliptic curves - ECIES. Both are not often present in crypto-libraries though.
If you decide to use RSA/AES for sending cryptograms then I would advice you to use OAEP and e.g. AES-CTR rather than AES-CBC as RSA PKCS#1 v1.5 padding and CBC padding are both vulnerable to padding oracle attacks.
It is highly recommended to sign the messages, otherwise an adversary can encrypt fake messages. Encryption is only used to achieve message confidentiality, not message integrity & authenticity. An adversary may even try plaintext oracle attacks if any message can be send. If you are not allowing a set of private keys that you control then you should sign-then-encrypt, not encrypt-then-sign.
And as always, prefer TLS or other explicit secure transport protocols if that's an option for transport security.
I want to encrypt all my form data with crypto js AES encryption. Is it good to keep the encrypt key value in client side like below.Kindly suggest.
var key = CryptoJS.enc.Utf8.parse("234234234DFDFDF343434DFDFDF")
, iv = CryptoJS.enc.Utf8.parse("234234324234324")
, data = CryptoJS.enc.Utf8.parse(str)
, encryptedData = CryptoJS.AES.encrypt(data, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
No, this is generally not secure.
First of all, you wrongly state your goal. AES encryption is not a goal, it is a means to an end. What you want to do is to keep your form data confidential. The form data is called "the message" in crypto terminology.
If you need to send your message to a server, and then let the server have the decrypted form, then you need transport security. It's best to use TLS for that. Commonly JavaScript doesn't have any means to create a trust relationship with the server (your browser uses it's certificate store with trusted certificates for that). So in that case you cannot rely on JavaScript security.
Sometimes you want to keep your front end from decrypting the messages. In that case you could send a public key such as an RSA public key over the secure channel. Then you could encrypt the form data using RSA and AES (hybrid cryptography). Your backend would then be able to decrypt the messages. This scheme still fails if your front end sends the wrong key though, as the message would be encrypted with a public key from another party. So this assumes that the front end software cannot be easily hacked (or replaced altogether by a different server, subverting the traffic).
Even if you could use a trusted AES key then using CBC for transport mode security will definitely enable plaintext or padding oracle attacks. You're lacking way too much experience with crypto to pull this off. Use TLS, that's hard enough (to secure, using it is relatively easy).
Problem
I want to sign and encrypt (effectively, obfuscate) some information ('token') on my server (a trusted environment) and send the cyphertext to a client machine (not quite trusted environment) to be read and verified by my client-side software. This type of the environment allows me to have a private key on the server for asymmetric signing, but I cannot 'hide' a secret key for symmetric signing on a client side.
Alternatives
I chose to use JWT as a standard and Nimbus JOSE+JWT library as an implementation for signing and encryption. Nimbus library provides two options for sign + encrypt: nest JWS into JWE or use JWE with authenticated encryption algorithm (A128CBC_HS256, A192CBC_HS384, or A256CBC_HS512). Algorithm Selection Guide for Nimbus states:
Encryption in JOSE is always authenticated, meaning that ciphertext’s integrity is protected from tampering. Authenticated encryption thus makes nesting an HMAC JWT inside a JSON Web Encryption (JWE) redundant; use just JWE encryption.
However, AxxxCBC_HSxxx encryption methods use only symmetric keys. Additionally, replacing direct JWE algorithm with RSA JWE algorithm should not help, because an abuser can generate CEK (consisting of encryption key and key for HMAC) themselves and encrypt it with a public key.
Question
Despite the quote about the redundancy of nested JWTs, I concluded, that for my case JWE+JWS nesting is the only workable approach. Am I right?
Clarifications
Every content encryption algorithms (AxxxGCM and AxxxCBC_HSxxx) use a symmetric key (CEK). This key is determined by the key encryption algorithm and its key management mode (random CEK, key agreement, direct key...).
You are right, contrary to the AxxxGCM algorithms, the AxxxCBC algorithms are not authenticated encryption algorithms.
However, the RFC7516 section 5.1 item 15. (specification for JWE) introduces a tag that allows to authenticate the cyphertext and protect the integrity of the protected header (that is why the AxxxCBC algorithm is used with the HSxxx).
This is confirmed by the table in the RFC7518 section 5.1. Details are given in the next section.
In any case, you will need 2 algorithms for JWE computation:
The key encryption algorithm: you mentioned you have an asymmetric key so I guess you will chose an RSA or an ECDH-ES algorithm depending on your key type.
The content encryption key: AxxxGCM or AxxxCBC_HSxxx algorithms. With the JWE specification both offer an authenticated encryption. Personally I prefer AxxxGCM algorithms because they are faster in my environment.
Answer
You indicated that you want sign and encrypt but you cannot hide a secret key on client side thus the signature will not be guaranteed.
If you only encrypt (JWE only), your server will not be able to verify the issuer of the token.
say you have some string:
bank_account = '12345';
and you want to encrypt it automatically with some method:
magic_encrypt(bank_account);
and store it. The decryption password/code will not exist on the server, and so the server needs to be able to encrypt it the data without being able to decrypt it. This way if the server is compromised, none of the stored data would be able to be decrypted by an evil 3rd party.
The data, when needed, would be pulled from the server and decrypted in a secure environment.
What type of encryption should I use?
What you want is called asymmetric key cryptography. Algorithms like RSA and ElGamal will do that.
I need to implemented security for client-server communication. I have implemented the following hybrid cryptosystem
To encrypt a message addressed to Alice in a hybrid cryptosystem, Bob does the following:
Obtains Alice's public key.
Generates a fresh symmetric key for the data encapsulation scheme.
Encrypts the message under the data encapsulation scheme, using the symmetric key just generated.
Encrypt the symmetric key under the key encapsulation scheme, using Alice's public key.
Send both of these encryptions to Alice.
To decrypt this hybrid ciphertext, Alice does the following:
uses her private key to decrypt the symmetric key contained in the key encapsulation segment.
uses this symmetric key to decrypt the message contained in the data encapsulation segment.
I am using RSA For a public-key cryptosystem, and AES for symmetric-key cryptosystem. Every thing works fine, but I am not sure how to handle AES initialization vector. Currently, I am concatenating the AES key and initialization vector encrypting it with the public key and sending that to server.
I just wanted to get some opinions about this approach. How this problem is solved by other communication protocols SSL etc.
Thanks.
You don't encrypt the IV. Bundle it with the encrypted key and send it (in the clear) to the recipient.
Standards for this do exist. This scheme is called "KeyTransRecipientInfo" in CMS (upon which S/MIME is based), and PGP offers a similar mode. TLS also includes the initialization vector as a parameter in the key encryption algorithm identifier, using the same ASN.1 syntax as CMS. A robust, open-source library to perform this operation is available for many, many platforms.
At the very least, studying the CMS specification might help avoid some of the many pitfalls in a home-brew implementation. See §6.1 and §6.2.1 of RFC 3369.
I've done the same thing, and I handled it the same way - concatenate the AES key with the IV and encrypt them both.
You could also just send the key and use the key itself to generate an IV - for example by using the first 128 bits of a hash of the key as the IV. That should be OK security-wise as long as you are generating a new AES key for each session and not re-using the same AES key over and over with the same IV.
There is no reason to encrypt the IV - you can send that in the clear. Just make sure you pick a new one each time (the same way you do the AES key).
That said, it is often convenient to package the AES key and IV together. Encryption of 16 bytes ain't that expensive.