Coverage Report

Created: 2021-02-21 07:20

/src/botan/src/lib/modes/cfb/cfb.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
* CFB Mode
3
* (C) 1999-2007,2013,2017 Jack Lloyd
4
* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity
5
*
6
* Botan is released under the Simplified BSD License (see license.txt)
7
*/
8
9
#include <botan/internal/cfb.h>
10
11
namespace Botan {
12
13
CFB_Mode::CFB_Mode(BlockCipher* cipher, size_t feedback_bits) :
14
   m_cipher(cipher),
15
   m_block_size(m_cipher->block_size()),
16
   m_feedback_bytes(feedback_bits ? feedback_bits / 8 : m_block_size)
17
0
   {
18
0
   if(feedback_bits % 8 || feedback() > cipher->block_size())
19
0
      throw Invalid_Argument(name() + ": feedback bits " +
20
0
                                  std::to_string(feedback_bits) + " not supported");
21
0
   }
22
23
void CFB_Mode::clear()
24
0
   {
25
0
   m_cipher->clear();
26
0
   m_keystream.clear();
27
0
   reset();
28
0
   }
29
30
void CFB_Mode::reset()
31
0
   {
32
0
   m_state.clear();
33
0
   zeroise(m_keystream);
34
0
   }
35
36
std::string CFB_Mode::name() const
37
0
   {
38
0
   if(feedback() == cipher().block_size())
39
0
      return cipher().name() + "/CFB";
40
0
   else
41
0
      return cipher().name() + "/CFB(" + std::to_string(feedback()*8) + ")";
42
0
   }
43
44
size_t CFB_Mode::output_length(size_t input_length) const
45
0
   {
46
0
   return input_length;
47
0
   }
48
49
size_t CFB_Mode::update_granularity() const
50
0
   {
51
0
   return feedback();
52
0
   }
53
54
size_t CFB_Mode::minimum_final_size() const
55
0
   {
56
0
   return 0;
57
0
   }
58
59
Key_Length_Specification CFB_Mode::key_spec() const
60
0
   {
61
0
   return cipher().key_spec();
62
0
   }
63
64
size_t CFB_Mode::default_nonce_length() const
65
0
   {
66
0
   return block_size();
67
0
   }
68
69
bool CFB_Mode::valid_nonce_length(size_t n) const
70
0
   {
71
0
   return (n == 0 || n == block_size());
72
0
   }
73
74
void CFB_Mode::key_schedule(const uint8_t key[], size_t length)
75
0
   {
76
0
   m_cipher->set_key(key, length);
77
0
   m_keystream.resize(m_cipher->block_size());
78
0
   }
79
80
void CFB_Mode::start_msg(const uint8_t nonce[], size_t nonce_len)
81
0
   {
82
0
   if(!valid_nonce_length(nonce_len))
83
0
      throw Invalid_IV_Length(name(), nonce_len);
84
85
0
   verify_key_set(!m_keystream.empty());
86
87
0
   if(nonce_len == 0)
88
0
      {
89
0
      if(m_state.empty())
90
0
         {
91
0
         throw Invalid_State("CFB requires a non-empty initial nonce");
92
0
         }
93
      // No reason to encrypt state->keystream_buf, because no change
94
0
      }
95
0
   else
96
0
      {
97
0
      m_state.assign(nonce, nonce + nonce_len);
98
0
      cipher().encrypt(m_state, m_keystream);
99
0
      m_keystream_pos = 0;
100
0
      }
101
0
   }
102
103
void CFB_Mode::shift_register()
104
0
   {
105
0
   const size_t shift = feedback();
106
0
   const size_t carryover = block_size() - shift;
107
108
0
   if(carryover > 0)
109
0
      {
110
0
      copy_mem(m_state.data(), &m_state[shift], carryover);
111
0
      }
112
0
   copy_mem(&m_state[carryover], m_keystream.data(), shift);
113
0
   cipher().encrypt(m_state, m_keystream);
114
0
   m_keystream_pos = 0;
115
0
   }
116
117
size_t CFB_Encryption::process(uint8_t buf[], size_t sz)
118
0
   {
119
0
   verify_key_set(!m_keystream.empty());
120
0
   BOTAN_STATE_CHECK(m_state.empty() == false);
121
122
0
   const size_t shift = feedback();
123
124
0
   size_t left = sz;
125
126
0
   if(m_keystream_pos != 0)
127
0
      {
128
0
      const size_t take = std::min<size_t>(left, shift - m_keystream_pos);
129
130
0
      xor_buf(m_keystream.data() + m_keystream_pos, buf, take);
131
0
      copy_mem(buf, m_keystream.data() + m_keystream_pos, take);
132
133
0
      m_keystream_pos += take;
134
0
      left -= take;
135
0
      buf += take;
136
137
0
      if(m_keystream_pos == shift)
138
0
         {
139
0
         shift_register();
140
0
         }
141
0
      }
142
143
0
   while(left >= shift)
144
0
      {
145
0
      xor_buf(m_keystream.data(), buf, shift);
146
0
      copy_mem(buf, m_keystream.data(), shift);
147
148
0
      left -= shift;
149
0
      buf += shift;
150
0
      shift_register();
151
0
      }
152
153
0
   if(left > 0)
154
0
      {
155
0
      xor_buf(m_keystream.data(), buf, left);
156
0
      copy_mem(buf, m_keystream.data(), left);
157
0
      m_keystream_pos += left;
158
0
      }
159
160
0
   return sz;
161
0
   }
162
163
void CFB_Encryption::finish(secure_vector<uint8_t>& buffer, size_t offset)
164
0
   {
165
0
   update(buffer, offset);
166
0
   }
167
168
namespace {
169
170
inline void xor_copy(uint8_t buf[], uint8_t key_buf[], size_t len)
171
0
   {
172
0
   for(size_t i = 0; i != len; ++i)
173
0
      {
174
0
      uint8_t k = key_buf[i];
175
0
      key_buf[i] = buf[i];
176
0
      buf[i] ^= k;
177
0
      }
178
0
   }
179
180
}
181
182
size_t CFB_Decryption::process(uint8_t buf[], size_t sz)
183
0
   {
184
0
   verify_key_set(!m_keystream.empty());
185
0
   BOTAN_STATE_CHECK(m_state.empty() == false);
186
187
0
   const size_t shift = feedback();
188
189
0
   size_t left = sz;
190
191
0
   if(m_keystream_pos != 0)
192
0
      {
193
0
      const size_t take = std::min<size_t>(left, shift - m_keystream_pos);
194
195
0
      xor_copy(buf, m_keystream.data() + m_keystream_pos, take);
196
197
0
      m_keystream_pos += take;
198
0
      left -= take;
199
0
      buf += take;
200
201
0
      if(m_keystream_pos == shift)
202
0
         {
203
0
         shift_register();
204
0
         }
205
0
      }
206
207
0
   while(left >= shift)
208
0
      {
209
0
      xor_copy(buf, m_keystream.data(), shift);
210
0
      left -= shift;
211
0
      buf += shift;
212
0
      shift_register();
213
0
      }
214
215
0
   if(left > 0)
216
0
      {
217
0
      xor_copy(buf, m_keystream.data(), left);
218
0
      m_keystream_pos += left;
219
0
      }
220
221
0
   return sz;
222
0
   }
223
224
void CFB_Decryption::finish(secure_vector<uint8_t>& buffer, size_t offset)
225
0
   {
226
0
   update(buffer, offset);
227
0
   }
228
229
}