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 }