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/objects.h>
21#include <openssl/evp.h>
22
29
32{
33 /* In OpenSSL 3.0 the method that returns EVP_CIPHER, the cipher needs to be
34 * freed afterwards, thus needing a non-const type. In contrast, OpenSSL 1.1.1
35 * and lower returns a const type, needing a const type */
36#if OPENSSL_VERSION_NUMBER < 0x30000000L
37 using evp_cipher_type = const EVP_CIPHER;
38#else
39 using evp_cipher_type = EVP_CIPHER;
40#endif
41
42 using CIPHER_unique_ptr = std::unique_ptr<evp_cipher_type, decltype(&::EVP_CIPHER_free)>;
43
44 CipherContext(const CipherContext &) = delete;
46
47 public:
48 OPENVPN_SIMPLE_EXCEPTION(openssl_cipher_mode_error);
49 OPENVPN_SIMPLE_EXCEPTION(openssl_cipher_uninitialized);
50 OPENVPN_EXCEPTION(openssl_cipher_error);
51
52 // mode parameter for constructor
53 enum
54 {
57 DECRYPT = 0
58 };
59
60 // OpenSSL cipher constants
61 enum
62 {
63 MAX_IV_LENGTH = EVP_MAX_IV_LENGTH,
64 CIPH_CBC_MODE = EVP_CIPH_CBC_MODE
65 };
66
67 CipherContext() = default;
68
73
74 static bool is_supported(SSLLib::Ctx libctx, const CryptoAlgs::Type alg)
75 {
76 CIPHER_unique_ptr cipher(cipher_type(libctx, alg), EVP_CIPHER_free);
77 return (bool)(cipher);
78 }
79
80 void init(SSLLib::Ctx libctx, const CryptoAlgs::Type alg, const unsigned char *key, const int mode)
81 {
82 // check that mode is valid
83 if (!(mode == ENCRYPT || mode == DECRYPT))
84 throw openssl_cipher_mode_error();
86 ctx = EVP_CIPHER_CTX_new();
87 EVP_CIPHER_CTX_reset(ctx);
88 CIPHER_unique_ptr cipher(cipher_type(libctx, alg), EVP_CIPHER_free);
89
90 if (!cipher)
91 OPENVPN_THROW(openssl_cipher_error, CryptoAlgs::name(alg) << ": not usable");
92
93 if (!EVP_CipherInit_ex(ctx, cipher.get(), nullptr, key, nullptr, mode))
94 {
97 throw openssl_cipher_error("EVP_CipherInit_ex (init)");
98 }
99 }
100
101 void reset(const unsigned char *iv)
102 {
104 if (!EVP_CipherInit_ex(ctx, nullptr, nullptr, nullptr, iv, -1))
105 {
107 throw openssl_cipher_error("EVP_CipherInit_ex (reset)");
108 }
109 }
110
111 bool update(unsigned char *out,
112 const size_t max_out_size,
113 const unsigned char *in,
114 const size_t in_size,
115 size_t &out_acc)
116 {
118 int outlen;
119 if (EVP_CipherUpdate(ctx, out, &outlen, in, int(in_size)))
120 {
121 out_acc += outlen;
122 return true;
123 }
124 else
125 {
127 return false;
128 }
129 }
130
131 bool final(unsigned char *out, const size_t max_out_size, size_t &out_acc)
132 {
134 int outlen;
135 if (EVP_CipherFinal_ex(ctx, out, &outlen))
136 {
137 out_acc += outlen;
138 return true;
139 }
140 else
141 {
143 return false;
144 }
145 }
146
147 bool is_initialized() const
148 {
149 return ctx != nullptr;
150 }
151
152 size_t iv_length() const
153 {
155 return EVP_CIPHER_CTX_iv_length(ctx);
156 }
157
158 size_t block_size() const
159 {
161 return EVP_CIPHER_CTX_block_size(ctx);
162 }
163
164 // return cipher mode (such as CIPH_CBC_MODE, etc.)
165 int cipher_mode() const
166 {
168 return EVP_CIPHER_CTX_mode(ctx);
169 }
170
171 private:
173 {
174 switch (alg)
175 {
177 return EVP_CIPHER_fetch(libctx, "AES-128-CBC", nullptr);
179 return EVP_CIPHER_fetch(libctx, "AES-192-CBC", nullptr);
181 return EVP_CIPHER_fetch(libctx, "AES-256-CBC", nullptr);
183 return EVP_CIPHER_fetch(libctx, "AES-256-CTR", nullptr);
185 return EVP_CIPHER_fetch(libctx, "DES-CBC", nullptr);
187 return EVP_CIPHER_fetch(libctx, "DES-EDE-CBC", nullptr);
189 return EVP_CIPHER_fetch(libctx, "BF-CBC", nullptr);
190 default:
191 return nullptr;
192 }
193 }
194
196 {
197 EVP_CIPHER_CTX_free(ctx);
198 ctx = nullptr;
199 }
200
201 void check_initialized() const
202 {
203#ifdef OPENVPN_ENABLE_ASSERT
204 if (ctx == nullptr)
205 throw openssl_cipher_uninitialized();
206#endif
207 }
208
209 EVP_CIPHER_CTX *ctx = nullptr;
210};
211} // namespace openvpn::OpenSSLCrypto
212
213#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:111
static bool is_supported(SSLLib::Ctx libctx, const CryptoAlgs::Type alg)
Definition cipher.hpp:74
std::unique_ptr< evp_cipher_type, decltype(&::EVP_CIPHER_free)> CIPHER_unique_ptr
Definition cipher.hpp:42
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:80
OPENVPN_SIMPLE_EXCEPTION(openssl_cipher_mode_error)
CipherContext & operator=(const CipherContext &)=delete
void reset(const unsigned char *iv)
Definition cipher.hpp:101
static evp_cipher_type * cipher_type(SSLLib::Ctx libctx, const CryptoAlgs::Type alg)
Definition cipher.hpp:172
static void EVP_CIPHER_free(const EVP_CIPHER *cipher)
Definition compat.hpp:83
static const EVP_CIPHER * EVP_CIPHER_fetch(void *ctx, const char *algorithm, const char *properties)
Definition compat.hpp:54
#define OPENVPN_THROW(exc, stuff)
const char * name(const KeyDerivation kd)
void openssl_clear_error_stack()
Definition error.hpp:247
static std::stringstream out
Definition test_path.cpp:10