· 4 years ago · Feb 12, 2021, 08:44 AM
1//implmentqtion file for crypto.h
2#include<string>
3#include <iostream>
4#include<cstring>
5#include<random>
6#include"crypto.h"
7#include <openssl/evp.h>
8#include "openssl/sha.h"
9#include"sqlite/build/sqlite3.h"
10
11//thus functiin takes a string, which will be a password but could be used to hash any string, it using the sha512 algorithm
12std::string create_hash(const std::string &input)
13{
14 int iter = 1007;
15
16 const unsigned char *salt = nullptr;
17 unsigned char key[32] = {0};
18
19 PKCS5_PBKDF2_HMAC(input.c_str(), input.size(),
20 salt, 0,
21 iter, EVP_sha256(),
22 sizeof(key), key);
23
24 std::string hashed;
25 hashed.assign((const char*)key, sizeof(key));
26 return hashed;
27
28}
29
30//this function creates a username and password in an sqlite database
31
32bool check_username (const std::string &username, const std::string &database) {
33 sqlite3 *pDB;
34 int rc= sqlite3_open(database.c_str(),&pDB);
35 if (rc != SQLITE_OK){
36 std::cout << "bad database: " << database << std::endl;
37 return false;
38 }
39
40 std::string sql= "SELECT COUNT(*) FROM USERS WHERE USERNAME = ?;";
41 sqlite3_stmt *pStmt = nullptr;
42 rc = sqlite3_prepare_v2(pDB,sql.c_str(),sql.size(),&pStmt,nullptr);
43
44 if (rc != SQLITE_OK)
45 {
46 sqlite3_finalize(pStmt);
47 sqlite3_close(pDB);
48 std::cout << "bad prepare: " << sql << std::endl;
49 return false;
50 }
51 rc = sqlite3_bind_text(pStmt,1,username.c_str(),username.size(),nullptr);
52 if (rc != SQLITE_OK)
53 {
54 sqlite3_finalize(pStmt);
55 sqlite3_close(pDB);
56 return false;
57 }
58
59 if (sqlite3_step(pStmt) != SQLITE_ROW)
60 {
61 sqlite3_close(pDB);
62 sqlite3_finalize(pStmt);
63 return false;
64 }
65
66 bool exists = (sqlite3_column_int(pStmt,0) > 0);
67
68 sqlite3_finalize(pStmt);
69 sqlite3_close(pDB);
70
71 return exists;
72}
73
74bool create_password (std::string password, const std::string &username, const std::string &database)
75{
76 //first we open the database
77 sqlite3 *pDB;
78 int rc= sqlite3_open(database.c_str(),&pDB);
79 if (rc != SQLITE_OK){
80 std::cout << "bad database: " << database << std::endl;
81 return false;
82 }
83 //this is for the hashed password
84 std::string hashed;
85 //we create a 32 bit string to ne added to the password
86 //salt is unknown to everyone and a new salt is create each time
87 std::string salt = create_salt();
88
89 password += salt;
90 //now we create the hash
91 hashed = create_hash(password);
92 //now we create the sqlite table if the table doesn't already exits
93 std::string sql= "CREATE TABLE IF NOT EXISTS USERS(USERNAME TEXT NOT NULL, PASSWORD TEXT NOT NULL, SALT TEXT NOT NULL);";
94
95 sqlite3_stmt *pStmt = nullptr;
96 rc = sqlite3_prepare_v2(pDB,sql.c_str(),sql.size(),&pStmt,nullptr);
97
98 //if table was not created
99 if (rc != SQLITE_OK)
100 {
101 sqlite3_finalize(pStmt);
102 sqlite3_close(pDB);
103 std::cout << "bad prepare: " << sql << std::endl;
104 return false;
105 }
106 //if table was not created
107 if (sqlite3_step(pStmt) != SQLITE_DONE)
108 {
109 sqlite3_close(pDB);
110 sqlite3_finalize(pStmt);
111 return false;
112 }
113
114 sqlite3_finalize(pStmt);
115
116 if(check_username(username, database)){
117 return false; // user already exists
118 }
119
120
121 //if we are here then the table created or alreasy existed now we insert the data
122 sql= "INSERT INTO USERS (USERNAME,PASSWORD,SALT)"
123 "VALUES (?,?,?);";
124 rc = sqlite3_prepare_v2(pDB,sql.c_str(),sql.size(),&pStmt,nullptr);
125
126 if (rc != SQLITE_OK)
127 {
128 sqlite3_finalize(pStmt);
129 sqlite3_close(pDB);
130 std::cout << "bad prepare: " << sql << std::endl;
131 return false;
132 }
133 //now we bind the arguments to the statement to be givin to sqlite3
134 rc = sqlite3_bind_text(pStmt,1,username.c_str(),username.size(),nullptr);
135 if (rc != SQLITE_OK)
136 {
137 sqlite3_close(pDB);
138 sqlite3_finalize(pStmt);
139 return false;
140 }
141 rc = sqlite3_bind_text(pStmt,2,hashed.c_str(),hashed.size(),nullptr);
142 if (rc != SQLITE_OK)
143 {
144 sqlite3_close(pDB);
145 sqlite3_finalize(pStmt);
146 return false;
147 }
148 rc = sqlite3_bind_text(pStmt,3,salt.c_str(),salt.size(),nullptr);
149 if (rc != SQLITE_OK)
150 {
151 sqlite3_close(pDB);
152 sqlite3_finalize(pStmt);
153 return false;
154 }
155 //now we place our sql statement with the arguments bound to it in our table
156 //if arguments not placed into the table
157 if (sqlite3_step(pStmt) != SQLITE_DONE)
158 {
159 sqlite3_close(pDB);
160 sqlite3_finalize(pStmt);
161 return false;
162 }
163 //ifnwe are here then the data was inserted _nto the database ane the username and password were successfully created
164 sqlite3_close(pDB);
165 sqlite3_finalize(pStmt);
166 return true;
167}
168
169//this function will take a password,username,and database and check the given password against the password stored in the database
170bool check_password (std::string password, const std::string &username, const std::string &database)
171{
172 //first we open the database
173 sqlite3 *pDB;
174 int rc= sqlite3_open(database.c_str(),&pDB);
175 if (rc != SQLITE_OK)
176 return false;
177 //now we create our sqlite3 string to select the password from the table where the user name matches
178 std::string sql= "SELECT PASSWORD,SALT FROM USERS WHERE USERNAME = ?;";
179 sqlite3_stmt *pStmt= nullptr;
180 rc = sqlite3_prepare_v2(pDB,sql.c_str(),sql.size(),&pStmt,nullptr);
181 if (rc != SQLITE_OK)
182 {
183 sqlite3_close(pDB);
184 sqlite3_finalize(pStmt);
185 return false;
186 }
187 //now we bind the username to the sqlite3 statement
188 rc= sqlite3_bind_text(pStmt,1,username.c_str(),username.size(),nullptr);
189 if (rc != SQLITE_OK)
190 {
191 sqlite3_close(pDB);
192 sqlite3_finalize(pStmt);
193 return false;
194 }
195 //check for username
196 if (sqlite3_step(pStmt) != SQLITE_ROW)
197 {
198 sqlite3_close(pDB);
199 sqlite3_finalize(pStmt);
200 return false;
201 }
202 //if we are still here username was found
203 std::string salt;
204 std::string curPword;
205
206 curPword.assign((const char*)sqlite3_column_text(pStmt, 0), sqlite3_column_bytes(pStmt, 0));
207 salt.assign((const char*)sqlite3_column_text(pStmt,1), sqlite3_column_bytes(pStmt,1));
208
209 sqlite3_finalize(pStmt);
210 sqlite3_close(pDB);
211 //now we compare thengiven password to the password stored in the database
212 //firsr we must hash the password given using (hensalt that was stored in the database
213
214
215 std::string hashed;
216 password += salt;
217 hashed=create_hash(password);
218
219 return hashed==curPword;
220}
221
222//this function will allow us to change a password at a given username
223bool change_password (std::string password, const std::string &username, const std::string &database)
224{
225 //first we open the database
226 sqlite3 *pDB;
227 int rc= sqlite3_open(database.c_str(),&pDB);
228 if (rc != SQLITE_OK)
229 return false;
230 //now we prepare our sqlite3 statement
231 std::string sql= "UPDATE USERS SET PASSWORD = ?1"
232 "WHERE USERNAME = ?2";
233 //now lets generate a new salt and hash the password
234 std::string salt= create_salt();
235 password += salt;
236 std::string hashed = create_hash(password);
237 //now we bind the usename and password
238 sqlite3_stmt *pStmt = nullptr;
239 rc= sqlite3_prepare_v2(pDB,sql.c_str(),sql.size(),&pStmt,nullptr);
240 if (rc != SQLITE_OK)
241 {
242 sqlite3_close(pDB);
243 sqlite3_finalize(pStmt);
244 return false;
245 }
246 rc= sqlite3_bind_text(pStmt,2,username.c_str(),username.size(),nullptr);
247 if (rc != SQLITE_OK)
248 {
249 sqlite3_close(pDB);
250 sqlite3_finalize(pStmt);
251 return false;
252 }
253 rc= sqlite3_bind_text(pStmt,1,hashed.c_str(),hashed.size(),nullptr);
254 if (rc != SQLITE_OK)
255 {
256 sqlite3_close(pDB);
257 sqlite3_finalize(pStmt);
258 return false;
259 }
260 if (sqlite3_step(pStmt) != SQLITE_DONE)
261 {
262 sqlite3_close(pDB);
263 sqlite3_finalize(pStmt);
264 return false;
265 }
266 //now we must change the salt to the new one
267 sql= "UPDATE USERS SET SALT = ?1"
268 "WHERE USERNAME = ?2";
269 sqlite3_finalize(pStmt);
270 rc= sqlite3_prepare_v2(pDB,sql.c_str(),sql.size(),&pStmt,nullptr);
271 if (rc != SQLITE_OK)
272 {
273 sqlite3_close(pDB);
274 sqlite3_finalize(pStmt);
275 return false;
276 }
277 rc= sqlite3_bind_text(pStmt,2,username.c_str(),username.size(),nullptr);
278 if (rc != SQLITE_OK)
279 {
280 sqlite3_close(pDB);
281 sqlite3_finalize(pStmt);
282 return false;
283 }
284 rc= sqlite3_bind_text(pStmt,1,salt.c_str(),salt.size(),nullptr);
285 if (rc != SQLITE_OK)
286 {
287 sqlite3_close(pDB);
288 sqlite3_finalize(pStmt);
289 return false;
290 }
291 if (sqlite3_step(pStmt) != SQLITE_DONE)
292 {
293 sqlite3_close(pDB);
294 sqlite3_finalize(pStmt);
295 return false;
296 }
297 //if we are here then the salt w&s changed, thus we have updated our (hashed) password as well as the salt
298 sqlite3_close(pDB);
299 sqlite3_finalize(pStmt);
300
301 return true;
302}
303
304//this function will create thensalt added to the password
305std::string create_salt()
306{
307 //characters used to produce the salt
308 const char alphanum[]= "0123456789"
309 "!@#$%&^"
310 "abcdefghijklmnopqrstuvwxyz"
311 " ABCDEFGHIJKLMNOPQRSTUVWXYZ";
312 int stringLength = sizeof(alphanum)-1;
313 //the followingnwill be used to generate our random number to be used as an index into our alphanum
314 std::random_device rd;
315 static std::mt19937 mt(rd());
316 std::string salt;
317 //now we create our salt
318 for (int i=0;i<36;++i)
319 {
320 //although it goes against convention, instantiating the distribution inside of the loop actually speeds the algorithm up by almost 1/3µm, as noted by Mr.Cheinan Marks at CppCon 2016
321 std::uniform_int_distribution<int> dist(0,stringLength);
322 salt.push_back(alphanum[dist(mt)]);
323 }
324 return salt;
325}
326