Botan 2.19.2
Crypto and TLS for C&
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
16namespace 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*/
26BOTAN_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*/
34BOTAN_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*/
62BOTAN_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*/
71BOTAN_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*/
82inline 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*/
97inline 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*/
115template<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*/
133template<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
145template<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
151template<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
157template<typename T> inline void typecast_copy(uint8_t out[], T in)
158 {
159 typecast_copy(out, &in, 1);
160 }
161
162template<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
168template <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*/
182inline 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
190inline const uint8_t* cast_char_ptr_to_uint8(const char* s)
191 {
192 return reinterpret_cast<const uint8_t*>(s);
193 }
194
195inline const char* cast_uint8_ptr_to_char(const uint8_t* b)
196 {
197 return reinterpret_cast<const char*>(b);
198 }
199
200inline uint8_t* cast_char_ptr_to_uint8(char* s)
201 {
202 return reinterpret_cast<uint8_t*>(s);
203 }
204
205inline 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*/
217template<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
227template<typename T, typename Alloc>
228size_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
242template<typename T, typename Alloc, typename Alloc2>
243size_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*/
262inline 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*/
297inline 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
326template<typename Alloc, typename Alloc2>
327void 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
334template<typename Alloc>
335void 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
342template<typename Alloc, typename Alloc2>
343void 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
351template<typename Alloc, typename Alloc2>
352std::vector<uint8_t, Alloc>&
353operator^=(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
#define BOTAN_ASSERT_NOMSG(expr)
Definition: assert.h:68
#define BOTAN_ASSERT_IMPLICATION(expr1, expr2, msg)
Definition: assert.h:94
#define BOTAN_PUBLIC_API(maj, min)
Definition: compiler.h:31
#define BOTAN_UNSTABLE_API
Definition: compiler.h:44
#define BOTAN_MALLOC_FN
Definition: compiler.h:100
fe T
Definition: ge.cpp:37
#define BOTAN_IS_TRIVIALLY_COPYABLE(T)
Definition: mem_ops.h:124
Definition: alg_id.cpp:13
void set_mem(uint8_t *ptr, size_t n, uint8_t val)
Definition: mem_ops.h:182
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
BOTAN_MALLOC_FN void * allocate_memory(size_t elems, size_t elem_size)
Definition: mem_ops.cpp:18
void deallocate_memory(void *p, size_t elems, size_t elem_size)
Definition: mem_ops.cpp:34
void secure_scrub_memory(void *ptr, size_t n)
Definition: os_utils.cpp:66
void clear_bytes(void *ptr, size_t bytes)
Definition: mem_ops.h:97
void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:133
bool constant_time_compare(const uint8_t x[], const uint8_t y[], size_t len)
Definition: mem_ops.h:82
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 xor_buf(uint8_t out[], const uint8_t in[], size_t length)
Definition: mem_ops.h:262
void typecast_copy(uint8_t out[], T in[], size_t N)
Definition: mem_ops.h:145
void initialize_allocator()
Definition: mem_ops.cpp:49
bool same_mem(const T *p1, const T *p2, size_t n)
Definition: mem_ops.h:217
const char * cast_uint8_ptr_to_char(const uint8_t *b)
Definition: mem_ops.h:195
void clear_mem(T *ptr, size_t n)
Definition: mem_ops.h:115
const uint8_t * cast_char_ptr_to_uint8(const char *s)
Definition: mem_ops.h:190
MechanismType type