Botan  2.4.0
Crypto and TLS for C++11
ctr.cpp
Go to the documentation of this file.
1 /*
2 * Counter mode
3 * (C) 1999-2011,2014 Jack Lloyd
4 *
5 * Botan is released under the Simplified BSD License (see license.txt)
6 */
7 
8 #include <botan/ctr.h>
9 #include <botan/loadstor.h>
10 
11 namespace Botan {
12 
14  m_cipher(ciph),
15  m_block_size(m_cipher->block_size()),
16  m_ctr_size(m_block_size),
17  m_ctr_blocks(m_cipher->parallel_bytes() / m_block_size),
18  m_counter(m_cipher->parallel_bytes()),
19  m_pad(m_counter.size()),
20  m_pad_pos(0)
21  {
22  }
23 
24 CTR_BE::CTR_BE(BlockCipher* cipher, size_t ctr_size) :
25  m_cipher(cipher),
26  m_block_size(m_cipher->block_size()),
27  m_ctr_size(ctr_size),
28  m_ctr_blocks(m_cipher->parallel_bytes() / m_block_size),
29  m_counter(m_cipher->parallel_bytes()),
30  m_pad(m_counter.size()),
31  m_pad_pos(0)
32  {
33  if(m_ctr_size < 4 || m_ctr_size > m_block_size)
34  throw Invalid_Argument("Invalid CTR-BE counter size");
35  }
36 
38  {
39  m_cipher->clear();
40  zeroise(m_pad);
41  zeroise(m_counter);
42  zap(m_iv);
43  m_pad_pos = 0;
44  }
45 
46 void CTR_BE::key_schedule(const uint8_t key[], size_t key_len)
47  {
48  m_cipher->set_key(key, key_len);
49 
50  // Set a default all-zeros IV
51  set_iv(nullptr, 0);
52  }
53 
54 std::string CTR_BE::name() const
55  {
56  if(m_ctr_size == m_block_size)
57  return ("CTR-BE(" + m_cipher->name() + ")");
58  else
59  return ("CTR-BE(" + m_cipher->name() + "," + std::to_string(m_ctr_size) + ")");
60 
61  }
62 
63 void CTR_BE::cipher(const uint8_t in[], uint8_t out[], size_t length)
64  {
65  verify_key_set(m_iv.empty() == false);
66 
67  const uint8_t* pad_bits = &m_pad[0];
68  const size_t pad_size = m_pad.size();
69 
70  if(m_pad_pos > 0)
71  {
72  const size_t avail = pad_size - m_pad_pos;
73  const size_t take = std::min(length, avail);
74  xor_buf(out, in, pad_bits + m_pad_pos, take);
75  length -= take;
76  in += take;
77  out += take;
78  m_pad_pos += take;
79 
80  if(take == avail)
81  {
82  add_counter(m_ctr_blocks);
83  m_cipher->encrypt_n(m_counter.data(), m_pad.data(), m_ctr_blocks);
84  m_pad_pos = 0;
85  }
86  }
87 
88  while(length >= pad_size)
89  {
90  xor_buf(out, in, pad_bits, pad_size);
91  length -= pad_size;
92  in += pad_size;
93  out += pad_size;
94 
95  add_counter(m_ctr_blocks);
96  m_cipher->encrypt_n(m_counter.data(), m_pad.data(), m_ctr_blocks);
97  }
98 
99  xor_buf(out, in, pad_bits, length);
100  m_pad_pos += length;
101  }
102 
103 void CTR_BE::set_iv(const uint8_t iv[], size_t iv_len)
104  {
105  if(!valid_iv_length(iv_len))
106  throw Invalid_IV_Length(name(), iv_len);
107 
108  m_iv.resize(m_cipher->block_size());
109  zeroise(m_iv);
110  buffer_insert(m_iv, 0, iv, iv_len);
111 
112  seek(0);
113  }
114 
115 void CTR_BE::add_counter(const uint64_t counter)
116  {
117  const size_t ctr_size = m_ctr_size;
118  const size_t ctr_blocks = m_ctr_blocks;
119  const size_t BS = m_block_size;
120 
121  if(ctr_size == 4)
122  {
123  size_t off = (BS - 4);
124  for(size_t i = 0; i != ctr_blocks; ++i)
125  {
126  uint32_t low32 = load_be<uint32_t>(&m_counter[off], 0);
127  low32 += counter;
128  store_be(low32, &m_counter[off]);
129  off += BS;
130  }
131  }
132  else if(ctr_size == 8)
133  {
134  size_t off = (BS - 8);
135  for(size_t i = 0; i != ctr_blocks; ++i)
136  {
137  uint64_t low64 = load_be<uint64_t>(&m_counter[off], 0);
138  low64 += counter;
139  store_be(low64, &m_counter[off]);
140  off += BS;
141  }
142  }
143  else if(ctr_size == 16)
144  {
145  size_t off = (BS - 16);
146  for(size_t i = 0; i != ctr_blocks; ++i)
147  {
148  uint64_t b0 = load_be<uint64_t>(&m_counter[off], 0);
149  uint64_t b1 = load_be<uint64_t>(&m_counter[off], 1);
150  b1 += counter;
151  b0 += (b1 < counter) ? 1 : 0; // carry
152  store_be(b0, &m_counter[off]);
153  store_be(b1, &m_counter[off+8]);
154  off += BS;
155  }
156  }
157  else
158  {
159  for(size_t i = 0; i != ctr_blocks; ++i)
160  {
161  uint64_t local_counter = counter;
162  uint16_t carry = static_cast<uint8_t>(local_counter);
163  for(size_t j = 0; (carry || local_counter) && j != ctr_size; ++j)
164  {
165  const size_t off = i*BS + (BS-1-j);
166  const uint16_t cnt = static_cast<uint16_t>(m_counter[off]) + carry;
167  m_counter[off] = static_cast<uint8_t>(cnt);
168  local_counter = (local_counter >> 8);
169  carry = (cnt >> 8) + static_cast<uint8_t>(local_counter);
170  }
171  }
172  }
173  }
174 
175 void CTR_BE::seek(uint64_t offset)
176  {
177  verify_key_set(m_iv.empty() == false);
178 
179  const uint64_t base_counter = m_ctr_blocks * (offset / m_counter.size());
180 
181  zeroise(m_counter);
182  buffer_insert(m_counter, 0, m_iv);
183 
184  const size_t BS = m_block_size;
185 
186  // Set m_counter blocks to IV, IV + 1, ... IV + n
187  for(size_t i = 1; i != m_ctr_blocks; ++i)
188  {
189  buffer_insert(m_counter, i*BS, &m_counter[(i-1)*BS], BS);
190 
191  for(size_t j = 0; j != m_ctr_size; ++j)
192  if(++m_counter[i*BS + (BS - 1 - j)])
193  break;
194  }
195 
196  if(base_counter > 0)
197  add_counter(base_counter);
198 
199  m_cipher->encrypt_n(m_counter.data(), m_pad.data(), m_ctr_blocks);
200  m_pad_pos = offset % m_counter.size();
201  }
202 }
void verify_key_set(bool cond) const
Definition: sym_algo.h:95
void zap(std::vector< T, Alloc > &vec)
Definition: secmem.h:191
void store_be(uint16_t in, uint8_t out[2])
Definition: loadstor.h:434
uint32_t load_be< uint32_t >(const uint8_t in[], size_t off)
Definition: loadstor.h:177
std::string name() const override
Definition: ctr.cpp:54
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:108
uint64_t load_be< uint64_t >(const uint8_t in[], size_t off)
Definition: loadstor.h:215
void seek(uint64_t offset) override
Definition: ctr.cpp:175
void xor_buf(uint8_t out[], const uint8_t in[], size_t length)
Definition: mem_ops.h:163
void clear() override
Definition: ctr.cpp:37
Definition: alg_id.cpp:13
CTR_BE(BlockCipher *cipher)
Definition: ctr.cpp:13
void set_iv(const uint8_t iv[], size_t iv_len) override
Definition: ctr.cpp:103
void cipher(const uint8_t in[], uint8_t out[], size_t length) override
Definition: ctr.cpp:63
size_t buffer_insert(std::vector< T, Alloc > &buf, size_t buf_offset, const T input[], size_t input_length)
Definition: secmem.h:103
bool valid_iv_length(size_t iv_len) const override
Definition: ctr.h:26
void zeroise(std::vector< T, Alloc > &vec)
Definition: secmem.h:181