18#include <openssl/objects.h>
19#include <openssl/evp.h>
35#if OPENSSL_VERSION_NUMBER < 0x30000000L
90 const unsigned char *key,
91 const unsigned int keysize,
95 unsigned int ckeysz = 0;
101 if (ckeysz > keysize)
102 throw openssl_gcm_error(
"insufficient key material");
103 ctx = EVP_CIPHER_CTX_new();
104 EVP_CIPHER_CTX_reset(
ctx);
108 if (!EVP_EncryptInit_ex(
ctx, ciph.get(),
nullptr, key,
nullptr))
112 throw openssl_gcm_error(
"EVP_EncryptInit_ex (init)");
116 if (!EVP_DecryptInit_ex(
ctx, ciph.get(),
nullptr, key,
nullptr))
120 throw openssl_gcm_error(
"EVP_DecryptInit_ex (init)");
124 throw openssl_gcm_error(
"bad mode");
126 if (EVP_CIPHER_CTX_ctrl(
ctx, EVP_CTRL_GCM_SET_IVLEN,
IV_LEN,
nullptr) != 1)
130 throw openssl_gcm_error(
"EVP_CIPHER_CTX_ctrl set IV len");
136 unsigned char *output,
138 const unsigned char *iv,
140 const unsigned char *ad,
147 if (!EVP_EncryptInit_ex(
ctx,
nullptr,
nullptr,
nullptr, iv))
150 throw openssl_gcm_error(
"EVP_EncryptInit_ex (reset)");
152 if (!EVP_EncryptUpdate(
ctx,
nullptr, &len, ad,
int(ad_len)))
155 throw openssl_gcm_error(
"EVP_EncryptUpdate AD");
157 if (!EVP_EncryptUpdate(
ctx, output, &len,
input,
int(length)))
160 throw openssl_gcm_error(
"EVP_EncryptUpdate data");
162 ciphertext_len = len;
163 if (!EVP_EncryptFinal_ex(
ctx, output + len, &len))
166 throw openssl_gcm_error(
"EVP_EncryptFinal_ex");
168 ciphertext_len += len;
169 if ((
size_t)ciphertext_len != length)
171 throw openssl_gcm_error(
"encrypt size inconsistency");
173 if (!EVP_CIPHER_CTX_ctrl(
ctx, EVP_CTRL_GCM_GET_TAG,
AUTH_TAG_LEN, tag))
176 throw openssl_gcm_error(
"EVP_CIPHER_CTX_ctrl get tag");
203 unsigned char *output,
205 const unsigned char *iv,
206 const unsigned char *tag,
207 const unsigned char *ad,
215 throw openssl_gcm_error(
"decrypt input length too short");
219 tag =
input + length;
223 if (!EVP_DecryptInit_ex(
ctx,
nullptr,
nullptr,
nullptr, iv))
226 throw openssl_gcm_error(
"EVP_DecryptInit_ex (reset)");
230 if (!EVP_DecryptUpdate(
ctx,
nullptr, &len, ad,
int(ad_len)))
233 throw openssl_gcm_error(
"EVP_DecryptUpdate AD");
235 if (!EVP_DecryptUpdate(
ctx, output, &len,
input,
int(length)))
238 throw openssl_gcm_error(
"EVP_DecryptUpdate data");
241 int plaintext_len = len;
244 if (!EVP_CIPHER_CTX_ctrl(
ctx, EVP_CTRL_GCM_SET_TAG,
AUTH_TAG_LEN,
const_cast<unsigned char *
>(tag)))
247 throw openssl_gcm_error(
"EVP_CIPHER_CTX_ctrl set tag");
249 if (!EVP_DecryptFinal_ex(
ctx, output + len, &len))
254 plaintext_len += len;
255 if (
static_cast<size_t>(plaintext_len) != length)
257 throw openssl_gcm_error(
"decrypt size inconsistency");
264 return ctx !=
nullptr;
269 unsigned int keysize = 0;
278 unsigned int &keysize)
302 EVP_CIPHER_CTX_free(
ctx);
308#ifdef OPENVPN_ENABLE_ASSERT
310 throw openssl_gcm_error(
"uninitialized");
314 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[]