2

Please bear with me as I am not an expert in security. I have a server and a client. On the server I am encrypting a very secret message (using AES256-GCM to hide the information and protect it's integrity) that I will send to the client. The client though will never decrypt this message, they will only receive it from the server and send it back to the server with their requests. My server will then decrypt and get the secret message which it needs to process other information. I need to ensure the client will never know of the contents inside the message. I am using javascript (NodeJS) for my server code and it looks like this (hopefully it is simple to read and easy to understand):

var crypto = require('crypto'); //get crypto library
var algorithm = 'aes-256-gcm'; // select which algorithm I want to use
var password = '3zTvzr3p67VC61jmV54rIYu1545x4TlY'; //Random generated 256bit key

function encrypt(text) {
  var iv = crypto.randomBytes(128) // generate a random 128bit iv for every encryption
  var cipher = crypto.createCipheriv(algorithm, password, iv)
  var encrypted = cipher.update(text, 'utf8', 'hex')
  encrypted += cipher.final('hex');
  var tag = cipher.getAuthTag();
  var enc = {
    content: encrypted,
    tag: tag.toString('hex')
  };

sendToClientOverInternet(enc,iv); //send the encrypted content + the iv to client over the internet

}

function decrypt(encrypted) {
  var decipher = crypto.createDecipheriv(algorithm, password, iv)
  decipher.setAuthTag(new Buffer(encrypted.tag, 'hex'));
  var dec = decipher.update(encrypted.content, 'hex', 'utf8')
  dec += decipher.final('utf8');
  return dec;
}

I am concerned more of the process and encryption methods opposed to infrastructure security. With that lets assume my server is completely safe and the hard coded password in my code will never be accessed and the transportation of data over the internet is over ssl.

My code with my questions:

1) First I generated a global securely random 32byte key.

Q: Is this the correct size? Any way to improve the key?

2) I have an encrypt method which takes some text and encrypts it using AES256-GCM. It then takes this encrypted object and along with the iv(128 bit securley random generated for every message) sends it to the client. The client if they wanted to then could now see this encrypted object and the iv.

Q: Is protecting the integrity of the data using GCM necessary? If I use CTR instead wouldn't it be impossible for the hacker to decrypt and change the message anyways without the key? So is GCM 'overkill'? Is sending the iv and having it accessible to the user safe? Is a 128 bit iv long enough? Any big improvements I can make here?.

3) I have a decrypt method which takes my encrypted string and decrypts it.

Q: (I don't think anything here needs to be improved).

Any improvements or suggestions would be greatly appreciated.

  • If the client doesn't need the data, why send it to begin with? – Jonathan Gray Jan 18 '16 at 23:50
  • Due to NoSQL nature of no relations I had to come up with some creative ways to do somethings. I have an entity which has non-confidential attributes and one confidential attribute. This attribute contains some information such as internal account numbers. These account numbers are confidential and to be used internally only. I send this encrypted attribute to the client so that when they make a request they pass this encrypted string along with the request which I then decrypt on the server side to be able to see the secret internal account number and perform CRUD operations on the database. – user2924127 Jan 19 '16 at 0:05
  • 2
    This sounds like a job for sessions. Generate a 32-byte cryptographically secure pseudo-random value, base64-encode it, and use that as a session ID. Store the sensitive data server-side in an object indexed by that session ID, and store the session ID in a session cookie. – Jonathan Gray Jan 19 '16 at 0:09
  • 3
    I don't want to continue this into a long discussion or anything but I would like to offer my two cents at the same time. The overhead of encryption/decryption per-request should also be weighed as a factor. Those are extra CPU cycles that could be put to much better use elsewhere. It can possibly even be used as a DoS vector by overloading the CPU with many long request to decrypt. IMHO this is something that should have been planned before the work on the project was even started. – Jonathan Gray Jan 19 '16 at 3:06
  • 2
    the 256-bit key in your code only has 192-bits max entropy, fyi – Richie Frame Jan 19 '16 at 10:37
4

I assume the client and server communicate via some secure channel e.g. TLS? Otherwise anyone sitting on the wire can mount a replay attack i.e. intercept the ciphertext sent to the client, and send that ciphertext back to the server to impersonate the intended recipient.

From the comments it sounds like you are using the ciphertext passed to the client as a way of not maintaining state on the server. More specifically, you send a message to the client of their encrypted state and then have them send it back and decrypt / process that state on arrival. If you are already storing the encryption keys is it really that much harder to refactor to storing session tokens?

Regarding your question using GCM

  • The iv (or nonce as it's generally called in GCM mode) is sent along with the ciphertext, the security of GCM does not rely on the iv being secret, only that it is never reused, so 128 bits of random is fine (though as Xander's answer states, there are theoretical attacks against ivs that are not 96 bits). As long as your key has enough entropy you should be fine.
  • GCM does get around some of the problems other modes have. CTR (which you mentioned) and CBC for instance have bit-flipping attacks against them where the ciphertext can be modified without knowledge of the key to produce meaningful changes in the plaintext. CBC and CTR modes would require a MAC of the ciphertext sent along with them to verify the integrity of it. So while it is possible to use these modes securely it's requires a couple more steps than GCM.

In conclusion this construction is rather unorthodox, and a mechanism such as session tokens would improve performance (and give the benefit of being a tried and tested method). If you must go this route though GCM should be fine for keeping the data secure from the client.

  • Puzzle - you mention that the OP is already storing the encryption keys. I'm not sure what you are referring to. From the code in the OP, it looks like there is one encryption key used for all client-side encrypted data that is hardwired into the code. Are you referring to another key? – Neil Smithline Jan 19 '16 at 23:44
  • I missed that detail in the source, I assumed from the password variable that some sort of key derivation was done to obtain the AES key. You are right that the server seems to have just one master AES key. – puzzlepalace Jan 20 '16 at 0:32
3

This all generally looks reasonable, but there are a couple of items to review:

  • First and foremost, the note in Puzzlepalace's answer about the need for TLS most definitely applies. And preferably HSTS as well, if you can.

  • Second, there are theoretical (read, not practical) attacks on GCM with nonces (IV) with lengths of other than 96-bits. So, while this might not be critical, it would certainly be a recommended practice to shorten your nonce from 128-bits to 96.

  • Third and finally, key management. Keys should be stored in a secure location, and definitely not in source code. They should not be committed to source control, stored in clear-text, shared between environments, known to users other than the environment operators, and rotated regularly. So, this pretty much rules out having your keys in the application source code itself.

I'm not a Node expert by any means, but other than those issues, but the approach is certainly fine.

  • Can you add a link to the GCM nonce/IV size attack thing Xander? My google-fu doesn't seem up to the job. – Neil Smithline Jan 19 '16 at 23:40
  • +1 for the critical point about key management. – Neil Smithline Jan 19 '16 at 23:43
  • Neil - Take a look at this paper, specifically section 4 "Non default length in IV". I'm not sure the attacks apply in this case as they are chosen plaintext attacks from what I gather. – puzzlepalace Jan 20 '16 at 0:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.