3

I am developing an application that is based on UDP, and I need to send a stream of packets. As you can imagine, packets can get lost or corrupted. I need to make sure that the content of those packets is encrypted, and I also need to be able to certify that the packet is correct when I receive it.

Finally, since performance is crucial in my application, I would like to keep the encryption overhead as small as possible. Often times, packets are relatively small, so even a few blocks can build up a relatively big overhead.

I don't have a reliable previous experience with cryptography, so I thought it was better not to trust myself on this.

Here is the strategy I have used until now (my application is far from being released, so having to change it more or less completely won't be so much of a problem).

  • First of all, packets are of fixed size, which is usually multiple of the block size of AES. I have no need whatsoever for padding, since messages aren't variable in length.

  • I use a shared key (obviously) and two fixed IVs, each endpoint uses one of the two to encrypt its messages. I use AES in CBC mode.

  • Since obviously using a fixed IV leads to a whole bunch of security flaws, I need to make my first block vary in a uniformly random fashion: that will act as IV for the next blocks.

  • Therefore, I prepend a block at the beginning of my packet. Its content goes as follows:

    • First four bytes: current timestamp in seconds
    • Next 12 bytes: zeros
    • I compute the sha256 hash of the message (32 bytes)
    • I xor the timestamp + zeros block with the first half of the hash
    • I xor the result with the second half of the hash
  • When I receive the packet on the other endpoint, I decrypt it with the key and the remote iv.
  • I compute the sha256 hash of the message (without the first block), xor the first half and the second half.
  • I xor the result of the hashing procedure with the first block.
  • If I get a timestamp that is no more than a few seconds ago, and 12 bytes of zeros, then the packet is correct.
  • If the packet is not correct, I just drop it, exactly as if I didn't receive it. No answer is sent back.

What are the flaws in this procedure?

otus
  • 32,132
  • 5
  • 70
  • 165
Matteo Monti
  • 1,407
  • 2
  • 14
  • 19
  • Don't roll your own crypto. What's wrong with TLS? 2. Encrypt-then-MAC (and please use a proper MAC) 3. Use AES-GCM 4. Keep it simple.
  • – SEJPM Jul 07 '15 at 17:03
  • What would stop an adversary from manipulating clocks?
  • – SEJPM Jul 07 '15 at 17:05
  • 1
    packets are "usually multiple of the block size of AES"? You can't say usually then say that you "have no need whatsoever for padding". – mikeazo Jul 07 '15 at 17:08
  • Why not just use TCP instead and then just put TLS on top of it? You would literally even be better off rolling your own reliability on top of UDP than rolling your own crypto scheme. If TCP or other reliable transport really isn't an option, try DTLS, as mentioned in one of the answers. – reirab Jul 07 '15 at 21:52