Coverage Report

Created: 2023-06-07 07:00

/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
1
      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
146M
inline constexpr void clear_bytes(void* ptr, size_t bytes) {
93
146M
   if(bytes > 0) {
94
146M
      std::memset(ptr, 0, bytes);
95
146M
   }
96
146M
}
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
146M
inline constexpr void clear_mem(T* ptr, size_t n) {
110
146M
   clear_bytes(ptr, sizeof(T) * n);
111
146M
}
void Botan::clear_mem<unsigned char>(unsigned char*, unsigned long)
Line
Count
Source
109
25
inline constexpr void clear_mem(T* ptr, size_t n) {
110
25
   clear_bytes(ptr, sizeof(T) * n);
111
25
}
void Botan::clear_mem<unsigned long>(unsigned long*, unsigned long)
Line
Count
Source
109
146M
inline constexpr void clear_mem(T* ptr, size_t n) {
110
146M
   clear_bytes(ptr, sizeof(T) * n);
111
146M
}
void Botan::clear_mem<unsigned int>(unsigned int*, unsigned long)
Line
Count
Source
109
1
inline constexpr void clear_mem(T* ptr, size_t n) {
110
1
   clear_bytes(ptr, sizeof(T) * n);
111
1
}
Unexecuted instantiation: void Botan::clear_mem<unsigned short>(unsigned short*, 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
1.53M
{
123
1.53M
   BOTAN_ASSERT_IMPLICATION(n > 0, in != nullptr && out != nullptr, "If n > 0 then args are not null");
124
125
1.53M
   if(in != nullptr && out != nullptr && n > 0) {
126
1.51M
      std::memmove(out, in, sizeof(T) * n);
127
1.51M
   }
128
1.53M
}
void Botan::copy_mem<unsigned long>(unsigned long*, unsigned long const*, unsigned long)
Line
Count
Source
122
1.43M
{
123
1.43M
   BOTAN_ASSERT_IMPLICATION(n > 0, in != nullptr && out != nullptr, "If n > 0 then args are not null");
124
125
1.43M
   if(in != nullptr && out != nullptr && n > 0) {
126
1.42M
      std::memmove(out, in, sizeof(T) * n);
127
1.42M
   }
128
1.43M
}
void Botan::copy_mem<unsigned char>(unsigned char*, unsigned char const*, unsigned long)
Line
Count
Source
122
101k
{
123
101k
   BOTAN_ASSERT_IMPLICATION(n > 0, in != nullptr && out != nullptr, "If n > 0 then args are not null");
124
125
101k
   if(in != nullptr && out != nullptr && n > 0) {
126
99.6k
      std::memmove(out, in, sizeof(T) * n);
127
99.6k
   }
128
101k
}
Unexecuted instantiation: void Botan::copy_mem<unsigned int>(unsigned int*, unsigned int const*, unsigned long)
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
36
{
134
36
   std::memcpy(out, in, sizeof(T) * N);
135
36
}
void Botan::typecast_copy<unsigned long>(unsigned char*, unsigned long*, unsigned long)
Line
Count
Source
133
4
{
134
4
   std::memcpy(out, in, sizeof(T) * N);
135
4
}
Unexecuted instantiation: void Botan::typecast_copy<unsigned short>(unsigned char*, unsigned short*, unsigned long)
void Botan::typecast_copy<unsigned int>(unsigned char*, unsigned int*, unsigned long)
Line
Count
Source
133
32
{
134
32
   std::memcpy(out, in, sizeof(T) * N);
135
32
}
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
531k
{
141
531k
   std::memcpy(out, in, sizeof(T) * N);
142
531k
}
void Botan::typecast_copy<unsigned long>(unsigned long*, unsigned char const*, unsigned long)
Line
Count
Source
140
531k
{
141
531k
   std::memcpy(out, in, sizeof(T) * N);
142
531k
}
Unexecuted instantiation: void Botan::typecast_copy<unsigned short>(unsigned short*, unsigned char const*, unsigned long)
void Botan::typecast_copy<unsigned int>(unsigned int*, unsigned char const*, unsigned long)
Line
Count
Source
140
162
{
141
162
   std::memcpy(out, in, sizeof(T) * N);
142
162
}
143
144
template <typename T>
145
36
inline constexpr void typecast_copy(uint8_t out[], T in) {
146
36
   typecast_copy(out, &in, 1);
147
36
}
void Botan::typecast_copy<unsigned long>(unsigned char*, unsigned long)
Line
Count
Source
145
4
inline constexpr void typecast_copy(uint8_t out[], T in) {
146
4
   typecast_copy(out, &in, 1);
147
4
}
Unexecuted instantiation: void Botan::typecast_copy<unsigned short>(unsigned char*, unsigned short)
void Botan::typecast_copy<unsigned int>(unsigned char*, unsigned int)
Line
Count
Source
145
32
inline constexpr void typecast_copy(uint8_t out[], T in) {
146
32
   typecast_copy(out, &in, 1);
147
32
}
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
531k
{
153
531k
   typecast_copy(&out, in, 1);
154
531k
}
void Botan::typecast_copy<unsigned long>(unsigned long&, unsigned char const*)
Line
Count
Source
152
531k
{
153
531k
   typecast_copy(&out, in, 1);
154
531k
}
Unexecuted instantiation: void Botan::typecast_copy<unsigned short>(unsigned short&, unsigned char const*)
void Botan::typecast_copy<unsigned int>(unsigned int&, unsigned char const*)
Line
Count
Source
152
160
{
153
160
   typecast_copy(&out, in, 1);
154
160
}
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
10
inline const uint8_t* cast_char_ptr_to_uint8(const char* s) { return reinterpret_cast<const uint8_t*>(s); }
178
179
10
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
9
size_t buffer_insert(std::vector<T, Alloc>& buf, size_t buf_offset, const T input[], size_t input_length) {
204
9
   BOTAN_ASSERT_NOMSG(buf_offset <= buf.size());
205
9
   const size_t to_copy = std::min(input_length, buf.size() - buf_offset);
206
9
   if(to_copy > 0) {
207
3
      copy_mem(&buf[buf_offset], input, to_copy);
208
3
   }
209
9
   return to_copy;
210
9
}
unsigned long Botan::buffer_insert<unsigned char, Botan::secure_allocator<unsigned char> >(std::__1::vector<unsigned char, Botan::secure_allocator<unsigned char> >&, unsigned long, unsigned char const*, unsigned long)
Line
Count
Source
203
9
size_t buffer_insert(std::vector<T, Alloc>& buf, size_t buf_offset, const T input[], size_t input_length) {
204
9
   BOTAN_ASSERT_NOMSG(buf_offset <= buf.size());
205
9
   const size_t to_copy = std::min(input_length, buf.size() - buf_offset);
206
9
   if(to_copy > 0) {
207
3
      copy_mem(&buf[buf_offset], input, to_copy);
208
3
   }
209
9
   return to_copy;
210
9
}
Unexecuted instantiation: unsigned long Botan::buffer_insert<unsigned char, std::__1::allocator<unsigned char> >(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, unsigned long, unsigned char const*, unsigned long)
211
212
template <typename T, typename Alloc, typename Alloc2>
213
0
size_t buffer_insert(std::vector<T, Alloc>& buf, size_t buf_offset, const std::vector<T, Alloc2>& input) {
214
0
   BOTAN_ASSERT_NOMSG(buf_offset <= buf.size());
215
0
   const size_t to_copy = std::min(input.size(), buf.size() - buf_offset);
216
0
   if(to_copy > 0) {
217
0
      copy_mem(&buf[buf_offset], input.data(), to_copy);
218
0
   }
219
0
   return to_copy;
220
0
}
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
231
0
   for(size_t i = 0; i != blocks; i += 32) {
232
0
      uint64_t x[4];
233
0
      uint64_t y[4];
234
235
0
      typecast_copy(x, out + i, 4);
236
0
      typecast_copy(y, in + i, 4);
237
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
243
0
      typecast_copy(out + i, x, 4);
244
0
   }
245
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
261
0
   for(size_t i = 0; i != blocks; i += 32) {
262
0
      uint64_t x[4];
263
0
      uint64_t y[4];
264
265
0
      typecast_copy(x, in + i, 4);
266
0
      typecast_copy(y, in2 + i, 4);
267
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
273
0
      typecast_copy(out + i, x, 4);
274
0
   }
275
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
0
void xor_buf(std::vector<uint8_t, Alloc>& out, const uint8_t* in, size_t n) {
287
0
   xor_buf(out.data(), in, n);
288
0
}
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
0
std::vector<uint8_t, Alloc>& operator^=(std::vector<uint8_t, Alloc>& out, const std::vector<uint8_t, Alloc2>& in) {
297
0
   if(out.size() < in.size())
298
0
      out.resize(in.size());
299
300
0
   xor_buf(out.data(), in.data(), in.size());
301
0
   return out;
302
0
}
303
304
}  // namespace Botan
305
306
#endif