1 /*
2 * Copyright (C) 2018 Rafael Ostertag
3 *
4 * This file is part of YAPET.
5 *
6 * YAPET is free software: you can redistribute it and/or modify it under the
7 * terms of the GNU General Public License as published by the Free Software
8 * Foundation, either version 3 of the License, or (at your option) any later
9 * version.
10 *
11 * YAPET is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14 * details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * YAPET. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * Additional permission under GNU GPL version 3 section 7
20 *
21 * If you modify this program, or any covered work, by linking or combining it
22 * with the OpenSSL project's OpenSSL library (or a modified version of that
23 * library), containing parts covered by the terms of the OpenSSL or SSLeay
24 * licenses, Rafael Ostertag grants you additional permission to convey the
25 * resulting work. Corresponding Source for a non-source form of such a
26 * combination shall include the source code for the parts of OpenSSL used as
27 * well as that of the covered work.
28 */
29
30 #include <cstdio>
31 #include <cstring>
32 #include <limits>
33 #include <stdexcept>
34
35 #include "consts.h"
36 #include "intl.h"
37 #include "securearray.hh"
38
39 using namespace yapet;
40
41 namespace {
castToSizeTypeOrThrow(size_t otherSize)42 inline SecureArray::size_type castToSizeTypeOrThrow(size_t otherSize) {
43 int maxSize = std::numeric_limits<SecureArray::size_type>::max();
44 size_t castedMaxSize = static_cast<size_t>(maxSize);
45 if (otherSize > castedMaxSize) {
46 throw std::invalid_argument(
47 _("Provided size exceeds maximum size of SecureArray"));
48 }
49
50 return static_cast<SecureArray::size_type>(otherSize);
51 }
52 } // namespace
53
indexInRangeOrThrow(size_type index) const54 void SecureArray::indexInRangeOrThrow(size_type index) const {
55 if (index >= _size || index < 0) {
56 char msg[YAPET::Consts::EXCEPTION_MESSAGE_BUFFER_SIZE];
57 std::snprintf(msg, YAPET::Consts::EXCEPTION_MESSAGE_BUFFER_SIZE,
58 _("Index out of range: %d"), index);
59 throw std::out_of_range{msg};
60 }
61 }
62
SecureArray(size_type size)63 SecureArray::SecureArray(size_type size) : _size{size}, _array{nullptr} {
64 if (_size < 0) {
65 throw std::invalid_argument{_("Size must not be negative")};
66 }
67
68 if (_size != 0) {
69 _array = new std::uint8_t[_size];
70 }
71 }
72
~SecureArray()73 SecureArray::~SecureArray() {
74 clearMemory();
75 freeMemory();
76 }
77
SecureArray(const SecureArray & other)78 SecureArray::SecureArray(const SecureArray& other)
79 : _size{other._size}, _array{nullptr} {
80 if (_size != 0) {
81 _array = new std::uint8_t[_size];
82 std::memcpy(_array, other._array, _size);
83 }
84 }
85
operator =(const SecureArray & other)86 SecureArray& SecureArray::operator=(const SecureArray& other) {
87 if (this == &other) {
88 return *this;
89 }
90
91 clearMemory();
92 freeMemory();
93
94 _size = other._size;
95 if (_size == 0) {
96 _array = other._array;
97 } else {
98 _array = new std::uint8_t[_size];
99 std::memcpy(_array, other._array, _size);
100 }
101
102 return *this;
103 }
104
SecureArray(SecureArray && other)105 SecureArray::SecureArray(SecureArray&& other)
106 : _size{other._size}, _array{other._array} {
107 other._array = nullptr;
108 other._size = 0;
109 }
110
operator =(SecureArray && other)111 SecureArray& SecureArray::operator=(SecureArray&& other) {
112 if (this == &other) {
113 return *this;
114 }
115
116 clearMemory();
117 freeMemory();
118
119 _size = other._size;
120 _array = other._array;
121 other._array = nullptr;
122 other._size = 0;
123
124 return *this;
125 }
126
clearMemory()127 inline void SecureArray::clearMemory() {
128 if (_array == nullptr) return;
129
130 std::memset(_array, 0, _size);
131 }
132
freeMemory()133 inline void SecureArray::freeMemory() {
134 if (_array == nullptr) return;
135 delete[] _array;
136 }
137
operator *() const138 const std::uint8_t* SecureArray::operator*() const { return _array; }
139
operator *()140 std::uint8_t* SecureArray::operator*() { return _array; }
141
operator [](size_type index) const142 std::uint8_t SecureArray::operator[](size_type index) const {
143 indexInRangeOrThrow(index);
144 return _array[index];
145 }
146
operator [](size_type index)147 std::uint8_t& SecureArray::operator[](size_type index) {
148 indexInRangeOrThrow(index);
149 return _array[index];
150 }
151
operator ==(const SecureArray & other) const152 bool SecureArray::operator==(const SecureArray& other) const {
153 if (other._size != _size) return false;
154
155 if (other._array == nullptr && _array == nullptr) return true;
156
157 return std::memcmp(_array, other._array, _size) == 0;
158 }
159
operator <<(const SecureArray & source)160 SecureArray& SecureArray::operator<<(const SecureArray& source) {
161 if (this == &source) return *this;
162
163 if (source._size == 0 || _size == 0) {
164 return *this;
165 }
166
167 if (source._size > _size) {
168 std::memcpy(_array, source._array, _size);
169 return *this;
170 }
171
172 clearMemory();
173 freeMemory();
174
175 _array = new std::uint8_t[source._size];
176 _size = source._size;
177 std::memcpy(_array, source._array, _size);
178
179 return *this;
180 }
181
toSecureArray(const char * str)182 SecureArray yapet::toSecureArray(const char* str) {
183 auto len = std::strlen(str) + 1;
184 if (len == 0) {
185 return SecureArray{};
186 }
187
188 auto castedSize = castToSizeTypeOrThrow(len);
189
190 SecureArray result{castedSize};
191 std::memcpy(*result, str, len);
192
193 return result;
194 }
195
toSecureArray(const std::string & str)196 SecureArray yapet::toSecureArray(const std::string& str) {
197 return toSecureArray(str.c_str());
198 }
199
toSecureArray(const std::uint8_t * ptr,SecureArray::size_type size)200 SecureArray yapet::toSecureArray(const std::uint8_t* ptr,
201 SecureArray::size_type size) {
202 if (ptr == nullptr) {
203 throw std::invalid_argument(_("Pointer must not be null"));
204 }
205
206 SecureArray secureArray{size};
207 std::memcpy(*secureArray, ptr, size);
208
209 return secureArray;
210 }
211
operator +(const SecureArray & a,const SecureArray & b)212 SecureArray yapet::operator+(const SecureArray& a, const SecureArray& b) {
213 auto aSize = a.size();
214 auto bSize = b.size();
215 SecureArray result{aSize + bSize};
216
217 std::memcpy(*result, *a, aSize);
218 auto ptrToBDest = *result + aSize;
219 std::memcpy(ptrToBDest, *b, bSize);
220
221 return result;
222 }
223