Botan 3.0.0
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 constexpr 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 constexpr void clear_mem(T* ptr, size_t n)
116 {
117 clear_bytes(ptr, sizeof(T)*n);
118 }
119
120/**
121* Copy memory
122* @param out the destination array
123* @param in the source array
124* @param n the number of elements of in/out
125*/
126template<typename T> inline constexpr void copy_mem(T* out, const T* in, size_t n)
127 requires std::is_trivial<typename std::decay<T>::type>::value
128 {
129 BOTAN_ASSERT_IMPLICATION(n > 0, in != nullptr && out != nullptr,
130 "If n > 0 then args are not null");
131
132 if(in != nullptr && out != nullptr && n > 0)
133 {
134 std::memmove(out, in, sizeof(T)*n);
135 }
136 }
137
138template<typename T> inline constexpr void typecast_copy(uint8_t out[], T in[], size_t N)
139 requires std::is_trivially_copyable<T>::value
140 {
141 std::memcpy(out, in, sizeof(T)*N);
142 }
143
144template<typename T> inline constexpr void typecast_copy(T out[], const uint8_t in[], size_t N)
145 requires std::is_trivial<T>::value
146 {
147 std::memcpy(out, in, sizeof(T)*N);
148 }
149
150template<typename T> inline constexpr void typecast_copy(uint8_t out[], T in)
151 {
152 typecast_copy(out, &in, 1);
153 }
154
155template<typename T> inline constexpr void typecast_copy(T& out, const uint8_t in[])
156 requires std::is_trivial<typename std::decay<T>::type>::value
157 {
158 typecast_copy(&out, in, 1);
159 }
160
161template <class To, class FromT> inline constexpr To typecast_copy(const FromT *src) noexcept
162 requires std::is_trivially_copyable<FromT>::value && std::is_trivial<To>::value
163 {
164 To dst;
165 std::memcpy(&dst, src, sizeof(To));
166 return dst;
167 }
168
169/**
170* Set memory to a fixed value
171* @param ptr a pointer to an array of bytes
172* @param n the number of Ts pointed to by ptr
173* @param val the value to set each byte to
174*/
175inline constexpr void set_mem(uint8_t* ptr, size_t n, uint8_t val)
176 {
177 if(n > 0)
178 {
179 std::memset(ptr, val, n);
180 }
181 }
182
183inline const uint8_t* cast_char_ptr_to_uint8(const char* s)
184 {
185 return reinterpret_cast<const uint8_t*>(s);
186 }
187
188inline const char* cast_uint8_ptr_to_char(const uint8_t* b)
189 {
190 return reinterpret_cast<const char*>(b);
191 }
192
193inline uint8_t* cast_char_ptr_to_uint8(char* s)
194 {
195 return reinterpret_cast<uint8_t*>(s);
196 }
197
198inline char* cast_uint8_ptr_to_char(uint8_t* b)
199 {
200 return reinterpret_cast<char*>(b);
201 }
202
203/**
204* Memory comparison, input insensitive
205* @param p1 a pointer to an array
206* @param p2 a pointer to another array
207* @param n the number of Ts in p1 and p2
208* @return true iff p1[i] == p2[i] forall i in [0...n)
209*/
210template<typename T> inline bool same_mem(const T* p1, const T* p2, size_t n)
211 {
212 volatile T difference = 0;
213
214 for(size_t i = 0; i != n; ++i)
215 difference = difference | (p1[i] ^ p2[i]);
216
217 return difference == 0;
218 }
219
220template<typename T, typename Alloc>
221size_t buffer_insert(std::vector<T, Alloc>& buf,
222 size_t buf_offset,
223 const T input[],
224 size_t input_length)
225 {
226 BOTAN_ASSERT_NOMSG(buf_offset <= buf.size());
227 const size_t to_copy = std::min(input_length, buf.size() - buf_offset);
228 if(to_copy > 0)
229 {
230 copy_mem(&buf[buf_offset], input, to_copy);
231 }
232 return to_copy;
233 }
234
235template<typename T, typename Alloc, typename Alloc2>
236size_t buffer_insert(std::vector<T, Alloc>& buf,
237 size_t buf_offset,
238 const std::vector<T, Alloc2>& input)
239 {
240 BOTAN_ASSERT_NOMSG(buf_offset <= buf.size());
241 const size_t to_copy = std::min(input.size(), buf.size() - buf_offset);
242 if(to_copy > 0)
243 {
244 copy_mem(&buf[buf_offset], input.data(), to_copy);
245 }
246 return to_copy;
247 }
248
249/**
250* XOR arrays. Postcondition out[i] = in[i] ^ out[i] forall i = 0...length
251* @param out the input/output buffer
252* @param in the read-only input buffer
253* @param length the length of the buffers
254*/
255inline void xor_buf(uint8_t out[],
256 const uint8_t in[],
257 size_t length)
258 {
259 const size_t blocks = length - (length % 32);
260
261 for(size_t i = 0; i != blocks; i += 32)
262 {
263 uint64_t x[4];
264 uint64_t y[4];
265
266 typecast_copy(x, out + i, 4);
267 typecast_copy(y, in + i, 4);
268
269 x[0] ^= y[0];
270 x[1] ^= y[1];
271 x[2] ^= y[2];
272 x[3] ^= y[3];
273
274 typecast_copy(out + i, x, 4);
275 }
276
277 for(size_t i = blocks; i != length; ++i)
278 {
279 out[i] ^= in[i];
280 }
281 }
282
283/**
284* XOR arrays. Postcondition out[i] = in[i] ^ in2[i] forall i = 0...length
285* @param out the output buffer
286* @param in the first input buffer
287* @param in2 the second output buffer
288* @param length the length of the three buffers
289*/
290inline void xor_buf(uint8_t out[],
291 const uint8_t in[],
292 const uint8_t in2[],
293 size_t length)
294 {
295 const size_t blocks = length - (length % 32);
296
297 for(size_t i = 0; i != blocks; i += 32)
298 {
299 uint64_t x[4];
300 uint64_t y[4];
301
302 typecast_copy(x, in + i, 4);
303 typecast_copy(y, in2 + i, 4);
304
305 x[0] ^= y[0];
306 x[1] ^= y[1];
307 x[2] ^= y[2];
308 x[3] ^= y[3];
309
310 typecast_copy(out + i, x, 4);
311 }
312
313 for(size_t i = blocks; i != length; ++i)
314 {
315 out[i] = in[i] ^ in2[i];
316 }
317 }
318
319template<typename Alloc, typename Alloc2>
320void xor_buf(std::vector<uint8_t, Alloc>& out,
321 const std::vector<uint8_t, Alloc2>& in,
322 size_t n)
323 {
324 xor_buf(out.data(), in.data(), n);
325 }
326
327template<typename Alloc>
328void xor_buf(std::vector<uint8_t, Alloc>& out,
329 const uint8_t* in,
330 size_t n)
331 {
332 xor_buf(out.data(), in, n);
333 }
334
335template<typename Alloc, typename Alloc2>
336void xor_buf(std::vector<uint8_t, Alloc>& out,
337 const uint8_t* in,
338 const std::vector<uint8_t, Alloc2>& in2,
339 size_t n)
340 {
341 xor_buf(out.data(), in, in2.data(), n);
342 }
343
344template<typename Alloc, typename Alloc2>
345std::vector<uint8_t, Alloc>&
346operator^=(std::vector<uint8_t, Alloc>& out,
347 const std::vector<uint8_t, Alloc2>& in)
348 {
349 if(out.size() < in.size())
350 out.resize(in.size());
351
352 xor_buf(out.data(), in.data(), in.size());
353 return out;
354 }
355
356}
357
358#endif
static SIMD_4x64 y
#define BOTAN_ASSERT_NOMSG(expr)
Definition: assert.h:67
#define BOTAN_ASSERT_IMPLICATION(expr1, expr2, msg)
Definition: assert.h:93
int(* final)(unsigned char *, CTX *)
#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:103
FE_25519 T
Definition: ge.cpp:36
Definition: alg_id.cpp:12
size_t buffer_insert(std::vector< T, Alloc > &buf, size_t buf_offset, const T input[], size_t input_length)
Definition: mem_ops.h:221
BOTAN_MALLOC_FN void * allocate_memory(size_t elems, size_t elem_size)
Definition: mem_ops.cpp:19
void deallocate_memory(void *p, size_t elems, size_t elem_size)
Definition: mem_ops.cpp:44
constexpr void clear_bytes(void *ptr, size_t bytes)
Definition: mem_ops.h:97
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:126
void secure_scrub_memory(void *ptr, size_t n)
Definition: os_utils.cpp:81
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:66
std::vector< uint8_t, Alloc > & operator^=(std::vector< uint8_t, Alloc > &out, const std::vector< uint8_t, Alloc2 > &in)
Definition: mem_ops.h:346
void xor_buf(uint8_t out[], const uint8_t in[], size_t length)
Definition: mem_ops.h:255
void initialize_allocator()
Definition: mem_ops.cpp:59
bool same_mem(const T *p1, const T *p2, size_t n)
Definition: mem_ops.h:210
const char * cast_uint8_ptr_to_char(const uint8_t *b)
Definition: mem_ops.h:188
constexpr void typecast_copy(T &out, const uint8_t in[])
Definition: mem_ops.h:155
constexpr 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:183