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