memory_operations.hpp
Go to the documentation of this file.
1 //---------------------------------------------------------------------------//
2 // Copyright (c) 2018-2020 Mikhail Komarov <nemo@nil.foundation>
3 //
4 // MIT License
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a copy
7 // of this software and associated documentation files (the "Software"), to deal
8 // in the Software without restriction, including without limitation the rights
9 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 // copies of the Software, and to permit persons to whom the Software is
11 // furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in all
14 // copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 // SOFTWARE.
23 //---------------------------------------------------------------------------//
24 
25 #ifndef CRYPTO3_MEMORY_OPERATIONS_HPP
26 #define CRYPTO3_MEMORY_OPERATIONS_HPP
27 
28 #include <cstring>
29 #include <vector>
30 
31 #ifdef CRYPTO3_HAS_LOCKING_ALLOCATOR
32 
34 
35 #endif
36 
37 namespace nil {
38  namespace crypto3 {
39 
48  BOOST_ATTRIBUTE_MALLOC_FUNCTION void *allocate_memory(size_t elems, size_t elem_size) {
49 #if defined(CRYPTO3_HAS_LOCKING_ALLOCATOR)
50  if (void *p = mlock_allocator::instance().allocate(elems, elem_size)) {
51  return p;
52  }
53 #endif
54 
55  void *ptr = std::calloc(elems, elem_size);
56  if (!ptr) {
57  throw std::bad_alloc();
58  }
59  return ptr;
60  }
61 
77  void secure_scrub_memory(void *ptr, size_t n) {
78 #if defined(CRYPTO3_TARGET_OS_HAS_RTLSECUREZEROMEMORY)
79  ::RtlSecureZeroMemory(ptr, n);
80 
81 #elif defined(CRYPTO3_TARGET_OS_HAS_EXPLICIT_BZERO)
82  ::explicit_bzero(ptr, n);
83 
84 #elif defined(CRYPTO3_USE_VOLATILE_MEMSET_FOR_ZERO) && (CRYPTO3_USE_VOLATILE_MEMSET_FOR_ZERO == 1)
85  /*
86  * Call memset through a static volatile pointer, which the compiler
87  * should not elide. This construct should be safe in conforming
88  * compilers, but who knows. I did confirm that on x86-64 GCC 6.1 and
89  * Clang 3.8 both create code that saves the memset address in the
90  * data segment and uncondtionally loads and jumps to that address.
91  */
92  static void *(*const volatile memset_ptr)(void *, int, size_t) = std::memset;
93  (memset_ptr)(ptr, 0, n);
94 #else
95 
96  volatile uint8_t *p = reinterpret_cast<volatile uint8_t *>(ptr);
97 
98  for (size_t i = 0; i != n; ++i) {
99  p[i] = 0;
100  }
101 #endif
102  }
103 
110  void deallocate_memory(void *p, size_t elems, size_t elem_size) {
111  if (p == nullptr) {
112  return;
113  }
114 
115  secure_scrub_memory(p, elems * elem_size);
116 
117 #if defined(CRYPTO3_HAS_LOCKING_ALLOCATOR)
118  if (mlock_allocator::instance().deallocate(p, elems, elem_size)) {
119  return;
120  }
121 #endif
122 
123  std::free(p);
124  }
125 
130 #if defined(CRYPTO3_HAS_LOCKING_ALLOCATOR)
132 #endif
133  }
134 
143  bool constant_time_compare(const uint8_t x[], const uint8_t y[], size_t len) {
144  volatile uint8_t difference = 0;
145 
146  for (size_t i = 0; i != len; ++i) {
147  difference |= (x[i] ^ y[i]);
148  }
149 
150  return difference == 0;
151  }
152 
158  inline void clear_bytes(void *ptr, size_t bytes) {
159  if (bytes > 0) {
160  std::memset(ptr, 0, bytes);
161  }
162  }
163 
174  template<typename T>
175  inline void clear_mem(T *ptr, size_t n) {
176  clear_bytes(ptr, sizeof(T) * n);
177  }
178 
185  template<typename T>
186  inline void copy_mem(T *out, const T *in, size_t n) {
187  if (n > 0) {
188  std::memmove(out, in, sizeof(T) * n);
189  }
190  }
191 
198  template<typename T>
199  inline void set_mem(T *ptr, size_t n, uint8_t val) {
200  if (n > 0) {
201  std::memset(ptr, val, sizeof(T) * n);
202  }
203  }
204 
205  inline const uint8_t *cast_char_ptr_to_uint8(const char *s) {
206  return reinterpret_cast<const uint8_t *>(s);
207  }
208 
209  inline const char *cast_uint8_ptr_to_char(const uint8_t *b) {
210  return reinterpret_cast<const char *>(b);
211  }
212 
213  inline uint8_t *cast_char_ptr_to_uint8(char *s) {
214  return reinterpret_cast<uint8_t *>(s);
215  }
216 
217  inline char *cast_uint8_ptr_to_char(uint8_t *b) {
218  return reinterpret_cast<char *>(b);
219  }
220 
228  template<typename T>
229  inline bool same_mem(const T *p1, const T *p2, size_t n) {
230  volatile T difference = 0;
231 
232  for (size_t i = 0; i != n; ++i) {
233  difference |= (p1[i] ^ p2[i]);
234  }
235 
236  return difference == 0;
237  }
238 
245  inline void xor_buf(uint8_t out[], const uint8_t in[], size_t length) {
246  while (length >= 16) {
247  uint64_t x0, x1, y0, y1;
248  std::memcpy(&x0, in, 8);
249  std::memcpy(&x1, in + 8, 8);
250  std::memcpy(&y0, out, 8);
251  std::memcpy(&y1, out + 8, 8);
252 
253  y0 ^= x0;
254  y1 ^= x1;
255  std::memcpy(out, &y0, 8);
256  std::memcpy(out + 8, &y1, 8);
257  out += 16;
258  in += 16;
259  length -= 16;
260  }
261 
262  while (length > 0) {
263  out[0] ^= in[0];
264  out += 1;
265  in += 1;
266  length -= 1;
267  }
268  }
269 
277  inline void xor_buf(uint8_t out[], const uint8_t in[], const uint8_t in2[], size_t length) {
278  while (length >= 16) {
279  uint64_t x0, x1, y0, y1;
280  std::memcpy(&x0, in, 8);
281  std::memcpy(&x1, in + 8, 8);
282  std::memcpy(&y0, in2, 8);
283  std::memcpy(&y1, in2 + 8, 8);
284 
285  x0 ^= y0;
286  x1 ^= y1;
287  std::memcpy(out, &x0, 8);
288  std::memcpy(out + 8, &x1, 8);
289  out += 16;
290  in += 16;
291  in2 += 16;
292  length -= 16;
293  }
294 
295  for (size_t i = 0; i != length; ++i) {
296  out[i] = in[i] ^ in2[i];
297  }
298  }
299 
300  template<typename Alloc, typename Alloc2>
301  void xor_buf(std::vector<uint8_t, Alloc> &out, const std::vector<uint8_t, Alloc2> &in, size_t n) {
302  xor_buf(out.data(), in.data(), n);
303  }
304 
305  template<typename Alloc>
306  void xor_buf(std::vector<uint8_t, Alloc> &out, const uint8_t *in, size_t n) {
307  xor_buf(out.data(), in, n);
308  }
309 
310  template<typename Alloc, typename Alloc2>
311  void xor_buf(std::vector<uint8_t, Alloc> &out, const uint8_t *in, const std::vector<uint8_t, Alloc2> &in2,
312  size_t n) {
313  xor_buf(out.data(), in, in2.data(), n);
314  }
315 
316  template<typename Alloc, typename Alloc2>
317  std::vector<uint8_t, Alloc> &operator^=(std::vector<uint8_t, Alloc> &out,
318  const std::vector<uint8_t, Alloc2> &in) {
319  if (out.size() < in.size()) {
320  out.resize(in.size());
321  }
322 
323  xor_buf(out.data(), in.data(), in.size());
324  return out;
325  }
326  } // namespace crypto3
327 } // namespace nil
328 
329 #endif
static mlock_allocator & instance()
Definition: locking_allocator.hpp:17
const uint8_t * cast_char_ptr_to_uint8(const char *s)
Definition: memory_operations.hpp:205
void set_mem(T *ptr, size_t n, uint8_t val)
Definition: memory_operations.hpp:199
void secure_scrub_memory(void *ptr, size_t n)
Definition: memory_operations.hpp:77
BOOST_ATTRIBUTE_MALLOC_FUNCTION void * allocate_memory(size_t elems, size_t elem_size)
Definition: memory_operations.hpp:48
bool same_mem(const T *p1, const T *p2, size_t n)
Definition: memory_operations.hpp:229
void deallocate_memory(void *p, size_t elems, size_t elem_size)
Definition: memory_operations.hpp:110
void initialize_allocator()
Definition: memory_operations.hpp:129
void clear_bytes(void *ptr, size_t bytes)
Definition: memory_operations.hpp:158
void xor_buf(uint8_t out[], const uint8_t in[], size_t length)
Definition: memory_operations.hpp:245
bool constant_time_compare(const uint8_t x[], const uint8_t y[], size_t len)
Definition: memory_operations.hpp:143
std::vector< uint8_t, Alloc > & operator^=(std::vector< uint8_t, Alloc > &out, const std::vector< uint8_t, Alloc2 > &in)
Definition: memory_operations.hpp:317
void copy_mem(T *out, const T *in, size_t n)
Definition: memory_operations.hpp:186
const char * cast_uint8_ptr_to_char(const uint8_t *b)
Definition: memory_operations.hpp:209
void clear_mem(T *ptr, size_t n)
Definition: memory_operations.hpp:175
Definition: pair.hpp:31