Coverage Report

Created: 2020-05-23 13:54

/src/botan/src/lib/modes/cipher_mode.cpp
Line
Count
Source (jump to first uncovered line)
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
0
   {
48
0
   if(auto mode = Cipher_Mode::create(algo, direction, provider))
49
0
      return mode;
50
0
51
0
   throw Lookup_Error("Cipher mode", algo, provider);
52
0
   }
53
54
std::unique_ptr<Cipher_Mode> Cipher_Mode::create(const std::string& algo,
55
                                                 Cipher_Dir direction,
56
                                                 const std::string& provider)
57
0
   {
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
0
#if defined(BOTAN_HAS_STREAM_CIPHER)
85
0
   if(auto sc = StreamCipher::create(algo))
86
0
      {
87
0
      return std::unique_ptr<Cipher_Mode>(new Stream_Cipher_Mode(sc.release()));
88
0
      }
89
0
#endif
90
0
91
0
#if defined(BOTAN_HAS_AEAD_MODES)
92
0
   if(auto aead = AEAD_Mode::create(algo, direction))
93
0
      {
94
0
      return std::unique_ptr<Cipher_Mode>(aead.release());
95
0
      }
96
0
#endif
97
0
98
0
   if(algo.find('/') != std::string::npos)
99
0
      {
100
0
      const std::vector<std::string> algo_parts = split_on(algo, '/');
101
0
      const std::string cipher_name = algo_parts[0];
102
0
      const std::vector<std::string> mode_info = parse_algorithm_name(algo_parts[1]);
103
0
104
0
      if(mode_info.empty())
105
0
         return std::unique_ptr<Cipher_Mode>();
106
0
107
0
      std::ostringstream alg_args;
108
0
109
0
      alg_args << '(' << cipher_name;
110
0
      for(size_t i = 1; i < mode_info.size(); ++i)
111
0
         alg_args << ',' << mode_info[i];
112
0
      for(size_t i = 2; i < algo_parts.size(); ++i)
113
0
         alg_args << ',' << algo_parts[i];
114
0
      alg_args << ')';
115
0
116
0
      const std::string mode_name = mode_info[0] + alg_args.str();
117
0
      return Cipher_Mode::create(mode_name, direction, provider);
118
0
      }
119
0
120
0
#if defined(BOTAN_HAS_BLOCK_CIPHER)
121
0
122
0
   SCAN_Name spec(algo);
123
0
124
0
   if(spec.arg_count() == 0)
125
0
      {
126
0
      return std::unique_ptr<Cipher_Mode>();
127
0
      }
128
0
129
0
   std::unique_ptr<BlockCipher> bc(BlockCipher::create(spec.arg(0), provider));
130
0
131
0
   if(!bc)
132
0
      {
133
0
      return std::unique_ptr<Cipher_Mode>();
134
0
      }
135
0
136
0
#if defined(BOTAN_HAS_MODE_CBC)
137
0
   if(spec.algo_name() == "CBC")
138
0
      {
139
0
      const std::string padding = spec.arg(1, "PKCS7");
140
0
141
0
      if(padding == "CTS")
142
0
         {
143
0
         if(direction == ENCRYPTION)
144
0
            return std::unique_ptr<Cipher_Mode>(new CTS_Encryption(bc.release()));
145
0
         else
146
0
            return std::unique_ptr<Cipher_Mode>(new CTS_Decryption(bc.release()));
147
0
         }
148
0
      else
149
0
         {
150
0
         std::unique_ptr<BlockCipherModePaddingMethod> pad(get_bc_pad(padding));
151
0
152
0
         if(pad)
153
0
            {
154
0
            if(direction == ENCRYPTION)
155
0
               return std::unique_ptr<Cipher_Mode>(new CBC_Encryption(bc.release(), pad.release()));
156
0
            else
157
0
               return std::unique_ptr<Cipher_Mode>(new CBC_Decryption(bc.release(), pad.release()));
158
0
            }
159
0
         }
160
0
      }
161
0
#endif
162
0
163
0
#if defined(BOTAN_HAS_MODE_XTS)
164
0
   if(spec.algo_name() == "XTS")
165
0
      {
166
0
      if(direction == ENCRYPTION)
167
0
         return std::unique_ptr<Cipher_Mode>(new XTS_Encryption(bc.release()));
168
0
      else
169
0
         return std::unique_ptr<Cipher_Mode>(new XTS_Decryption(bc.release()));
170
0
      }
171
0
#endif
172
0
173
0
#if defined(BOTAN_HAS_MODE_CFB)
174
0
   if(spec.algo_name() == "CFB")
175
0
      {
176
0
      const size_t feedback_bits = spec.arg_as_integer(1, 8*bc->block_size());
177
0
      if(direction == ENCRYPTION)
178
0
         return std::unique_ptr<Cipher_Mode>(new CFB_Encryption(bc.release(), feedback_bits));
179
0
      else
180
0
         return std::unique_ptr<Cipher_Mode>(new CFB_Decryption(bc.release(), feedback_bits));
181
0
      }
182
0
#endif
183
0
184
0
#endif
185
0
186
0
   return std::unique_ptr<Cipher_Mode>();
187
0
   }
188
189
//static
190
std::vector<std::string> Cipher_Mode::providers(const std::string& algo_spec)
191
0
   {
192
0
   const std::vector<std::string>& possible = { "base", "openssl", "commoncrypto" };
193
0
   std::vector<std::string> providers;
194
0
   for(auto&& prov : possible)
195
0
      {
196
0
      std::unique_ptr<Cipher_Mode> mode = Cipher_Mode::create(algo_spec, ENCRYPTION, prov);
197
0
      if(mode)
198
0
         {
199
0
         providers.push_back(prov); // available
200
0
         }
201
0
      }
202
0
   return providers;
203
0
   }
204
205
}