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