0

For AES based encryption on TCP/IP connections, I am guessing I have to do the following:

  1. Have the 2 parties share a common key, assuming I am doing AES-128 then a sequence of 16 bytes. Ideally the bits are securely random.

  2. Since we are running AES in CTR mode and the secret key is fixed, we must choose a securely random IV for each stream instance. Since a TCP/IP connection is actually full-duplex I assume I need 2 IVs per connection, one for each direction. I also need to transmit each IV to the other end in order for the corresponding stream to be decrypted.

Edit note: the scheme described above is prone to replay attacks. Maybe a better scheme is to send the decipher IVs to the other party and force the other party to encrypt a constant, and if we can decipher to get the constant back then the other end is authenticated. Also the scheme does not ensure message integrity.

My question is, for the IVs, should I be encrypting the IVs with my secret key before sending them over? I was told IVs don't have to be kept secret. Is there any security benefits if I do encrypt them before sending across?

ps. you may wonder why I am not using SSL/TLS. Our application does support SSL/TLS, but we also want to support alternate symmetric encryption mode where connection overhead can be minimized, as clients constantly disconnect and reconnect.

  • 3
    TLS already has a facility to do what you're looking for: session tickets. If you have to ask questions like the above, you are in no position to be inventing your own encrypted communication protocols. Using a protocol that already exists will save you countless amounts of engineering effort and actually stands a chance of protecting your data. – Stephen Touset Jan 27 '15 at 8:13
  • @Stephen actually session resumption can use either classic caching or newer/optional tickets. Caching is a bit cheaper as long as the/any server doesn't need to support an excessive number of clients, FSVO excessive. – dave_thompson_085 Jan 27 '15 at 16:16
  • @StephenTouset we already have SSL/TLS mode in place, just trying to support an alternate mode of operation with symmetric key encryption, where we don't have to deal with certificates. IMO SSL/TLS certificates are good for web based applications but not general TCP/IP apps because it adds a lot of complexity without gain in security. – javaPhobic Jan 27 '15 at 22:58
  • 1
    Based on what relevant experience and/or expertise do you make that claim? SSL (secure sockets layer) was designed to protect virtually any streaming socket (e.g., TCP), not as a secure HTTP layer. It has been put to use countless application-level protocols on top of TCP. And it doesn't matter that you also support HTTPS; you're only as secure as your weakest link, and if that weak link ends up being your homegrown transport protocol, that's the one attackers will exploit. – Stephen Touset Jan 28 '15 at 4:38
  • 1
    First, there exist non-RSA ciphersuites for TLS (e.g., ECDHE-ECDSA-AES128-GCM-SHA256, which is based on elliptic curves and have bit lengths on par with symmetric encryption). Second, even then it doesn't matter because 4,096-bit RSA is fine — the bit length is almost entirely irrelevant as long as it's large enough to provide the margin of security you're looking for given the choice of algorithm. And regardless, whatever home-brew system you concoct is infinitely more likely to be a source of weakness than 4,096-bit RSA keys. – Stephen Touset Jan 29 '15 at 3:29
3

No, you don't encrypt IVs. They need to be never, ever reused, but that's pretty much it for IV requirements for CTR mode -- there's absolutely no need to keep them confidential. Moreover, you affirmatively shouldn't encrypt your IV with the key used to encrypt your message -- depending on your padding scheme, that can very well expose one of the blocks of your message. Under no circumstances will it improve security; any vulnerability in CTR mode will be a vulnerability here as well.

Recall how CTR mode works. In CTR mode, the actual data is never passed as input to the block cipher. Instead, you concatenate a shorter-than-block IV and a shorter-than-block counter, encrypt that, and XOR with the data. An attacker who recovers the encryption of IV||n can recover the n-th block.

Now, you can't encrypt the IV by itself. It's actually impossible: the IV is sub-block-length, and AES is incapable of encrypting anything that isn't an exact multiple of the length of a block. You need to pad your IV to encrypt it (the reason CTR normally doesn't use padding is that you don't pass the data to AES; if you did, you would need padding). Suppose your padding scheme pads with zeroes and then tacks the length of the message on the end (all common padding schemes have to have the message length show up somewhere, because if you just zero-padded then "john0" and "john" would both become "john000...000"). For your 64-bit IV, the padding would turn IV into IV||0x00...01000000; you would then encrypt that and tack it on the start of your message. But the encryption of that is exactly what you XOR with the 64th block of your message. So by encrypting your IV here, you revealed the 64th block of your message, whereas with an unencrypted IV it was secure.

(incidentally: When people say "don't roll your own crypto, it's easy to make subtle mistakes," this is one such subtle mistake. If you're new to crypto, it might seem more secure to encrypt your IV. You have to pad it, so you might pick the fairly reasonable-seeming zero padding with a length tag. Doing so here lets an attacker read a block of your ciphertext.)

The only way around this is to pad such that the padded IV will never be encrypted to generate keystream material. Pretty much the best way to achieve this is to agree on IV length or send IV length cleartext, encrypt all zeroes for the first block, and then not send the IV (on the other end, the decrypted first block gives IV|0x00...01, which you can take the first bunch of bits for to get the IV). Any encryption of the IV, if the padding scheme is "stick this stuff which is k in hex, on the end of the IV", is equivalent to making block k consist of all zeroes. If you look at it like this, you can see that just about any CTR vulnerability will also affect your scheme. The only vulnerabilities related to the attacker knowing the IV, on the other hand, would indicate a serious flaw in AES itself, one which means any scheme using it is instantly suspect.

So no, it's a bad idea to encrypt the IV. If you must do it, the way to do it is to make the first block of your message all zeroes, not send the IV, and on the other end decrypt the first block and take the first 64 bits (or however long your IVs are) as your IV; that won't be less secure than regular CTR. However, it won't be more secure either, because any flaw in AES-CTR related to the IV makes all AES modes presumptively unsafe.

  • Thank you - I can't up-vote your answer but i will when I have enough reputation :) Btw, I am using Java and the IV in the function appears to enforce it being same size as the block of AES (16 bytes), and provided that I use SecureRandom to generate it I am guessing I won't be exposing my key even if I do send the IV across, but you have certainly convinced me it's not necessary. – javaPhobic Jan 27 '15 at 22:51
  • Often, an IV is computed from the same master key, exchanged securely, that the encryption key is computed from, e.g. K = H(master || 0) and IV = H(master || 1). In some case the IV is actually all zeros because the key will never be re-used. The Tor protocol for example uses a null IV. – forest Jun 22 '18 at 1:57

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.