Botan  2.13.0
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
91 * @param ptr a pointer to memory to zero
92 * @param bytes the number of bytes to zero in ptr
93 */
94 inline void clear_bytes(void* ptr, size_t bytes)
95  {
96  if(bytes > 0)
97  {
98  std::memset(ptr, 0, bytes);
99  }
100  }
101 
102 /**
103 * Zero memory before use. This simply calls memset and should not be
104 * used in cases where the compiler cannot see the call as a
105 * side-effecting operation (for example, if calling clear_mem before
106 * deallocating memory, the compiler would be allowed to omit the call
107 * to memset entirely under the as-if rule.)
108 *
109 * @param ptr a pointer to an array of Ts to zero
110 * @param n the number of Ts pointed to by ptr
111 */
112 template<typename T> inline void clear_mem(T* ptr, size_t n)
113  {
114  clear_bytes(ptr, sizeof(T)*n);
115  }
116 
117 
118 
119 // is_trivially_copyable is missing in g++ < 5.0
120 #if !__clang__ && __GNUG__ && __GNUC__ < 5
121 #define BOTAN_IS_TRIVIALLY_COPYABLE(T) true
122 #else
123 #define BOTAN_IS_TRIVIALLY_COPYABLE(T) std::is_trivially_copyable<T>::value
124 #endif
125 
126 /**
127 * Copy memory
128 * @param out the destination array
129 * @param in the source array
130 * @param n the number of elements of in/out
131 */
132 template<typename T> inline void copy_mem(T* out, const T* in, size_t n)
133  {
134  static_assert(std::is_trivial<typename std::decay<T>::type>::value, "");
135  BOTAN_ASSERT_IMPLICATION(n > 0, in != nullptr && out != nullptr,
136  "If n > 0 then args are not null");
137 
138  if(in != nullptr && out != nullptr && n > 0)
139  {
140  std::memmove(out, in, sizeof(T)*n);
141  }
142  }
143 
144 template<typename T> inline void typecast_copy(uint8_t out[], T in[], size_t N)
145  {
146  static_assert(BOTAN_IS_TRIVIALLY_COPYABLE(T), "");
147  std::memcpy(out, in, sizeof(T)*N);
148  }
149 
150 template<typename T> inline void typecast_copy(T out[], const uint8_t in[], size_t N)
151  {
152  static_assert(std::is_trivial<T>::value, "");
153  std::memcpy(out, in, sizeof(T)*N);
154  }
155 
156 template<typename T> inline void typecast_copy(uint8_t out[], T in)
157  {
158  typecast_copy(out, &in, 1);
159  }
160 
161 template<typename T> inline void typecast_copy(T& out, const uint8_t in[])
162  {
163  static_assert(std::is_trivial<typename std::decay<T>::type>::value, "");
164  typecast_copy(&out, in, 1);
165  }
166 
167 template <class To, class From> inline To typecast_copy(const From *src) noexcept
168  {
169  static_assert(BOTAN_IS_TRIVIALLY_COPYABLE(From) && std::is_trivial<To>::value, "");
170  To dst;
171  std::memcpy(&dst, src, sizeof(To));
172  return dst;
173  }
174 
175 /**
176 * Set memory to a fixed value
177 * @param ptr a pointer to an array of bytes
178 * @param n the number of Ts pointed to by ptr
179 * @param val the value to set each byte to
180 */
181 inline void set_mem(uint8_t* ptr, size_t n, uint8_t val)
182  {
183  if(n > 0)
184  {
185  std::memset(ptr, val, n);
186  }
187  }
188 
189 inline const uint8_t* cast_char_ptr_to_uint8(const char* s)
190  {
191  return reinterpret_cast<const uint8_t*>(s);
192  }
193 
194 inline const char* cast_uint8_ptr_to_char(const uint8_t* b)
195  {
196  return reinterpret_cast<const char*>(b);
197  }
198 
199 inline uint8_t* cast_char_ptr_to_uint8(char* s)
200  {
201  return reinterpret_cast<uint8_t*>(s);
202  }
203 
204 inline char* cast_uint8_ptr_to_char(uint8_t* b)
205  {
206  return reinterpret_cast<char*>(b);
207  }
208 
209 /**
210 * Memory comparison, input insensitive
211 * @param p1 a pointer to an array
212 * @param p2 a pointer to another array
213 * @param n the number of Ts in p1 and p2
214 * @return true iff p1[i] == p2[i] forall i in [0...n)
215 */
216 template<typename T> inline bool same_mem(const T* p1, const T* p2, size_t n)
217  {
218  volatile T difference = 0;
219 
220  for(size_t i = 0; i != n; ++i)
221  difference |= (p1[i] ^ p2[i]);
222 
223  return difference == 0;
224  }
225 
226 /**
227 * XOR arrays. Postcondition out[i] = in[i] ^ out[i] forall i = 0...length
228 * @param out the input/output buffer
229 * @param in the read-only input buffer
230 * @param length the length of the buffers
231 */
232 inline void xor_buf(uint8_t out[],
233  const uint8_t in[],
234  size_t length)
235  {
236  const size_t blocks = length - (length % 32);
237 
238  for(size_t i = 0; i != blocks; i += 32)
239  {
240  uint64_t x[4];
241  uint64_t y[4];
242 
243  typecast_copy(x, out + i, 4);
244  typecast_copy(y, in + i, 4);
245 
246  x[0] ^= y[0];
247  x[1] ^= y[1];
248  x[2] ^= y[2];
249  x[3] ^= y[3];
250 
251  typecast_copy(out + i, x, 4);
252  }
253 
254  for(size_t i = blocks; i != length; ++i)
255  {
256  out[i] ^= in[i];
257  }
258  }
259 
260 /**
261 * XOR arrays. Postcondition out[i] = in[i] ^ in2[i] forall i = 0...length
262 * @param out the output buffer
263 * @param in the first input buffer
264 * @param in2 the second output buffer
265 * @param length the length of the three buffers
266 */
267 inline void xor_buf(uint8_t out[],
268  const uint8_t in[],
269  const uint8_t in2[],
270  size_t length)
271  {
272  const size_t blocks = length - (length % 32);
273 
274  for(size_t i = 0; i != blocks; i += 32)
275  {
276  uint64_t x[4];
277  uint64_t y[4];
278 
279  typecast_copy(x, in + i, 4);
280  typecast_copy(y, in2 + i, 4);
281 
282  x[0] ^= y[0];
283  x[1] ^= y[1];
284  x[2] ^= y[2];
285  x[3] ^= y[3];
286 
287  typecast_copy(out + i, x, 4);
288  }
289 
290  for(size_t i = blocks; i != length; ++i)
291  {
292  out[i] = in[i] ^ in2[i];
293  }
294  }
295 
296 template<typename Alloc, typename Alloc2>
297 void xor_buf(std::vector<uint8_t, Alloc>& out,
298  const std::vector<uint8_t, Alloc2>& in,
299  size_t n)
300  {
301  xor_buf(out.data(), in.data(), n);
302  }
303 
304 template<typename Alloc>
305 void xor_buf(std::vector<uint8_t, Alloc>& out,
306  const uint8_t* in,
307  size_t n)
308  {
309  xor_buf(out.data(), in, n);
310  }
311 
312 template<typename Alloc, typename Alloc2>
313 void xor_buf(std::vector<uint8_t, Alloc>& out,
314  const uint8_t* in,
315  const std::vector<uint8_t, Alloc2>& in2,
316  size_t n)
317  {
318  xor_buf(out.data(), in, in2.data(), n);
319  }
320 
321 template<typename Alloc, typename Alloc2>
322 std::vector<uint8_t, Alloc>&
323 operator^=(std::vector<uint8_t, Alloc>& out,
324  const std::vector<uint8_t, Alloc2>& in)
325  {
326  if(out.size() < in.size())
327  out.resize(in.size());
328 
329  xor_buf(out.data(), in.data(), in.size());
330  return out;
331  }
332 
333 }
334 
335 #endif
void clear_bytes(void *ptr, size_t bytes)
Definition: mem_ops.h:94
bool same_mem(const T *p1, const T *p2, size_t n)
Definition: mem_ops.h:216
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:112
void set_mem(uint8_t *ptr, size_t n, uint8_t val)
Definition: mem_ops.h:181
#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:189
bool constant_time_compare(const uint8_t x[], const uint8_t y[], size_t len)
Definition: mem_ops.h:82
MechanismType type
void typecast_copy(uint8_t out[], T in[], size_t N)
Definition: mem_ops.h:144
#define BOTAN_MALLOC_FN
Definition: compiler.h:94
void xor_buf(uint8_t out[], const uint8_t in[], size_t length)
Definition: mem_ops.h:232
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:323
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:132
Definition: alg_id.cpp:13
#define BOTAN_IS_TRIVIALLY_COPYABLE(T)
Definition: mem_ops.h:123
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:194
#define BOTAN_ASSERT_IMPLICATION(expr1, expr2, msg)
Definition: assert.h:94
fe T
Definition: ge.cpp:37
void initialize_allocator()
Definition: mem_ops.cpp:49