/src/rnp/src/lib/crypto/mem.h
Line | Count | Source (jump to first uncovered line) |
1 | | /*- |
2 | | * Copyright (c) 2021-2023 Ribose Inc. |
3 | | * All rights reserved. |
4 | | * |
5 | | * Redistribution and use in source and binary forms, with or without |
6 | | * modification, are permitted provided that the following conditions |
7 | | * are met: |
8 | | * 1. Redistributions of source code must retain the above copyright |
9 | | * notice, this list of conditions and the following disclaimer. |
10 | | * 2. Redistributions in binary form must reproduce the above copyright |
11 | | * notice, this list of conditions and the following disclaimer in the |
12 | | * documentation and/or other materials provided with the distribution. |
13 | | * |
14 | | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
15 | | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
16 | | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
17 | | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS |
18 | | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
19 | | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
20 | | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
21 | | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
22 | | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
23 | | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
24 | | * POSSIBILITY OF SUCH DAMAGE. |
25 | | */ |
26 | | |
27 | | #ifndef CRYPTO_MEM_H_ |
28 | | #define CRYPTO_MEM_H_ |
29 | | |
30 | | #include "config.h" |
31 | | #include <array> |
32 | | #include <vector> |
33 | | #if defined(CRYPTO_BACKEND_BOTAN) |
34 | | #include <botan/secmem.h> |
35 | | #include <botan/ffi.h> |
36 | | #elif defined(CRYPTO_BACKEND_OPENSSL) |
37 | | #include <openssl/crypto.h> |
38 | | #endif |
39 | | #include "str-utils.h" |
40 | | |
41 | | namespace rnp { |
42 | | |
43 | | #if defined(CRYPTO_BACKEND_BOTAN) |
44 | | template <typename T> using secure_vector = Botan::secure_vector<T>; |
45 | | #elif defined(CRYPTO_BACKEND_OPENSSL) |
46 | | template <typename T> class ossl_allocator { |
47 | | public: |
48 | | #if !defined(_MSC_VER) || !defined(_DEBUG) |
49 | | /* MSVC in debug mode uses non-integral proxy types in container types */ |
50 | | static_assert(std::is_integral<T>::value, "secure_vector can hold integral types only"); |
51 | | #endif |
52 | | |
53 | | typedef T value_type; |
54 | | typedef std::size_t size_type; |
55 | | |
56 | | ossl_allocator() noexcept = default; |
57 | | ossl_allocator(const ossl_allocator &) noexcept = default; |
58 | | ossl_allocator &operator=(const ossl_allocator &) noexcept = default; |
59 | | ~ossl_allocator() noexcept = default; |
60 | | |
61 | | template <typename U> ossl_allocator(const ossl_allocator<U> &) noexcept |
62 | | { |
63 | | } |
64 | | |
65 | | T * |
66 | | allocate(std::size_t n) |
67 | | { |
68 | | if (!n) { |
69 | | return nullptr; |
70 | | } |
71 | | |
72 | | /* attempt to use OpenSSL secure alloc */ |
73 | | T *ptr = static_cast<T *>(OPENSSL_secure_zalloc(n * sizeof(T))); |
74 | | if (ptr) { |
75 | | return ptr; |
76 | | } |
77 | | /* fallback to std::alloc if failed */ |
78 | | ptr = static_cast<T *>(std::calloc(n, sizeof(T))); |
79 | | if (!ptr) |
80 | | throw std::bad_alloc(); |
81 | | return ptr; |
82 | | } |
83 | | |
84 | | void |
85 | | deallocate(T *p, std::size_t n) |
86 | | { |
87 | | if (!p) { |
88 | | return; |
89 | | } |
90 | | if (CRYPTO_secure_allocated(p)) { |
91 | | OPENSSL_secure_clear_free(p, n * sizeof(T)); |
92 | | return; |
93 | | } |
94 | | OPENSSL_cleanse(p, n * sizeof(T)); |
95 | | std::free(p); |
96 | | } |
97 | | }; |
98 | | |
99 | | template <typename T> using secure_vector = std::vector<T, ossl_allocator<T> >; |
100 | | #else |
101 | | #error Unsupported backend. |
102 | | #endif |
103 | | |
104 | | using secure_bytes = secure_vector<uint8_t>; |
105 | | |
106 | | template <typename T, std::size_t N> struct secure_array { |
107 | | private: |
108 | | #if !defined(_MSC_VER) || !defined(_DEBUG) |
109 | | /* MSVC in debug mode uses non-integral proxy types in container types */ |
110 | | static_assert(std::is_integral<T>::value, "secure_array can hold integral types only"); |
111 | | #endif |
112 | | |
113 | | std::array<T, N> data_; |
114 | | |
115 | | public: |
116 | 76 | secure_array() : data_({0}) |
117 | 76 | { |
118 | 76 | } Unexecuted instantiation: rnp::secure_array<unsigned char, 32ul>::secure_array() rnp::secure_array<char, 256ul>::secure_array() Line | Count | Source | 116 | 76 | secure_array() : data_({0}) | 117 | 76 | { | 118 | 76 | } |
Unexecuted instantiation: rnp::secure_array<unsigned short, 1ul>::secure_array() Unexecuted instantiation: rnp::secure_array<unsigned char, 33ul>::secure_array() |
119 | | |
120 | | T * |
121 | | data() |
122 | 76 | { |
123 | 76 | return &data_[0]; |
124 | 76 | } Unexecuted instantiation: rnp::secure_array<unsigned char, 32ul>::data() rnp::secure_array<char, 256ul>::data() Line | Count | Source | 122 | 76 | { | 123 | 76 | return &data_[0]; | 124 | 76 | } |
Unexecuted instantiation: rnp::secure_array<unsigned char, 33ul>::data() |
125 | | |
126 | | const T * |
127 | | data() const |
128 | 0 | { |
129 | 0 | return &data_[0]; |
130 | 0 | } |
131 | | |
132 | | std::size_t |
133 | | size() const |
134 | 76 | { |
135 | 76 | return data_.size(); |
136 | 76 | } rnp::secure_array<char, 256ul>::size() const Line | Count | Source | 134 | 76 | { | 135 | 76 | return data_.size(); | 136 | 76 | } |
Unexecuted instantiation: rnp::secure_array<unsigned char, 32ul>::size() const |
137 | | |
138 | | T |
139 | | operator[](size_t idx) const |
140 | | { |
141 | | return data_[idx]; |
142 | | } |
143 | | |
144 | | T & |
145 | | operator[](size_t idx) |
146 | 0 | { |
147 | 0 | return data_[idx]; |
148 | 0 | } Unexecuted instantiation: rnp::secure_array<unsigned char, 32ul>::operator[](unsigned long) Unexecuted instantiation: rnp::secure_array<unsigned short, 1ul>::operator[](unsigned long) Unexecuted instantiation: rnp::secure_array<unsigned char, 33ul>::operator[](unsigned long) |
149 | | |
150 | | ~secure_array() |
151 | 76 | { |
152 | 76 | #if defined(CRYPTO_BACKEND_BOTAN) |
153 | 76 | botan_scrub_mem(&data_[0], sizeof(data_)); |
154 | | #elif defined(CRYPTO_BACKEND_OPENSSL) |
155 | | OPENSSL_cleanse(&data_[0], sizeof(data_)); |
156 | | #else |
157 | | #error "Unsupported crypto backend." |
158 | | #endif |
159 | 76 | } Unexecuted instantiation: rnp::secure_array<unsigned char, 32ul>::~secure_array() rnp::secure_array<char, 256ul>::~secure_array() Line | Count | Source | 151 | 76 | { | 152 | 76 | #if defined(CRYPTO_BACKEND_BOTAN) | 153 | 76 | botan_scrub_mem(&data_[0], sizeof(data_)); | 154 | | #elif defined(CRYPTO_BACKEND_OPENSSL) | 155 | | OPENSSL_cleanse(&data_[0], sizeof(data_)); | 156 | | #else | 157 | | #error "Unsupported crypto backend." | 158 | | #endif | 159 | 76 | } |
Unexecuted instantiation: rnp::secure_array<unsigned short, 1ul>::~secure_array() Unexecuted instantiation: rnp::secure_array<unsigned char, 33ul>::~secure_array() |
160 | | }; |
161 | | |
162 | | enum class HexFormat { Lowercase, Uppercase }; |
163 | | |
164 | | bool hex_encode(const uint8_t *buf, |
165 | | size_t buf_len, |
166 | | char * hex, |
167 | | size_t hex_len, |
168 | | HexFormat format = HexFormat::Uppercase); |
169 | | size_t hex_decode(const char *hex, uint8_t *buf, size_t buf_len); |
170 | | |
171 | | inline std::string |
172 | | bin_to_hex(const uint8_t *data, size_t len, HexFormat format = HexFormat::Uppercase) |
173 | 864k | { |
174 | 864k | std::string res(len * 2 + 1, '\0'); |
175 | 864k | (void) hex_encode(data, len, &res.front(), res.size(), format); |
176 | 864k | res.resize(len * 2); |
177 | 864k | return res; |
178 | 864k | } |
179 | | |
180 | | inline std::string |
181 | | bin_to_hex(const std::vector<uint8_t> &vec, HexFormat format = HexFormat::Uppercase) |
182 | 0 | { |
183 | 0 | return bin_to_hex(vec.data(), vec.size(), format); |
184 | 0 | } |
185 | | |
186 | | inline std::vector<uint8_t> |
187 | | hex_to_bin(const std::string &str) |
188 | 1.25M | { |
189 | 1.25M | if (str.empty() || !is_hex(str)) { |
190 | 0 | return {}; |
191 | 0 | } |
192 | | /* 1 extra char for case of non-even input , 1 for terminating zero */ |
193 | 1.25M | std::vector<uint8_t> res(str.size() / 2 + 2); |
194 | 1.25M | size_t len = hex_decode(str.c_str(), res.data(), res.size()); |
195 | 1.25M | res.resize(len); |
196 | 1.25M | return res; |
197 | 1.25M | } |
198 | | |
199 | | } // namespace rnp |
200 | | |
201 | | void secure_clear(void *vp, size_t size); |
202 | | |
203 | | #endif // CRYPTO_MEM_H_ |