OpenVPN 3 Core Library
Loading...
Searching...
No Matches
cipher.hpp
Go to the documentation of this file.
1// OpenVPN -- An application to securely tunnel IP networks
2// over a single port, with support for SSL/TLS-based
3// session authentication and key exchange,
4// packet encryption, packet authentication, and
5// packet compression.
6//
7// Copyright (C) 2012- OpenVPN Inc.
8//
9// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
10//
11
12// Wrap the OpenSSL cipher API defined in <openssl/evp.h> so
13// that it can be used as part of the crypto layer of the OpenVPN core.
14
15#ifndef OPENVPN_OPENSSL_CRYPTO_CIPHER_H
16#define OPENVPN_OPENSSL_CRYPTO_CIPHER_H
17
18#include <string>
19
20#include <openssl/evp.h>
21#include <openssl/objects.h>
22#include <openssl/opensslv.h>
23
30
33{
34 /* In OpenSSL 3.0 the method that returns EVP_CIPHER, the cipher needs to be
35 * freed afterwards, thus needing a non-const type. In contrast, OpenSSL 1.1.1
36 * and lower returns a const type, needing a const type */
37#if OPENSSL_VERSION_NUMBER < 0x30000000L
38 using evp_cipher_type = const EVP_CIPHER;
39#else
40 using evp_cipher_type = EVP_CIPHER;
41#endif
42
43 using CIPHER_unique_ptr = std::unique_ptr<evp_cipher_type, decltype(&::EVP_CIPHER_free)>;
44
45 CipherContext(const CipherContext &) = delete;
47
48 public:
49 OPENVPN_SIMPLE_EXCEPTION(openssl_cipher_mode_error);
50 OPENVPN_SIMPLE_EXCEPTION(openssl_cipher_uninitialized);
51 OPENVPN_EXCEPTION(openssl_cipher_error);
52
53 // mode parameter for constructor
54 enum
55 {
58 DECRYPT = 0
59 };
60
61 // OpenSSL cipher constants
62 enum
63 {
64 MAX_IV_LENGTH = EVP_MAX_IV_LENGTH,
65 CIPH_CBC_MODE = EVP_CIPH_CBC_MODE
66 };
67
68 CipherContext() = default;
69
74
75 static bool is_supported(SSLLib::Ctx libctx, const CryptoAlgs::Type alg)
76 {
77 CIPHER_unique_ptr cipher(cipher_type(libctx, alg), EVP_CIPHER_free);
78 return (bool)(cipher);
79 }
80
81 void init(SSLLib::Ctx libctx, const CryptoAlgs::Type alg, const unsigned char *key, const int mode)
82 {
83 // check that mode is valid
84 if (!(mode == ENCRYPT || mode == DECRYPT))
85 throw openssl_cipher_mode_error();
87 ctx = EVP_CIPHER_CTX_new();
88 EVP_CIPHER_CTX_reset(ctx);
89 CIPHER_unique_ptr cipher(cipher_type(libctx, alg), EVP_CIPHER_free);
90
91 if (!cipher)
92 OPENVPN_THROW(openssl_cipher_error, CryptoAlgs::name(alg) << ": not usable");
93
94 if (!EVP_CipherInit_ex(ctx, cipher.get(), nullptr, key, nullptr, mode))
95 {
98 throw openssl_cipher_error("EVP_CipherInit_ex (init)");
99 }
100 }
101
102 void reset(const unsigned char *iv)
103 {
105 if (!EVP_CipherInit_ex(ctx, nullptr, nullptr, nullptr, iv, -1))
106 {
108 throw openssl_cipher_error("EVP_CipherInit_ex (reset)");
109 }
110 }
111
112 bool update(unsigned char *out,
113 const size_t max_out_size,
114 const unsigned char *in,
115 const size_t in_size,
116 size_t &out_acc)
117 {
119 int outlen;
120 if (EVP_CipherUpdate(ctx, out, &outlen, in, int(in_size)))
121 {
122 out_acc += outlen;
123 return true;
124 }
125
127 return false;
128 }
129
130 bool final(unsigned char *out, const size_t max_out_size, size_t &out_acc)
131 {
133 int outlen;
134 if (EVP_CipherFinal_ex(ctx, out, &outlen))
135 {
136 out_acc += outlen;
137 return true;
138 }
139
141 return false;
142 }
143
144 bool is_initialized() const
145 {
146 return ctx != nullptr;
147 }
148
149 size_t iv_length() const
150 {
152 return EVP_CIPHER_CTX_iv_length(ctx);
153 }
154
155 size_t block_size() const
156 {
158 return EVP_CIPHER_CTX_block_size(ctx);
159 }
160
161 // return cipher mode (such as CIPH_CBC_MODE, etc.)
162 int cipher_mode() const
163 {
165 return EVP_CIPHER_CTX_mode(ctx);
166 }
167
168 private:
170 {
171 switch (alg)
172 {
174 return EVP_CIPHER_fetch(libctx, "AES-128-CBC", nullptr);
176 return EVP_CIPHER_fetch(libctx, "AES-192-CBC", nullptr);
178 return EVP_CIPHER_fetch(libctx, "AES-256-CBC", nullptr);
180 return EVP_CIPHER_fetch(libctx, "AES-256-CTR", nullptr);
182 return EVP_CIPHER_fetch(libctx, "DES-CBC", nullptr);
184 return EVP_CIPHER_fetch(libctx, "DES-EDE-CBC", nullptr);
186 return EVP_CIPHER_fetch(libctx, "BF-CBC", nullptr);
187 default:
188 return nullptr;
189 }
190 }
191
193 {
194 EVP_CIPHER_CTX_free(ctx);
195 ctx = nullptr;
196 }
197
198 void check_initialized() const
199 {
200#ifdef OPENVPN_ENABLE_ASSERT
201 if (ctx == nullptr)
202 throw openssl_cipher_uninitialized();
203#endif
204 }
205
206 EVP_CIPHER_CTX *ctx = nullptr;
207};
208} // namespace openvpn::OpenSSLCrypto
209
210#endif
OPENVPN_SIMPLE_EXCEPTION(openssl_cipher_uninitialized)
bool update(unsigned char *out, const size_t max_out_size, const unsigned char *in, const size_t in_size, size_t &out_acc)
Definition cipher.hpp:112
static bool is_supported(SSLLib::Ctx libctx, const CryptoAlgs::Type alg)
Definition cipher.hpp:75
std::unique_ptr< evp_cipher_type, decltype(&::EVP_CIPHER_free)> CIPHER_unique_ptr
Definition cipher.hpp:43
OPENVPN_EXCEPTION(openssl_cipher_error)
CipherContext(const CipherContext &)=delete
void init(SSLLib::Ctx libctx, const CryptoAlgs::Type alg, const unsigned char *key, const int mode)
Definition cipher.hpp:81
OPENVPN_SIMPLE_EXCEPTION(openssl_cipher_mode_error)
CipherContext & operator=(const CipherContext &)=delete
void reset(const unsigned char *iv)
Definition cipher.hpp:102
static evp_cipher_type * cipher_type(SSLLib::Ctx libctx, const CryptoAlgs::Type alg)
Definition cipher.hpp:169
static void EVP_CIPHER_free(const EVP_CIPHER *cipher)
Definition compat.hpp:85
static const EVP_CIPHER * EVP_CIPHER_fetch(void *ctx, const char *algorithm, const char *properties)
Definition compat.hpp:56
#define OPENVPN_THROW(exc, stuff)
const char * name(const KeyDerivation kd)
void openssl_clear_error_stack()
Definition error.hpp:239
static std::stringstream out
Definition test_path.cpp:10