Do I need multiple EVP_CIPHER_CTX structures?

I have a single-threaded client-server application that should perform both encryption and decryption of their network communication. I plan to use the OpenSSL EVP API and AES-256-CBC.

Some examples of pseudo-codes that I found from several examples:

// key is 256 bits (32 bytes) when using EVP_aes_256_*() // I think iv is the same size as the block size, 128 bits (16 bytes)...is it? 1: EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); 2: EVP_CipherInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv, 1); //0=decrypt, 1=encrypt 3: EVP_CipherUpdate(ctx, outbuf, &outlen, inbuf, inlen); 4: EVP_CipherFinal_ex(ctx, outbuf + outlen, &tmplen)); 5: outlen += tmplen; 6: EVP_CIPHER_CTX_cleanup(ctx); 7: EVP_CIPHER_CTX_free(ctx); 

The problem of all these examples, I'm not sure what to do with each encryption / decryption and what I should do only once at startup.

In particular:

  • On line 1, create this EVP_CIPHER_CTX only once and continue to reuse it until the application ends?
  • Also in line 1 can I reuse the same EVP_CIPHER_CTX for encryption and decryption, or should I create 2 of them?
  • On line 2, if IV is re-installed in every package that I encrypt? Or do I install IV only once, and then allow it to continue forever?
  • What should I do if I encrypt UDP packets, where a packet can easily go missing or be received due to an order: do I think that CBC is not working correctly, or is this where I need to reset the beginning of each packet sent?
+7
source share
3 answers

I have a single-threaded client-server application that must perform both encryption and decryption of its network interaction. I plan to use the OpenSSL EVP API and AES-256-CBC.

If you use the SSL_* functions from libssl , then most likely you will never EVP_* APIs EVP_* .


On line 1, do I create EVP_CIPHER_CTX only once and continue to use it until the application terminates?

You create it once per use. That is, since you need to encrypt, you use the same context. If you need to encrypt the second stream, you must use the second context. If you need to decrypt the third stream, you must use the third context.


Also on line 1, can I reuse the same EVP_CIPHER_CTX for encryption and decryption, or should I create 2 of them?

No, see above.

Ciphers will have different states.


On line 2, should I reinstall IV for every packet that I encrypt? Or did I install IV only once, and then let it go on forever?

No. You install IV once, and then forget about it. The context object manages this part of the state for the cipher.


What should I do if I encrypt UDP packets, where the packet can easily disappear or be received out of order: do I think that CBC will not work correctly ...

If you use UDP, then you may find similar problems. You will probably end up inventing TCP.

Encryption alone is usually not enough. You also need to ensure authenticity and integrity. You are not handling data that is not authentic. This is what continues to cause SST / TLS and SSH problems.

For example, here is the guy who wrote the main article on verified encryption regarding IPSec, SSL / TLS and SSH, weighing the Authenticate-Then-Encrypt (EtA) scheme used by SSL / TLS: Last Call: (Encrypt-then -MAC for TLS and DTLS) to the proposed standard :

The technical results in my 2001 article are correct, but the conclusion regarding SSL / TLS is incorrect. I assumed that TLS uses fresh IV and that the MAC was computed in encoded plaintext, i.e. Encode-Mac-Encrypt, while TLS does Mac-Encode-Encrypt, which, as my theoretical example shows, is unsafe.

For authenticity, you must abandon CBC mode and switch to GCM mode. GCM is an authenticated encryption mode that combines confidentiality and authenticity in one mode, so you do not need to combine primitives (like AES / CBC with HMAC).


or is this where I need to drop the IV at the beginning of every packet I sent?

No, you installed IV once, and then forgot about it.


The problem is in all these examples, I'm not sure what to do with each encryption / decryption, and what I should do only once at startup.

  1. Create it once: EVP_CIPHER_CTX
  2. Call it once to configure: EVP_CipherInit
  3. EVP_CipherUpdate is as many times as you want: EVP_CipherUpdate
  4. Call it once to clear: EVP_CipherFinal

OpenSSL has many examples of using the EVP_* interfaces. See Symmetric Encryption and Decryption of EVP, Encryption and Decryption with EVP Authentication , Signing and Verification of EVP .

All examples use the same template: Init , Update and then Final . It does not matter whether its encryption or hashing.


Related: this should interest you: encryption and decryption using EVP . This is sample code from the OpenSSL wiki.


Related: you can find copies of Viega, Messier and Chandra Network Security with OpenSSL online. You might consider finding a copy and getting to know some of its concepts.

+8
source

Sorry to restore the old thread, but I noticed the following error in the accepted answer:

On line 1, create this EVP_CIPHER_CTX only once and continue to reuse it until the application ends?

You create it once for use. That is, since you need to encrypt, you use the same context. If you need to encrypt the second stream, you must use the second context. If you need to decrypt the third stream, you must use the third context.

Also in line 1 can I reuse the same EVP_CIPHER_CTX for encryption and decryption, or should I create 2 of them?

No, see above.

It's not obligatory. On the man page for OpenSSL:

The new code should use EVP_EncryptInit_ex (), EVP_EncryptFinal_ex (), EVP_DecryptInit_ex (), EVP_DecryptFinal_ex (), EVP_CipherInit_ex (), and EVP_CipherFinal_ex (), since they can reuse the existing context without selecting.

In other words, you need to reinitialize the context each time before using it, but you can use the same context again and again without creating (highlighting) a new one.

+8
source

Sorry to revive the old branch, but LazerSharks asked twice about the evp encryption context in the comments. I do not have enough reputation points to add a few comments, so I will answer here. (A Google search doesn’t even show the right information now) From the book by Pravir Chandra, Network Security with OpenSSL, by Matt Messier, John Viega:

Before we can begin encryption or decryption, we must isolate and initialize the encryption context. A cipher context is a data structure that monitors all relevant states for the purpose of encrypting or decrypting data over a period of time. For example, we can have several data streams encrypted in CBC mode. The cipher context will track the key associated with each thread and the internal state that must be maintained between messages in CBC mode. In addition, when encrypting using a block-based encryption mode, the context object buffers data that does not exactly match the block size until more data arrives or the buffer is explicitly flushed, after which the data is usually supplemented accordingly.,

The general cipher context type is EVP_CIPHER_CTX. We can initialize one, whether it was allocated dynamically or statically by calling EVP_CIPHER_CTX_init, for example like this:

EVP_CIPHER_CTX * x = (EVP_CIPHER_CTX *) malloc (sizeof (EVP_CIPHER_CTX)); EVP_CIPHER_CTX_init (x);

0
source

Source: https://habr.com/ru/post/971164/


All Articles