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 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33
34 #include <argon2.h>
35 #include <openssl/rand.h>
36 #include <cstdio>
37 #include <cstring>
38 #include <typeinfo>
39 #ifdef DEBUG_LOG
40 #include <iomanip>
41 #include <sstream>
42 #endif
43
44 #include "consts.h"
45 #include "cryptoerror.hh"
46 #include "globals.h"
47 #include "intl.h"
48 #include "key256.hh"
49 #include "logger.hh"
50 #include "ods.hh"
51
52 using namespace yapet;
53
54 namespace {
55 #ifdef DEBUG_LOG
56 constexpr char hexPrefix[]{"0x"};
57 #endif
58 /**
59 * The max length of key in bytes (256 bits)
60 */
61 constexpr int KEY_LENGTH{32};
62 constexpr int SSL_SUCCESS{1};
63
64 // in bytes
65 constexpr int SALT_NIBBLE_SIZE{sizeof(int)};
66 constexpr int NUMBER_OF_SALT_NIBBLES{4};
67 // In bytes
68 constexpr int SALT_LENGTH = SALT_NIBBLE_SIZE * NUMBER_OF_SALT_NIBBLES;
69
70 union architecture_agnostic_salt_type {
71 int nibbles[NUMBER_OF_SALT_NIBBLES];
72 uint8_t bytes[SALT_LENGTH];
73 };
74
75 #ifdef DEBUG_LOG
saltNibblesToHexString(const int * salt)76 std::string saltNibblesToHexString(const int* salt) {
77 std::stringstream hexValue;
78 hexValue << hexPrefix << std::hex;
79 for (int i = 0; i < NUMBER_OF_SALT_NIBBLES; i++) {
80 hexValue << salt[i];
81 }
82 return hexValue.str();
83 }
84
saltBytesToHexString(const std::uint8_t * salt)85 std::string saltBytesToHexString(const std::uint8_t* salt) {
86 std::stringstream hexValue;
87 hexValue << hexPrefix << std::hex;
88 for (int i = 0; i < SALT_LENGTH; i++) {
89 hexValue << static_cast<int>(salt[i]);
90 }
91 return hexValue.str();
92 }
93
metaDataSaltToHexString(const MetaData & metaData)94 std::string metaDataSaltToHexString(const MetaData& metaData) {
95 std::stringstream hexValue;
96 hexValue << hexPrefix << std::hex
97 << metaData.getValue(YAPET::Consts::ARGON2_SALT1_KEY)
98 << metaData.getValue(YAPET::Consts::ARGON2_SALT2_KEY)
99 << metaData.getValue(YAPET::Consts::ARGON2_SALT3_KEY)
100 << metaData.getValue(YAPET::Consts::ARGON2_SALT4_KEY);
101 return hexValue.str();
102 }
103
secureArrayToHexString(const SecureArray & secureArray)104 std::string secureArrayToHexString(const SecureArray& secureArray) {
105 std::stringstream hexValue;
106 hexValue << hexPrefix << std::hex;
107 for (SecureArray::size_type i = 0; i < secureArray.size(); i++) {
108 hexValue << static_cast<int>(secureArray[i]);
109 }
110
111 return hexValue.str();
112 }
113 #endif
114
composeSaltFromIntegers(const int * nibbles,uint8_t * saltBuffer)115 inline void composeSaltFromIntegers(const int* nibbles, uint8_t* saltBuffer) {
116 architecture_agnostic_salt_type archAgnosticSalt;
117 for (int i = 0; i < NUMBER_OF_SALT_NIBBLES; i++) {
118 archAgnosticSalt.nibbles[i] = toODS(nibbles[i]);
119 }
120
121 std::memcpy(saltBuffer, archAgnosticSalt.bytes, SALT_LENGTH);
122 }
123
hash(const SecureArray & password,const MetaData & parameters)124 inline SecureArray hash(const SecureArray& password,
125 const MetaData& parameters) {
126 int timeCost = parameters.getValue(YAPET::Consts::ARGON2_TIME_COST_KEY);
127 int memoryCost = parameters.getValue(YAPET::Consts::ARGON2_MEMORY_COST_KEY);
128 int parallelism =
129 parameters.getValue(YAPET::Consts::ARGON2_PARALLELISM_KEY);
130
131 int saltNibbles[NUMBER_OF_SALT_NIBBLES];
132 saltNibbles[0] = parameters.getValue(YAPET::Consts::ARGON2_SALT1_KEY);
133 saltNibbles[1] = parameters.getValue(YAPET::Consts::ARGON2_SALT2_KEY);
134 saltNibbles[2] = parameters.getValue(YAPET::Consts::ARGON2_SALT3_KEY);
135 saltNibbles[3] = parameters.getValue(YAPET::Consts::ARGON2_SALT4_KEY);
136
137 uint8_t saltBuffer[SALT_LENGTH];
138 composeSaltFromIntegers(saltNibbles, saltBuffer);
139
140 SecureArray hash{KEY_LENGTH};
141
142 int status = argon2i_hash_raw(timeCost, memoryCost, parallelism, *password,
143 password.size(), saltBuffer, SALT_LENGTH,
144 *hash, hash.size());
145
146 LOG_MESSAGE(std::string{__func__} + " ## Hash Password Begin");
147 LOG_MESSAGE(std::string{__func__} +
148 " Salt from Meta data: " + metaDataSaltToHexString(parameters));
149 LOG_MESSAGE(std::string{__func__} +
150 " Salt as nibbles: " + saltNibblesToHexString(saltNibbles));
151 LOG_MESSAGE(std::string{__func__} +
152 " Salt as bytes: " + saltBytesToHexString(saltBuffer));
153 LOG_MESSAGE(std::string{__func__} + " Password '" +
154 secureArrayToString(password) + "' is hashed as " +
155 secureArrayToHexString(hash));
156 LOG_MESSAGE(std::string{__func__} + " ## Hash Password End");
157
158 if (status != ARGON2_OK) {
159 throw HashError(_("Error hashing password using Argon2"));
160 }
161 return hash;
162 }
163
randomInt()164 int randomInt() {
165 int i;
166 auto result = RAND_bytes(reinterpret_cast<unsigned char*>(&i), sizeof(int));
167 if (result != SSL_SUCCESS) {
168 throw HashError{_("Cannot generate random salt")};
169 }
170 return i;
171 }
172
173 } // namespace
174
newDefaultKeyingParameters()175 MetaData Key256::newDefaultKeyingParameters() {
176 MetaData metaData{};
177 metaData.setValue(YAPET::Consts::ARGON2_MEMORY_COST_KEY,
178 YAPET::Globals::config.argon2_memory.get());
179 metaData.setValue(YAPET::Consts::ARGON2_PARALLELISM_KEY,
180 YAPET::Globals::config.argon2_parallelism.get());
181 metaData.setValue(YAPET::Consts::ARGON2_TIME_COST_KEY,
182 YAPET::Globals::config.argon2_iterations.get());
183 metaData.setValue(YAPET::Consts::ARGON2_SALT1_KEY, randomInt());
184 metaData.setValue(YAPET::Consts::ARGON2_SALT2_KEY, randomInt());
185 metaData.setValue(YAPET::Consts::ARGON2_SALT3_KEY, randomInt());
186 metaData.setValue(YAPET::Consts::ARGON2_SALT4_KEY, randomInt());
187
188 LOG_MESSAGE(std::string{__func__} + ": Created random salt " +
189 metaDataSaltToHexString(metaData));
190 return metaData;
191 }
192
193 /**
194 * Initializes the key and the initialization vector. Make sure you
195 * securely destroy the password provided to this method.
196 *
197 * @param password a pointer to the location the password is
198 * stored. The password has to be zero-terminated.
199 */
Key256()200 Key256::Key256() : _key{0}, _keyingParameters{} {}
201
keyingParameters(const MetaData & parameters)202 void Key256::keyingParameters(const MetaData& parameters) {
203 _keyingParameters = parameters;
204 }
205
keyingParameters() const206 const MetaData& Key256::keyingParameters() const { return _keyingParameters; }
207
password(const SecureArray & password)208 void Key256::password(const SecureArray& password) {
209 SecureArray passwordWithoutZeroTerminator{password.size() - 1};
210 passwordWithoutZeroTerminator << password;
211
212 _key = hash(passwordWithoutZeroTerminator, _keyingParameters);
213
214 if (_key.size() != KEY_LENGTH) {
215 char msg[YAPET::Consts::EXCEPTION_MESSAGE_BUFFER_SIZE];
216 std::snprintf(
217 msg, YAPET::Consts::EXCEPTION_MESSAGE_BUFFER_SIZE,
218 _("Effective key length of %d does not match expected key "
219 "length %d"),
220 _key.size(), KEY_LENGTH);
221 throw HashError{msg};
222 }
223 }
224
Key256(Key256 && k)225 Key256::Key256(Key256&& k)
226 : _key{std::move(k._key)},
227 _keyingParameters{std::move(k._keyingParameters)} {}
228
Key256(const Key256 & k)229 Key256::Key256(const Key256& k)
230 : _key{k._key}, _keyingParameters{k._keyingParameters} {}
231
operator =(const Key256 & k)232 Key256& Key256::operator=(const Key256& k) {
233 if (this == &k) return *this;
234
235 _key = k._key;
236 _keyingParameters = k._key;
237
238 return *this;
239 }
240
operator =(Key256 && k)241 Key256& Key256::operator=(Key256&& k) {
242 if (this == &k) return *this;
243
244 _key = std::move(k._key);
245 _keyingParameters = std::move(k._keyingParameters);
246
247 return *this;
248 }
249
operator ==(const Key256 & k) const250 bool Key256::operator==(const Key256& k) const { return _key == k._key; }
operator ==(const Key & k) const251 bool Key256::operator==(const Key& k) const {
252 if (typeid(k) != typeid(*this)) {
253 return false;
254 }
255
256 return operator==(dynamic_cast<const Key256&>(k));
257 }
258
operator !=(const Key256 & k) const259 bool Key256::operator!=(const Key256& k) const { return !operator==(k); }
260
operator !=(const Key & k) const261 bool Key256::operator!=(const Key& k) const {
262 if (typeid(k) != typeid(*this)) {
263 return true;
264 }
265
266 return operator!=(dynamic_cast<const Key256&>(k));
267 }