Coverage Report

Created: 2023-06-07 06:59

/src/botan/build/include/botan/mem_ops.h
Line
Count
Source (jump to first uncovered line)
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 <span>
14
#include <type_traits>
15
#include <vector>
16
17
namespace Botan {
18
19
/**
20
* Allocate a memory buffer by some method. This should only be used for
21
* primitive types (uint8_t, uint32_t, etc).
22
*
23
* @param elems the number of elements
24
* @param elem_size the size of each element
25
* @return pointer to allocated and zeroed memory, or throw std::bad_alloc on failure
26
*/
27
BOTAN_PUBLIC_API(2, 3) BOTAN_MALLOC_FN void* allocate_memory(size_t elems, size_t elem_size);
28
29
/**
30
* Free a pointer returned by allocate_memory
31
* @param p the pointer returned by allocate_memory
32
* @param elems the number of elements, as passed to allocate_memory
33
* @param elem_size the size of each element, as passed to allocate_memory
34
*/
35
BOTAN_PUBLIC_API(2, 3) void deallocate_memory(void* p, size_t elems, size_t elem_size);
36
37
/**
38
* Ensure the allocator is initialized
39
*/
40
void BOTAN_UNSTABLE_API initialize_allocator();
41
42
class Allocator_Initializer final {
43
   public:
44
0
      Allocator_Initializer() { initialize_allocator(); }
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[], const uint8_t y[], size_t len);
72
73
/**
74
* Memory comparison, input insensitive
75
* @param x a pointer to an array
76
* @param y a pointer to another array
77
* @param len the number of Ts in x and y
78
* @return true iff x[i] == y[i] forall i in [0...n)
79
*/
80
0
inline bool constant_time_compare(const uint8_t x[], const uint8_t y[], size_t len) {
81
0
   return ct_compare_u8(x, y, len) == 0xFF;
82
0
}
83
84
/**
85
* Zero out some bytes. Warning: use secure_scrub_memory instead if the
86
* memory is about to be freed or otherwise the compiler thinks it can
87
* elide the writes.
88
*
89
* @param ptr a pointer to memory to zero
90
* @param bytes the number of bytes to zero in ptr
91
*/
92
27.0k
inline constexpr void clear_bytes(void* ptr, size_t bytes) {
93
27.0k
   if(bytes > 0) {
94
17.6k
      std::memset(ptr, 0, bytes);
95
17.6k
   }
96
27.0k
}
97
98
/**
99
* Zero memory before use. This simply calls memset and should not be
100
* used in cases where the compiler cannot see the call as a
101
* side-effecting operation (for example, if calling clear_mem before
102
* deallocating memory, the compiler would be allowed to omit the call
103
* to memset entirely under the as-if rule.)
104
*
105
* @param ptr a pointer to an array of Ts to zero
106
* @param n the number of Ts pointed to by ptr
107
*/
108
template <typename T>
109
27.0k
inline constexpr void clear_mem(T* ptr, size_t n) {
110
27.0k
   clear_bytes(ptr, sizeof(T) * n);
111
27.0k
}
Unexecuted instantiation: void Botan::clear_mem<unsigned char>(unsigned char*, unsigned long)
void Botan::clear_mem<unsigned long>(unsigned long*, unsigned long)
Line
Count
Source
109
27.0k
inline constexpr void clear_mem(T* ptr, size_t n) {
110
27.0k
   clear_bytes(ptr, sizeof(T) * n);
111
27.0k
}
Unexecuted instantiation: void Botan::clear_mem<unsigned int>(unsigned int*, unsigned long)
112
113
/**
114
* Copy memory
115
* @param out the destination array
116
* @param in the source array
117
* @param n the number of elements of in/out
118
*/
119
template <typename T>
120
inline constexpr void copy_mem(T* out, const T* in, size_t n)
121
   requires std::is_trivial<typename std::decay<T>::type>::value
122
24.3k
{
123
24.3k
   BOTAN_ASSERT_IMPLICATION(n > 0, in != nullptr && out != nullptr, "If n > 0 then args are not null");
124
125
24.3k
   if(in != nullptr && out != nullptr && n > 0) {
126
24.2k
      std::memmove(out, in, sizeof(T) * n);
127
24.2k
   }
128
24.3k
}
129
130
template <typename T>
131
inline constexpr void typecast_copy(uint8_t out[], T in[], size_t N)
132
   requires std::is_trivially_copyable<T>::value
133
0
{
134
0
   std::memcpy(out, in, sizeof(T) * N);
135
0
}
Unexecuted instantiation: void Botan::typecast_copy<unsigned long>(unsigned char*, unsigned long*, unsigned long)
Unexecuted instantiation: void Botan::typecast_copy<unsigned short>(unsigned char*, unsigned short*, unsigned long)
Unexecuted instantiation: void Botan::typecast_copy<unsigned int>(unsigned char*, unsigned int*, unsigned long)
136
137
template <typename T>
138
inline constexpr void typecast_copy(T out[], const uint8_t in[], size_t N)
139
   requires std::is_trivial<T>::value
140
20.9k
{
141
20.9k
   std::memcpy(out, in, sizeof(T) * N);
142
20.9k
}
void Botan::typecast_copy<unsigned long>(unsigned long*, unsigned char const*, unsigned long)
Line
Count
Source
140
20.9k
{
141
20.9k
   std::memcpy(out, in, sizeof(T) * N);
142
20.9k
}
Unexecuted instantiation: void Botan::typecast_copy<unsigned short>(unsigned short*, unsigned char const*, unsigned long)
Unexecuted instantiation: void Botan::typecast_copy<unsigned int>(unsigned int*, unsigned char const*, unsigned long)
143
144
template <typename T>
145
0
inline constexpr void typecast_copy(uint8_t out[], T in) {
146
0
   typecast_copy(out, &in, 1);
147
0
}
Unexecuted instantiation: void Botan::typecast_copy<unsigned long>(unsigned char*, unsigned long)
Unexecuted instantiation: void Botan::typecast_copy<unsigned short>(unsigned char*, unsigned short)
Unexecuted instantiation: void Botan::typecast_copy<unsigned int>(unsigned char*, unsigned int)
148
149
template <typename T>
150
inline constexpr void typecast_copy(T& out, const uint8_t in[])
151
   requires std::is_trivial<typename std::decay<T>::type>::value
152
20.9k
{
153
20.9k
   typecast_copy(&out, in, 1);
154
20.9k
}
void Botan::typecast_copy<unsigned long>(unsigned long&, unsigned char const*)
Line
Count
Source
152
20.9k
{
153
20.9k
   typecast_copy(&out, in, 1);
154
20.9k
}
Unexecuted instantiation: void Botan::typecast_copy<unsigned short>(unsigned short&, unsigned char const*)
Unexecuted instantiation: void Botan::typecast_copy<unsigned int>(unsigned int&, unsigned char const*)
155
156
template <class To, class FromT>
157
inline constexpr To typecast_copy(const FromT* src) noexcept
158
   requires std::is_trivially_copyable<FromT>::value && std::is_trivial<To>::value
159
{
160
   To dst;
161
   std::memcpy(&dst, src, sizeof(To));
162
   return dst;
163
}
164
165
/**
166
* Set memory to a fixed value
167
* @param ptr a pointer to an array of bytes
168
* @param n the number of Ts pointed to by ptr
169
* @param val the value to set each byte to
170
*/
171
0
inline constexpr void set_mem(uint8_t* ptr, size_t n, uint8_t val) {
172
0
   if(n > 0) {
173
0
      std::memset(ptr, val, n);
174
0
   }
175
0
}
176
177
0
inline const uint8_t* cast_char_ptr_to_uint8(const char* s) { return reinterpret_cast<const uint8_t*>(s); }
178
179
0
inline const char* cast_uint8_ptr_to_char(const uint8_t* b) { return reinterpret_cast<const char*>(b); }
180
181
0
inline uint8_t* cast_char_ptr_to_uint8(char* s) { return reinterpret_cast<uint8_t*>(s); }
182
183
0
inline char* cast_uint8_ptr_to_char(uint8_t* b) { return reinterpret_cast<char*>(b); }
184
185
/**
186
* Memory comparison, input insensitive
187
* @param p1 a pointer to an array
188
* @param p2 a pointer to another array
189
* @param n the number of Ts in p1 and p2
190
* @return true iff p1[i] == p2[i] forall i in [0...n)
191
*/
192
template <typename T>
193
inline bool same_mem(const T* p1, const T* p2, size_t n) {
194
   volatile T difference = 0;
195
196
   for(size_t i = 0; i != n; ++i)
197
      difference = difference | (p1[i] ^ p2[i]);
198
199
   return difference == 0;
200
}
201
202
template <typename T, typename Alloc>
203
size_t buffer_insert(std::vector<T, Alloc>& buf, size_t buf_offset, const T input[], size_t input_length) {
204
   BOTAN_ASSERT_NOMSG(buf_offset <= buf.size());
205
   const size_t to_copy = std::min(input_length, buf.size() - buf_offset);
206
   if(to_copy > 0) {
207
      copy_mem(&buf[buf_offset], input, to_copy);
208
   }
209
   return to_copy;
210
}
211
212
template <typename T, typename Alloc, typename Alloc2>
213
size_t buffer_insert(std::vector<T, Alloc>& buf, size_t buf_offset, const std::vector<T, Alloc2>& input) {
214
   BOTAN_ASSERT_NOMSG(buf_offset <= buf.size());
215
   const size_t to_copy = std::min(input.size(), buf.size() - buf_offset);
216
   if(to_copy > 0) {
217
      copy_mem(&buf[buf_offset], input.data(), to_copy);
218
   }
219
   return to_copy;
220
}
221
222
/**
223
* XOR arrays. Postcondition out[i] = in[i] ^ out[i] forall i = 0...length
224
* @param out the input/output buffer
225
* @param in the read-only input buffer
226
* @param length the length of the buffers
227
*/
228
0
inline void xor_buf(uint8_t out[], const uint8_t in[], size_t length) {
229
0
   const size_t blocks = length - (length % 32);
230
0
231
0
   for(size_t i = 0; i != blocks; i += 32) {
232
0
      uint64_t x[4];
233
0
      uint64_t y[4];
234
0
235
0
      typecast_copy(x, out + i, 4);
236
0
      typecast_copy(y, in + i, 4);
237
0
238
0
      x[0] ^= y[0];
239
0
      x[1] ^= y[1];
240
0
      x[2] ^= y[2];
241
0
      x[3] ^= y[3];
242
0
243
0
      typecast_copy(out + i, x, 4);
244
0
   }
245
0
246
0
   for(size_t i = blocks; i != length; ++i) {
247
0
      out[i] ^= in[i];
248
0
   }
249
0
}
250
251
/**
252
* XOR arrays. Postcondition out[i] = in[i] ^ in2[i] forall i = 0...length
253
* @param out the output buffer
254
* @param in the first input buffer
255
* @param in2 the second output buffer
256
* @param length the length of the three buffers
257
*/
258
0
inline void xor_buf(uint8_t out[], const uint8_t in[], const uint8_t in2[], size_t length) {
259
0
   const size_t blocks = length - (length % 32);
260
0
261
0
   for(size_t i = 0; i != blocks; i += 32) {
262
0
      uint64_t x[4];
263
0
      uint64_t y[4];
264
0
265
0
      typecast_copy(x, in + i, 4);
266
0
      typecast_copy(y, in2 + i, 4);
267
0
268
0
      x[0] ^= y[0];
269
0
      x[1] ^= y[1];
270
0
      x[2] ^= y[2];
271
0
      x[3] ^= y[3];
272
0
273
0
      typecast_copy(out + i, x, 4);
274
0
   }
275
0
276
0
   for(size_t i = blocks; i != length; ++i) {
277
0
      out[i] = in[i] ^ in2[i];
278
0
   }
279
0
}
280
281
0
inline void xor_buf(std::span<uint8_t> out, std::span<const uint8_t> in, size_t n) {
282
0
   xor_buf(out.data(), in.data(), n);
283
0
}
284
285
template <typename Alloc>
286
void xor_buf(std::vector<uint8_t, Alloc>& out, const uint8_t* in, size_t n) {
287
   xor_buf(out.data(), in, n);
288
}
289
290
template <typename Alloc, typename Alloc2>
291
void xor_buf(std::vector<uint8_t, Alloc>& out, const uint8_t* in, const std::vector<uint8_t, Alloc2>& in2, size_t n) {
292
   xor_buf(out.data(), in, in2.data(), n);
293
}
294
295
template <typename Alloc, typename Alloc2>
296
std::vector<uint8_t, Alloc>& operator^=(std::vector<uint8_t, Alloc>& out, const std::vector<uint8_t, Alloc2>& in) {
297
   if(out.size() < in.size())
298
      out.resize(in.size());
299
300
   xor_buf(out.data(), in.data(), in.size());
301
   return out;
302
}
303
304
}  // namespace Botan
305
306
#endif