/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 | | } |