18#include <openssl/evp.h>
19#include <openssl/objects.h>
20#include <openssl/opensslv.h>
36#if OPENSSL_VERSION_NUMBER < 0x30000000L
91 const unsigned char *key,
92 const unsigned int keysize,
96 unsigned int ckeysz = 0;
102 if (ckeysz > keysize)
103 throw openssl_gcm_error(
"insufficient key material");
104 ctx = EVP_CIPHER_CTX_new();
105 EVP_CIPHER_CTX_reset(
ctx);
109 if (!EVP_EncryptInit_ex(
ctx, ciph.get(),
nullptr, key,
nullptr))
113 throw openssl_gcm_error(
"EVP_EncryptInit_ex (init)");
117 if (!EVP_DecryptInit_ex(
ctx, ciph.get(),
nullptr, key,
nullptr))
121 throw openssl_gcm_error(
"EVP_DecryptInit_ex (init)");
125 throw openssl_gcm_error(
"bad mode");
127 if (EVP_CIPHER_CTX_ctrl(
ctx, EVP_CTRL_GCM_SET_IVLEN,
IV_LEN,
nullptr) != 1)
131 throw openssl_gcm_error(
"EVP_CIPHER_CTX_ctrl set IV len");
137 unsigned char *output,
139 const unsigned char *iv,
141 const unsigned char *ad,
148 if (!EVP_EncryptInit_ex(
ctx,
nullptr,
nullptr,
nullptr, iv))
151 throw openssl_gcm_error(
"EVP_EncryptInit_ex (reset)");
153 if (!EVP_EncryptUpdate(
ctx,
nullptr, &len, ad,
int(ad_len)))
156 throw openssl_gcm_error(
"EVP_EncryptUpdate AD");
158 if (!EVP_EncryptUpdate(
ctx, output, &len,
input,
int(length)))
161 throw openssl_gcm_error(
"EVP_EncryptUpdate data");
163 ciphertext_len = len;
164 if (!EVP_EncryptFinal_ex(
ctx, output + len, &len))
167 throw openssl_gcm_error(
"EVP_EncryptFinal_ex");
169 ciphertext_len += len;
170 if ((
size_t)ciphertext_len != length)
172 throw openssl_gcm_error(
"encrypt size inconsistency");
174 if (!EVP_CIPHER_CTX_ctrl(
ctx, EVP_CTRL_GCM_GET_TAG,
AUTH_TAG_LEN, tag))
177 throw openssl_gcm_error(
"EVP_CIPHER_CTX_ctrl get tag");
204 unsigned char *output,
206 const unsigned char *iv,
207 const unsigned char *tag,
208 const unsigned char *ad,
216 throw openssl_gcm_error(
"decrypt input length too short");
220 tag =
input + length;
224 if (!EVP_DecryptInit_ex(
ctx,
nullptr,
nullptr,
nullptr, iv))
227 throw openssl_gcm_error(
"EVP_DecryptInit_ex (reset)");
231 if (!EVP_DecryptUpdate(
ctx,
nullptr, &len, ad,
int(ad_len)))
234 throw openssl_gcm_error(
"EVP_DecryptUpdate AD");
236 if (!EVP_DecryptUpdate(
ctx, output, &len,
input,
int(length)))
239 throw openssl_gcm_error(
"EVP_DecryptUpdate data");
242 int plaintext_len = len;
245 if (!EVP_CIPHER_CTX_ctrl(
ctx, EVP_CTRL_GCM_SET_TAG,
AUTH_TAG_LEN,
const_cast<unsigned char *
>(tag)))
248 throw openssl_gcm_error(
"EVP_CIPHER_CTX_ctrl set tag");
250 if (!EVP_DecryptFinal_ex(
ctx, output + len, &len))
255 plaintext_len += len;
256 if (
static_cast<size_t>(plaintext_len) != length)
258 throw openssl_gcm_error(
"decrypt size inconsistency");
265 return ctx !=
nullptr;
270 unsigned int keysize = 0;
279 unsigned int &keysize)
303 EVP_CIPHER_CTX_free(
ctx);
309#ifdef OPENVPN_ENABLE_ASSERT
311 throw openssl_gcm_error(
"uninitialized");
315 EVP_CIPHER_CTX *
ctx =
nullptr;
void update(const std::size_t outlen)
void free_cipher_context()
static evp_cipher_type * cipher_type(SSLLib::Ctx libctx, const CryptoAlgs::Type alg, unsigned int &keysize)
const Crypto::AEADUsageLimit & get_usage_limit()
static bool is_supported(SSLLib::Ctx libctx, const CryptoAlgs::Type alg)
bool is_initialized() const
void init(SSLLib::Ctx libctx, const CryptoAlgs::Type alg, const unsigned char *key, const unsigned int keysize, const int mode)
const EVP_CIPHER evp_cipher_type
CipherContextAEAD(CipherContextAEAD &&other) noexcept
bool decrypt(const unsigned char *input, unsigned char *output, size_t length, const unsigned char *iv, const unsigned char *tag, const unsigned char *ad, size_t ad_len)
CipherContextAEAD()=default
void check_initialized() const
Crypto::AEADUsageLimit aead_usage_limit_
OPENVPN_EXCEPTION(openssl_gcm_error)
std::unique_ptr< evp_cipher_type, decltype(&::EVP_CIPHER_free)> CIPHER_unique_ptr
CipherContextAEAD(const CipherContextAEAD &)=delete
CipherContextAEAD & operator=(const CipherContextAEAD &)=delete
CipherContextAEAD & operator=(CipherContextAEAD &&other)
bool constexpr requires_authtag_at_end()
void encrypt(const unsigned char *input, unsigned char *output, size_t length, const unsigned char *iv, unsigned char *tag, const unsigned char *ad, size_t ad_len)
static void EVP_CIPHER_free(const EVP_CIPHER *cipher)
static const EVP_CIPHER * EVP_CIPHER_fetch(void *ctx, const char *algorithm, const char *properties)
#define OPENVPN_THROW(exc, stuff)
const char * name(const KeyDerivation kd)
void openssl_clear_error_stack()
static const char * input[]