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