Coverage Report

Created: 2026-11-12 06:54

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