Coverage Report

Created: 2022-01-14 08:07

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