Botan  2.18.1
Crypto and TLS for C++11
mem_ops.h
Go to the documentation of this file.
1 /*
2 * Memory Operations
3 * (C) 1999-2009,2012,2015 Jack Lloyd
4 *
5 * Botan is released under the Simplified BSD License (see license.txt)
6 */
7 
8 #ifndef BOTAN_MEMORY_OPS_H_
9 #define BOTAN_MEMORY_OPS_H_
10 
11 #include <botan/types.h>
12 #include <cstring>
13 #include <type_traits>
14 #include <vector>
15 
16 namespace Botan {
17 
18 /**
19 * Allocate a memory buffer by some method. This should only be used for
20 * primitive types (uint8_t, uint32_t, etc).
21 *
22 * @param elems the number of elements
23 * @param elem_size the size of each element
24 * @return pointer to allocated and zeroed memory, or throw std::bad_alloc on failure
25 */
26 BOTAN_PUBLIC_API(2,3) BOTAN_MALLOC_FN void* allocate_memory(size_t elems, size_t elem_size);
27 
28 /**
29 * Free a pointer returned by allocate_memory
30 * @param p the pointer returned by allocate_memory
31 * @param elems the number of elements, as passed to allocate_memory
32 * @param elem_size the size of each element, as passed to allocate_memory
33 */
34 BOTAN_PUBLIC_API(2,3) void deallocate_memory(void* p, size_t elems, size_t elem_size);
35 
36 /**
37 * Ensure the allocator is initialized
38 */
40 
42  {
43  public:
45  };
46 
47 /**
48 * Scrub memory contents in a way that a compiler should not elide,
49 * using some system specific technique. Note that this function might
50 * not zero the memory (for example, in some hypothetical
51 * implementation it might combine the memory contents with the output
52 * of a system PRNG), but if you can detect any difference in behavior
53 * at runtime then the clearing is side-effecting and you can just
54 * use `clear_mem`.
55 *
56 * Use this function to scrub memory just before deallocating it, or on
57 * a stack buffer before returning from the function.
58 *
59 * @param ptr a pointer to memory to scrub
60 * @param n the number of bytes pointed to by ptr
61 */
62 BOTAN_PUBLIC_API(2,0) void secure_scrub_memory(void* ptr, size_t n);
63 
64 /**
65 * Memory comparison, input insensitive
66 * @param x a pointer to an array
67 * @param y a pointer to another array
68 * @param len the number of Ts in x and y
69 * @return 0xFF iff x[i] == y[i] forall i in [0...n) or 0x00 otherwise
70 */
71 BOTAN_PUBLIC_API(2,9) uint8_t ct_compare_u8(const uint8_t x[],
72  const uint8_t y[],
73  size_t len);
74 
75 /**
76 * Memory comparison, input insensitive
77 * @param x a pointer to an array
78 * @param y a pointer to another array
79 * @param len the number of Ts in x and y
80 * @return true iff x[i] == y[i] forall i in [0...n)
81 */
82 inline bool constant_time_compare(const uint8_t x[],
83  const uint8_t y[],
84  size_t len)
85  {
86  return ct_compare_u8(x, y, len) == 0xFF;
87  }
88 
89 /**
90 * Zero out some bytes. Warning: use secure_scrub_memory instead if the
91 * memory is about to be freed or otherwise the compiler thinks it can
92 * elide the writes.
93 *
94 * @param ptr a pointer to memory to zero
95 * @param bytes the number of bytes to zero in ptr
96 */
97 inline void clear_bytes(void* ptr, size_t bytes)
98  {
99  if(bytes > 0)
100  {
101  std::memset(ptr, 0, bytes);
102  }
103  }
104 
105 /**
106 * Zero memory before use. This simply calls memset and should not be
107 * used in cases where the compiler cannot see the call as a
108 * side-effecting operation (for example, if calling clear_mem before
109 * deallocating memory, the compiler would be allowed to omit the call
110 * to memset entirely under the as-if rule.)
111 *
112 * @param ptr a pointer to an array of Ts to zero
113 * @param n the number of Ts pointed to by ptr
114 */
115 template<typename T> inline void clear_mem(T* ptr, size_t n)
116  {
117  clear_bytes(ptr, sizeof(T)*n);
118  }
119 
120 // is_trivially_copyable is missing in g++ < 5.0
121 #if (BOTAN_GCC_VERSION > 0 && BOTAN_GCC_VERSION < 500)
122 #define BOTAN_IS_TRIVIALLY_COPYABLE(T) true
123 #else
124 #define BOTAN_IS_TRIVIALLY_COPYABLE(T) std::is_trivially_copyable<T>::value
125 #endif
126 
127 /**
128 * Copy memory
129 * @param out the destination array
130 * @param in the source array
131 * @param n the number of elements of in/out
132 */
133 template<typename T> inline void copy_mem(T* out, const T* in, size_t n)
134  {
135  static_assert(std::is_trivial<typename std::decay<T>::type>::value, "");
136  BOTAN_ASSERT_IMPLICATION(n > 0, in != nullptr && out != nullptr,
137  "If n > 0 then args are not null");
138 
139  if(in != nullptr && out != nullptr && n > 0)
140  {
141  std::memmove(out, in, sizeof(T)*n);
142  }
143  }
144 
145 template<typename T> inline void typecast_copy(uint8_t out[], T in[], size_t N)
146  {
147  static_assert(BOTAN_IS_TRIVIALLY_COPYABLE(T), "");
148  std::memcpy(out, in, sizeof(T)*N);
149  }
150 
151 template<typename T> inline void typecast_copy(T out[], const uint8_t in[], size_t N)
152  {
153  static_assert(std::is_trivial<T>::value, "");
154  std::memcpy(out, in, sizeof(T)*N);
155  }
156 
157 template<typename T> inline void typecast_copy(uint8_t out[], T in)
158  {
159  typecast_copy(out, &in, 1);
160  }
161 
162 template<typename T> inline void typecast_copy(T& out, const uint8_t in[])
163  {
164  static_assert(std::is_trivial<typename std::decay<T>::type>::value, "");
165  typecast_copy(&out, in, 1);
166  }
167 
168 template <class To, class From> inline To typecast_copy(const From *src) noexcept
169  {
170  static_assert(BOTAN_IS_TRIVIALLY_COPYABLE(From) && std::is_trivial<To>::value, "");
171  To dst;
172  std::memcpy(&dst, src, sizeof(To));
173  return dst;
174  }
175 
176 /**
177 * Set memory to a fixed value
178 * @param ptr a pointer to an array of bytes
179 * @param n the number of Ts pointed to by ptr
180 * @param val the value to set each byte to
181 */
182 inline void set_mem(uint8_t* ptr, size_t n, uint8_t val)
183  {
184  if(n > 0)
185  {
186  std::memset(ptr, val, n);
187  }
188  }
189 
190 inline const uint8_t* cast_char_ptr_to_uint8(const char* s)
191  {
192  return reinterpret_cast<const uint8_t*>(s);
193  }
194 
195 inline const char* cast_uint8_ptr_to_char(const uint8_t* b)
196  {
197  return reinterpret_cast<const char*>(b);
198  }
199 
200 inline uint8_t* cast_char_ptr_to_uint8(char* s)
201  {
202  return reinterpret_cast<uint8_t*>(s);
203  }
204 
205 inline char* cast_uint8_ptr_to_char(uint8_t* b)
206  {
207  return reinterpret_cast<char*>(b);
208  }
209 
210 /**
211 * Memory comparison, input insensitive
212 * @param p1 a pointer to an array
213 * @param p2 a pointer to another array
214 * @param n the number of Ts in p1 and p2
215 * @return true iff p1[i] == p2[i] forall i in [0...n)
216 */
217 template<typename T> inline bool same_mem(const T* p1, const T* p2, size_t n)
218  {
219  volatile T difference = 0;
220 
221  for(size_t i = 0; i != n; ++i)
222  difference |= (p1[i] ^ p2[i]);
223 
224  return difference == 0;
225  }
226 
227 template<typename T, typename Alloc>
228 size_t buffer_insert(std::vector<T, Alloc>& buf,
229  size_t buf_offset,
230  const T input[],
231  size_t input_length)
232  {
233  BOTAN_ASSERT_NOMSG(buf_offset <= buf.size());
234  const size_t to_copy = std::min(input_length, buf.size() - buf_offset);
235  if(to_copy > 0)
236  {
237  copy_mem(&buf[buf_offset], input, to_copy);
238  }
239  return to_copy;
240  }
241 
242 template<typename T, typename Alloc, typename Alloc2>
243 size_t buffer_insert(std::vector<T, Alloc>& buf,
244  size_t buf_offset,
245  const std::vector<T, Alloc2>& input)
246  {
247  BOTAN_ASSERT_NOMSG(buf_offset <= buf.size());
248  const size_t to_copy = std::min(input.size(), buf.size() - buf_offset);
249  if(to_copy > 0)
250  {
251  copy_mem(&buf[buf_offset], input.data(), to_copy);
252  }
253  return to_copy;
254  }
255 
256 /**
257 * XOR arrays. Postcondition out[i] = in[i] ^ out[i] forall i = 0...length
258 * @param out the input/output buffer
259 * @param in the read-only input buffer
260 * @param length the length of the buffers
261 */
262 inline void xor_buf(uint8_t out[],
263  const uint8_t in[],
264  size_t length)
265  {
266  const size_t blocks = length - (length % 32);
267 
268  for(size_t i = 0; i != blocks; i += 32)
269  {
270  uint64_t x[4];
271  uint64_t y[4];
272 
273  typecast_copy(x, out + i, 4);
274  typecast_copy(y, in + i, 4);
275 
276  x[0] ^= y[0];
277  x[1] ^= y[1];
278  x[2] ^= y[2];
279  x[3] ^= y[3];
280 
281  typecast_copy(out + i, x, 4);
282  }
283 
284  for(size_t i = blocks; i != length; ++i)
285  {
286  out[i] ^= in[i];
287  }
288  }
289 
290 /**
291 * XOR arrays. Postcondition out[i] = in[i] ^ in2[i] forall i = 0...length
292 * @param out the output buffer
293 * @param in the first input buffer
294 * @param in2 the second output buffer
295 * @param length the length of the three buffers
296 */
297 inline void xor_buf(uint8_t out[],
298  const uint8_t in[],
299  const uint8_t in2[],
300  size_t length)
301  {
302  const size_t blocks = length - (length % 32);
303 
304  for(size_t i = 0; i != blocks; i += 32)
305  {
306  uint64_t x[4];
307  uint64_t y[4];
308 
309  typecast_copy(x, in + i, 4);
310  typecast_copy(y, in2 + i, 4);
311 
312  x[0] ^= y[0];
313  x[1] ^= y[1];
314  x[2] ^= y[2];
315  x[3] ^= y[3];
316 
317  typecast_copy(out + i, x, 4);
318  }
319 
320  for(size_t i = blocks; i != length; ++i)
321  {
322  out[i] = in[i] ^ in2[i];
323  }
324  }
325 
326 template<typename Alloc, typename Alloc2>
327 void xor_buf(std::vector<uint8_t, Alloc>& out,
328  const std::vector<uint8_t, Alloc2>& in,
329  size_t n)
330  {
331  xor_buf(out.data(), in.data(), n);
332  }
333 
334 template<typename Alloc>
335 void xor_buf(std::vector<uint8_t, Alloc>& out,
336  const uint8_t* in,
337  size_t n)
338  {
339  xor_buf(out.data(), in, n);
340  }
341 
342 template<typename Alloc, typename Alloc2>
343 void xor_buf(std::vector<uint8_t, Alloc>& out,
344  const uint8_t* in,
345  const std::vector<uint8_t, Alloc2>& in2,
346  size_t n)
347  {
348  xor_buf(out.data(), in, in2.data(), n);
349  }
350 
351 template<typename Alloc, typename Alloc2>
352 std::vector<uint8_t, Alloc>&
353 operator^=(std::vector<uint8_t, Alloc>& out,
354  const std::vector<uint8_t, Alloc2>& in)
355  {
356  if(out.size() < in.size())
357  out.resize(in.size());
358 
359  xor_buf(out.data(), in.data(), in.size());
360  return out;
361  }
362 
363 }
364 
365 #endif
void clear_bytes(void *ptr, size_t bytes)
Definition: mem_ops.h:97
#define BOTAN_UNSTABLE_API
Definition: compiler.h:44
bool same_mem(const T *p1, const T *p2, size_t n)
Definition: mem_ops.h:217
BOTAN_MALLOC_FN void * allocate_memory(size_t elems, size_t elem_size)
Definition: mem_ops.cpp:18
void clear_mem(T *ptr, size_t n)
Definition: mem_ops.h:115
void set_mem(uint8_t *ptr, size_t n, uint8_t val)
Definition: mem_ops.h:182
#define BOTAN_PUBLIC_API(maj, min)
Definition: compiler.h:31
const uint8_t * cast_char_ptr_to_uint8(const char *s)
Definition: mem_ops.h:190
bool constant_time_compare(const uint8_t x[], const uint8_t y[], size_t len)
Definition: mem_ops.h:82
#define BOTAN_ASSERT_NOMSG(expr)
Definition: assert.h:68
MechanismType type
void initialize_allocator()
Definition: mem_ops.cpp:49
void typecast_copy(uint8_t out[], T in[], size_t N)
Definition: mem_ops.h:145
#define BOTAN_MALLOC_FN
Definition: compiler.h:100
void xor_buf(uint8_t out[], const uint8_t in[], size_t length)
Definition: mem_ops.h:262
uint8_t ct_compare_u8(const uint8_t x[], const uint8_t y[], size_t len)
Definition: mem_ops.cpp:56
std::vector< uint8_t, Alloc > & operator^=(std::vector< uint8_t, Alloc > &out, const std::vector< uint8_t, Alloc2 > &in)
Definition: mem_ops.h:353
void deallocate_memory(void *p, size_t elems, size_t elem_size)
Definition: mem_ops.cpp:34
void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:133
Definition: alg_id.cpp:13
#define BOTAN_IS_TRIVIALLY_COPYABLE(T)
Definition: mem_ops.h:124
void secure_scrub_memory(void *ptr, size_t n)
Definition: os_utils.cpp:66
const char * cast_uint8_ptr_to_char(const uint8_t *b)
Definition: mem_ops.h:195
size_t buffer_insert(std::vector< T, Alloc > &buf, size_t buf_offset, const T input[], size_t input_length)
Definition: mem_ops.h:228
#define BOTAN_ASSERT_IMPLICATION(expr1, expr2, msg)
Definition: assert.h:94
fe T
Definition: ge.cpp:37