Coverage Report

Created: 2025-07-18 06:20

/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_