Botan  1.10.17
secmem.h
Go to the documentation of this file.
1 /*
2 * Secure Memory Buffers
3 * (C) 1999-2007 Jack Lloyd
4 *
5 * Distributed under the terms of the Botan license
6 */
7 
8 #ifndef BOTAN_SECURE_MEMORY_BUFFERS_H__
9 #define BOTAN_SECURE_MEMORY_BUFFERS_H__
10 
11 #include <botan/allocate.h>
12 #include <botan/mem_ops.h>
13 #include <algorithm>
14 
15 namespace Botan {
16 
17 /**
18 * This class represents variable length memory buffers.
19 */
20 template<typename T>
22  {
23  public:
24  /**
25  * Find out the size of the buffer, i.e. how many objects of type T it
26  * contains.
27  * @return size of the buffer
28  */
29  size_t size() const { return used; }
30 
31  /**
32  * Find out whether this buffer is empty.
33  * @return true if the buffer is empty, false otherwise
34  */
35  bool empty() const { return (used == 0); }
36 
37  /**
38  * Get a pointer to the first element in the buffer.
39  * @return pointer to the first element in the buffer
40  */
41  operator T* () { return buf; }
42 
43  /**
44  * Get a constant pointer to the first element in the buffer.
45  * @return constant pointer to the first element in the buffer
46  */
47  operator const T* () const { return buf; }
48 
49  /**
50  * Get a pointer to the first element in the buffer.
51  * @return pointer to the first element in the buffer
52  */
53  T* data() { return buf; }
54 
55  /**
56  * Get a pointer to the first element in the buffer.
57  * @return pointer to the first element in the buffer
58  */
59  T* begin() { return buf; }
60 
61  /**
62  * Get a constant pointer to the first element in the buffer.
63  * @return constant pointer to the first element in the buffer
64  */
65  const T* begin() const { return buf; }
66 
67  /**
68  * Get a pointer to one past the last element in the buffer.
69  * @return pointer to one past the last element in the buffer
70  */
71  T* end() { return (buf + size()); }
72 
73  /**
74  * Get a const pointer to one past the last element in the buffer.
75  * @return const pointer to one past the last element in the buffer
76  */
77  const T* end() const { return (buf + size()); }
78 
79  /**
80  * Check two buffers for equality.
81  * @return true iff the content of both buffers is byte-wise equal
82  */
83  bool operator==(const MemoryRegion<T>& other) const
84  {
85  return (size() == other.size() &&
86  same_mem(buf, other.buf, size()));
87  }
88 
89  /**
90  * Compare two buffers
91  * @return true iff this is ordered before other
92  */
93  bool operator<(const MemoryRegion<T>& other) const;
94 
95  /**
96  * Check two buffers for inequality.
97  * @return false if the content of both buffers is byte-wise equal, true
98  * otherwise.
99  */
100  bool operator!=(const MemoryRegion<T>& other) const
101  { return (!(*this == other)); }
102 
103  /**
104  * Copy the contents of another buffer into this buffer.
105  * The former contents of *this are discarded.
106  * @param other the buffer to copy the contents from.
107  * @return reference to *this
108  */
110  {
111  if(this != &other)
112  {
113  this->resize(other.size());
114  this->copy(&other[0], other.size());
115  }
116  return (*this);
117  }
118 
119  /**
120  * Copy the contents of an array of objects of type T into this buffer.
121  * The former contents of *this are discarded.
122  * The length of *this must be at least n, otherwise memory errors occur.
123  * @param in the array to copy the contents from
124  * @param n the length of in
125  */
126  void copy(const T in[], size_t n)
127  {
128  copy_mem(buf, in, std::min(n, size()));
129  }
130 
131  /**
132  * Copy the contents of an array of objects of type T into this buffer.
133  * The former contents of *this are discarded.
134  * The length of *this must be at least n, otherwise memory errors occur.
135  * @param off the offset position inside this buffer to start inserting
136  * the copied bytes
137  * @param in the array to copy the contents from
138  * @param n the length of in
139  */
140  void copy(size_t off, const T in[], size_t n)
141  {
142  copy_mem(buf + off, in, std::min(n, size() - off));
143  }
144 
145  /**
146  * Append a single element.
147  * @param x the element to append
148  */
149  void push_back(T x)
150  {
151  resize(size() + 1);
152  buf[size()-1] = x;
153  }
154 
155  /**
156  * Reset this buffer to an empty buffer with size zero.
157  */
158  void clear() { resize(0); }
159 
160  /**
161  * Inserts or erases elements at the end such that the size
162  * becomes n, leaving elements in the range 0...n unmodified if
163  * set or otherwise zero-initialized
164  * @param n length of the new buffer
165  */
166  void resize(size_t n);
167 
168  /**
169  * Swap this buffer with another object.
170  */
171  void swap(MemoryRegion<T>& other);
172 
173  ~MemoryRegion() { deallocate(buf, allocated); }
174  protected:
175  MemoryRegion() : buf(0), used(0), allocated(0), alloc(0) {}
176 
177  /**
178  * Copy constructor
179  * @param other the other region to copy
180  */
182  buf(0),
183  used(0),
184  allocated(0),
185  alloc(other.alloc)
186  {
187  resize(other.size());
188  copy(&other[0], other.size());
189  }
190 
191  /**
192  * @param locking should we use a locking allocator
193  * @param length the initial length to use
194  */
195  void init(bool locking, size_t length = 0)
196  { alloc = Allocator::get(locking); resize(length); }
197 
198  private:
199  T* allocate(size_t n)
200  {
201  return static_cast<T*>(alloc->allocate(sizeof(T)*n));
202  }
203 
204  void deallocate(T* p, size_t n)
205  { if(alloc && p && n) alloc->deallocate(p, sizeof(T)*n); }
206 
207  T* buf;
208  size_t used;
209  size_t allocated;
210  Allocator* alloc;
211  };
212 
213 /*
214 * Change the size of the buffer
215 */
216 template<typename T>
218  {
219  if(n <= allocated)
220  {
221  size_t zap = std::min(used, n);
222  clear_mem(buf + zap, allocated - zap);
223  used = n;
224  }
225  else
226  {
227  T* new_buf = allocate(n);
228  copy_mem(new_buf, buf, used);
229  deallocate(buf, allocated);
230  buf = new_buf;
231  allocated = used = n;
232  }
233  }
234 
235 /*
236 * Compare this buffer with another one
237 */
238 template<typename T>
240  {
241  const size_t min_size = std::min(size(), other.size());
242 
243  // This should probably be rewritten to run in constant time
244  for(size_t i = 0; i != min_size; ++i)
245  {
246  if(buf[i] < other[i])
247  return true;
248  if(buf[i] > other[i])
249  return false;
250  }
251 
252  // First min_size bytes are equal, shorter is first
253  return (size() < other.size());
254  }
255 
256 /*
257 * Swap this buffer with another one
258 */
259 template<typename T>
261  {
262  std::swap(buf, x.buf);
263  std::swap(used, x.used);
264  std::swap(allocated, x.allocated);
265  std::swap(alloc, x.alloc);
266  }
267 
268 /**
269 * This class represents variable length buffers that do not
270 * make use of memory locking.
271 */
272 template<typename T>
273 class MemoryVector : public MemoryRegion<T>
274  {
275  public:
276  /**
277  * Copy the contents of another buffer into this buffer.
278  * @param in the buffer to copy the contents from
279  * @return reference to *this
280  */
282  {
283  if(this != &in)
284  {
285  this->resize(in.size());
286  this->copy(&in[0], in.size());
287  }
288  return (*this);
289  }
290 
291  /**
292  * Create a buffer of the specified length.
293  * @param n the length of the buffer to create.
294  */
295  MemoryVector(size_t n = 0) { this->init(false, n); }
296 
297  /**
298  * Create a buffer with the specified contents.
299  * @param in the array containing the data to be initially copied
300  * into the newly created buffer
301  * @param n the size of the arry in
302  */
303  MemoryVector(const T in[], size_t n)
304  {
305  this->init(false);
306  this->resize(n);
307  this->copy(in, n);
308  }
309 
310  /**
311  * Copy constructor.
312  */
314  {
315  this->init(false);
316  this->resize(in.size());
317  this->copy(&in[0], in.size());
318  }
319  };
320 
321 /**
322 * This class represents variable length buffers using the operating
323 * systems capability to lock memory, i.e. keeping it from being
324 * swapped out to disk. In this way, a security hole allowing attackers
325 * to find swapped out secret keys is closed.
326 */
327 template<typename T>
328 class SecureVector : public MemoryRegion<T>
329  {
330  public:
331  /**
332  * Copy the contents of another buffer into this buffer.
333  * @param other the buffer to copy the contents from
334  * @return reference to *this
335  */
337  {
338  if(this != &other)
339  {
340  this->resize(other.size());
341  this->copy(&other[0], other.size());
342  }
343  return (*this);
344  }
345 
346  /**
347  * Create a buffer of the specified length.
348  * @param n the length of the buffer to create.
349  */
350  SecureVector(size_t n = 0) { this->init(true, n); }
351 
352  /**
353  * Create a buffer with the specified contents.
354  * @param in the array containing the data to be initially copied
355  * into the newly created buffer
356  * @param n the size of the array in
357  */
358  SecureVector(const T in[], size_t n)
359  {
360  this->init(true);
361  this->resize(n);
362  this->copy(&in[0], n);
363  }
364 
365  /**
366  * Create a buffer with contents specified contents.
367  * @param in the buffer holding the contents that will be
368  * copied into the newly created buffer.
369  */
371  {
372  this->init(true);
373  this->resize(in.size());
374  this->copy(&in[0], in.size());
375  }
376  };
377 
378 #if __cplusplus >= 201103
379 
380 // For better compatability with 2.x API
381  template<typename T>
382  using secure_vector = SecureVector<T>;
383 #endif
384 
385 template<typename T>
387  const MemoryRegion<T>& in)
388  {
389  const size_t copy_offset = out.size();
390  out.resize(out.size() + in.size());
391  copy_mem(&out[copy_offset], &in[0], in.size());
392  return out;
393  }
394 
395 template<typename T>
397  T in)
398  {
399  out.push_back(in);
400  return out;
401  }
402 
403 template<typename T, typename L>
405  const std::pair<const T*, L>& in)
406  {
407  const size_t copy_offset = out.size();
408  out.resize(out.size() + in.second);
409  copy_mem(&out[copy_offset], in.first, in.second);
410  return out;
411  }
412 
413 template<typename T, typename L>
415  const std::pair<T*, L>& in)
416  {
417  const size_t copy_offset = out.size();
418  out.resize(out.size() + in.second);
419  copy_mem(&out[copy_offset], in.first, in.second);
420  return out;
421  }
422 
423 /**
424 * Zeroise the values; length remains unchanged
425 * @param vec the vector to zeroise
426 */
427 template<typename T>
429  {
430  clear_mem(&vec[0], vec.size());
431  }
432 
433 }
434 
435 namespace std {
436 
437 template<typename T>
439  {
440  x.swap(y);
441  }
442 
443 }
444 
445 #endif
void resize(size_t n)
Definition: secmem.h:217
virtual void deallocate(void *ptr, size_t n)=0
bool same_mem(const T *p1, const T *p2, size_t n)
Definition: mem_ops.h:57
SecureVector(const T in[], size_t n)
Definition: secmem.h:358
const T * end() const
Definition: secmem.h:77
virtual void * allocate(size_t n)=0
void clear_mem(T *ptr, size_t n)
Definition: mem_ops.h:32
MemoryRegion< T > & operator=(const MemoryRegion< T > &other)
Definition: secmem.h:109
Definition: secmem.h:435
void push_back(T x)
Definition: secmem.h:149
bool operator==(const MemoryRegion< T > &other) const
Definition: secmem.h:83
static Allocator * get(bool locking)
Definition: defalloc.cpp:90
bool operator!=(const MemoryRegion< T > &other) const
Definition: secmem.h:100
const T * begin() const
Definition: secmem.h:65
void copy(const T in[], size_t n)
Definition: secmem.h:126
void init(bool locking, size_t length=0)
Definition: secmem.h:195
SecureVector< T > & operator=(const MemoryRegion< T > &other)
Definition: secmem.h:336
MemoryVector(size_t n=0)
Definition: secmem.h:295
bool empty() const
Definition: secmem.h:35
MemoryVector(const MemoryRegion< T > &in)
Definition: secmem.h:313
MemoryVector< T > & operator=(const MemoryRegion< T > &in)
Definition: secmem.h:281
SecureVector(size_t n=0)
Definition: secmem.h:350
MemoryVector(const T in[], size_t n)
Definition: secmem.h:303
SecureVector(const MemoryRegion< T > &in)
Definition: secmem.h:370
void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:22
MemoryRegion< T > & operator+=(MemoryRegion< T > &out, const MemoryRegion< T > &in)
Definition: secmem.h:386
size_t size() const
Definition: secmem.h:29
void swap(MemoryRegion< T > &other)
Definition: secmem.h:260
T min(T a, T b)
Definition: ct_utils.h:127
void swap(Botan::MemoryRegion< T > &x, Botan::MemoryRegion< T > &y)
Definition: secmem.h:438
void copy(size_t off, const T in[], size_t n)
Definition: secmem.h:140
MemoryRegion(const MemoryRegion< T > &other)
Definition: secmem.h:181
Allocator * alloc
Definition: bzip2.cpp:29
void zeroise(MemoryRegion< T > &vec)
Definition: secmem.h:428
bool operator<(const MemoryRegion< T > &other) const
Definition: secmem.h:239