Hi dev, https://www.openssl.org/docs/man1.1.0/crypto/EVP_CIPHER_CTX_ctrl.html
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, taglen, tag); Sets the expected tag to taglen bytes from tag. This call is only legal when decrypting data and must be made before any data is processed (e.g. before any EVP_DecryptUpdate() call). For OCB mode the taglen must either be 16 or the value previously set via EVP_CTRL_AEAD_SET_TAG. According to the openssl 1.1.0 docs, it said the EVP_CTRL_AEAD_SET_TAG is only legal and must before any data is processed. But the sample code within wiki.openssl.org: https://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *aad, int aad_len, unsigned char *tag, unsigned char *key, unsigned char *iv, int iv_len, unsigned char *plaintext) { EVP_CIPHER_CTX *ctx; int len; int plaintext_len; int ret; /* Create and initialise the context */ if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors(); /* Initialise the decryption operation. */ if(!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL)) handleErrors(); /* Set IV length. Not necessary if this is 12 bytes (96 bits) */ if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL)) handleErrors(); /* Initialise key and IV */ if(!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv)) handleErrors(); /* Provide any AAD data. This can be called zero or more times as * required */ if(!EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len)) handleErrors(); /* Provide the message to be decrypted, and obtain the plaintext output. * EVP_DecryptUpdate can be called multiple times if necessary */ if(!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len)) handleErrors(); plaintext_len = len; /* Set expected tag value. Works in OpenSSL 1.0.1d and later */ if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag)) handleErrors(); /* Finalise the decryption. A positive return value indicates success, * anything else is a failure - the plaintext is not trustworthy. */ ret = EVP_DecryptFinal_ex(ctx, plaintext + len, &len); /* Clean up */ EVP_CIPHER_CTX_free(ctx); if(ret > 0) { /* Success */ plaintext_len += len; return plaintext_len; } else { /* Verify failed */ return -1; } } And our AE/AD decrypt function from QUIC: ``` bool QUICCrypto::_decrypt(uint8_t *plain, size_t &plain_len, size_t max_plain_len, const uint8_t *cipher, size_t cipher_len, uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const uint8_t *key, size_t key_len, const uint8_t *iv, size_t iv_len, size_t tag_len) const { uint8_t nonce[EVP_MAX_IV_LENGTH] = {0}; size_t nonce_len = 0; _gen_nonce(nonce, nonce_len, pkt_num, iv, iv_len); EVP_CIPHER_CTX *aead_ctx; int len; if (!(aead_ctx = EVP_CIPHER_CTX_new())) { return false; } if (!EVP_DecryptInit_ex(aead_ctx, this->_aead, nullptr, nullptr, nullptr)) { return false; } if (!EVP_CIPHER_CTX_ctrl(aead_ctx, EVP_CTRL_AEAD_SET_IVLEN, nonce_len, nullptr)) { return false; } if (!EVP_DecryptInit_ex(aead_ctx, nullptr, nullptr, key, nonce)) { return false; } if (!EVP_DecryptUpdate(aead_ctx, nullptr, &len, ad, ad_len)) { return false; } if (cipher_len < tag_len) { return false; } cipher_len -= tag_len; if (!EVP_DecryptUpdate(aead_ctx, plain, &len, cipher, cipher_len)) { return false; } plain_len = len; if (!EVP_CIPHER_CTX_ctrl(aead_ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, const_cast<uint8_t *>(cipher + cipher_len))) { return false; } int ret = EVP_DecryptFinal_ex(aead_ctx, plain + len, &len); EVP_CIPHER_CTX_free(aead_ctx); if (ret > 0) { plain_len += len; return true; } else { Debug(tag, "Failed to decrypt"); return false; } } ``` - Oknet