Botan 3.6.1
Crypto and TLS for C&
cipher_mode.cpp
Go to the documentation of this file.
1/*
2* Cipher Modes
3* (C) 2015 Jack Lloyd
4*
5* Botan is released under the Simplified BSD License (see license.txt)
6*/
7
8#include <botan/cipher_mode.h>
9
10#include <botan/internal/parsing.h>
11#include <botan/internal/scan_name.h>
12#include <botan/internal/stream_mode.h>
13#include <sstream>
14
15#if defined(BOTAN_HAS_BLOCK_CIPHER)
16 #include <botan/block_cipher.h>
17#endif
18
19#if defined(BOTAN_HAS_AEAD_MODES)
20 #include <botan/aead.h>
21#endif
22
23#if defined(BOTAN_HAS_MODE_CBC)
24 #include <botan/internal/cbc.h>
25#endif
26
27#if defined(BOTAN_HAS_MODE_CFB)
28 #include <botan/internal/cfb.h>
29#endif
30
31#if defined(BOTAN_HAS_MODE_XTS)
32 #include <botan/internal/xts.h>
33#endif
34
35#if defined(BOTAN_HAS_COMMONCRYPTO)
36 #include <botan/internal/commoncrypto.h>
37#endif
38
39namespace Botan {
40
41std::unique_ptr<Cipher_Mode> Cipher_Mode::create_or_throw(std::string_view algo,
42 Cipher_Dir direction,
43 std::string_view provider) {
44 if(auto mode = Cipher_Mode::create(algo, direction, provider)) {
45 return mode;
46 }
47
48 throw Lookup_Error("Cipher mode", algo, provider);
49}
50
51std::unique_ptr<Cipher_Mode> Cipher_Mode::create(std::string_view algo,
52 Cipher_Dir direction,
53 std::string_view provider) {
54#if defined(BOTAN_HAS_COMMONCRYPTO)
55 if(provider.empty() || provider == "commoncrypto") {
56 if(auto cm = make_commoncrypto_cipher_mode(algo, direction))
57 return cm;
58
59 if(!provider.empty())
60 return nullptr;
61 }
62#endif
63
64 if(provider != "base" && !provider.empty()) {
65 return nullptr;
66 }
67
68#if defined(BOTAN_HAS_STREAM_CIPHER)
69 if(auto sc = StreamCipher::create(algo)) {
70 return std::make_unique<Stream_Cipher_Mode>(std::move(sc));
71 }
72#endif
73
74#if defined(BOTAN_HAS_AEAD_MODES)
75 if(auto aead = AEAD_Mode::create(algo, direction)) {
76 return aead;
77 }
78#endif
79
80 if(algo.find('/') != std::string::npos) {
81 const std::vector<std::string> algo_parts = split_on(algo, '/');
82 std::string_view cipher_name = algo_parts[0];
83 const std::vector<std::string> mode_info = parse_algorithm_name(algo_parts[1]);
84
85 if(mode_info.empty()) {
86 return std::unique_ptr<Cipher_Mode>();
87 }
88
89 std::ostringstream mode_name;
90
91 mode_name << mode_info[0] << '(' << cipher_name;
92 for(size_t i = 1; i < mode_info.size(); ++i) {
93 mode_name << ',' << mode_info[i];
94 }
95 for(size_t i = 2; i < algo_parts.size(); ++i) {
96 mode_name << ',' << algo_parts[i];
97 }
98 mode_name << ')';
99
100 return Cipher_Mode::create(mode_name.str(), direction, provider);
101 }
102
103#if defined(BOTAN_HAS_BLOCK_CIPHER)
104
105 SCAN_Name spec(algo);
106
107 if(spec.arg_count() == 0) {
108 return std::unique_ptr<Cipher_Mode>();
109 }
110
111 auto bc = BlockCipher::create(spec.arg(0), provider);
112
113 if(!bc) {
114 return std::unique_ptr<Cipher_Mode>();
115 }
116
117 #if defined(BOTAN_HAS_MODE_CBC)
118 if(spec.algo_name() == "CBC") {
119 const std::string padding = spec.arg(1, "PKCS7");
120
121 if(padding == "CTS") {
122 if(direction == Cipher_Dir::Encryption) {
123 return std::make_unique<CTS_Encryption>(std::move(bc));
124 } else {
125 return std::make_unique<CTS_Decryption>(std::move(bc));
126 }
127 } else {
128 auto pad = BlockCipherModePaddingMethod::create(padding);
129
130 if(pad) {
131 if(direction == Cipher_Dir::Encryption) {
132 return std::make_unique<CBC_Encryption>(std::move(bc), std::move(pad));
133 } else {
134 return std::make_unique<CBC_Decryption>(std::move(bc), std::move(pad));
135 }
136 }
137 }
138 }
139 #endif
140
141 #if defined(BOTAN_HAS_MODE_XTS)
142 if(spec.algo_name() == "XTS") {
143 if(direction == Cipher_Dir::Encryption) {
144 return std::make_unique<XTS_Encryption>(std::move(bc));
145 } else {
146 return std::make_unique<XTS_Decryption>(std::move(bc));
147 }
148 }
149 #endif
150
151 #if defined(BOTAN_HAS_MODE_CFB)
152 if(spec.algo_name() == "CFB") {
153 const size_t feedback_bits = spec.arg_as_integer(1, 8 * bc->block_size());
154 if(direction == Cipher_Dir::Encryption) {
155 return std::make_unique<CFB_Encryption>(std::move(bc), feedback_bits);
156 } else {
157 return std::make_unique<CFB_Decryption>(std::move(bc), feedback_bits);
158 }
159 }
160 #endif
161
162#endif
163
164 return std::unique_ptr<Cipher_Mode>();
165}
166
167//static
168std::vector<std::string> Cipher_Mode::providers(std::string_view algo_spec) {
169 const std::vector<std::string>& possible = {"base", "commoncrypto"};
170 std::vector<std::string> providers;
171 for(auto&& prov : possible) {
172 auto mode = Cipher_Mode::create(algo_spec, Cipher_Dir::Encryption, prov);
173 if(mode) {
174 providers.push_back(prov); // available
175 }
176 }
177 return providers;
178}
179
180} // namespace Botan
static std::unique_ptr< AEAD_Mode > create(std::string_view algo, Cipher_Dir direction, std::string_view provider="")
Definition aead.cpp:53
static std::unique_ptr< BlockCipherModePaddingMethod > create(std::string_view algo_spec)
Definition mode_pad.cpp:19
static std::unique_ptr< BlockCipher > create(std::string_view algo_spec, std::string_view provider="")
static std::unique_ptr< Cipher_Mode > create(std::string_view algo, Cipher_Dir direction, std::string_view provider="")
virtual std::string provider() const
static std::unique_ptr< Cipher_Mode > create_or_throw(std::string_view algo, Cipher_Dir direction, std::string_view provider="")
static std::vector< std::string > providers(std::string_view algo_spec)
std::string arg(size_t i) const
size_t arg_count() const
Definition scan_name.h:49
const std::string & algo_name() const
Definition scan_name.h:44
size_t arg_as_integer(size_t i, size_t def_value) const
static std::unique_ptr< StreamCipher > create(std::string_view algo_spec, std::string_view provider="")
std::vector< std::string > split_on(std::string_view str, char delim)
Definition parsing.cpp:111
std::unique_ptr< Cipher_Mode > make_commoncrypto_cipher_mode(std::string_view name, Cipher_Dir direction)
std::vector< std::string > parse_algorithm_name(std::string_view namex)
Definition parsing.cpp:57