MaddieM4 / EJTP-lib-python

Encrypted JSON Transport Protocol library for Python 2.6-3.3.
GNU Lesser General Public License v3.0
23 stars 10 forks source link

AES should never be used in ECB mode #133

Open PeterScott opened 11 years ago

PeterScott commented 11 years ago

Currently, your AES encryption is using ECB mode, rather than a more reasonable mode of operation like CBC or CTR. ECB mode always encrypts each block the same way, which can leak a lot of information.

MaddieM4 commented 11 years ago

AES has always been one of the worst encryption options available in EJTP, because there is no good fit in terms of cipher algorithm. The reason is that the EJTP frame model is extremely stateless. Frames can arrive in any order, at any time, and under bad network conditions some frames will drop. It's like encrypted UDP. You can use EJForward to handle retransmission, but you still have the order problem, and the fact that we don't track cipher stream state for anything.

Every frame is distinctly encrypted and has to be able to stand alone.

This is a bitch for getting stream encryption advantages, but I don't think it's impossible. There should theoretically be some efficient way to include ephemeral IV data at the head of every encrypted string. If you have any advice on how we would do this, given the constraints of the frame model's UDP-like nature, please let me know. It's something that's kind of been sitting stagnant, waiting for someone to come along who knows what he's doing.

PeterScott commented 11 years ago

Well, the usual method is this:

  1. Generate a random IV for each message from os.urandom()
  2. Encrypt the plaintext with the encryption key and IV in CBC mode.
  3. Append a timestamp and the IV to the ciphertext. (You can check this timestamp later to mitigate replay attacks.)
  4. Compute the HMAC of the ciphertext, IV, and timestamp with the hashing key.
  5. Append the HMAC to the message. Send it out!
  6. When the receiver gets the message, it first checks the HMAC, then the timestamp, then decrypts the message, then parses the JSON. Be sure to use a constant-time string comparison for the HMAC check.

The alternate method, which I would highly recommend, is to use PyNaCl. It does everything I just said, but better, and the API is super-easy.

MaddieM4 commented 11 years ago

Thank you very much for the rundown! It looks like PyNaCl is somewhat picky about what algorithms are currently available, so no AES, but this doesn't seem too onerous to do manually, especially thanks to the hmac module (which is arguably the most complex part of the dance).

The only part that worries me, of course, is timestamp persistence. Where that data is stored, how long, etc. On its own, EJTP intentionally only uses volatile memory (RAM), except to load identity data from cache files (which are not good candidates for storing hundreds or thousands of timestamps per identity). If we can solve that issue, we can finally move forward and make AES worth using.