patterncppMinor
Password and shadow file mockup
Viewed 0 times
fileshadowpasswordmockupand
Problem
I tried to implement something similar to the Linux shadow.txt file and I am not aware of concepts such as memory fingerprinting. Could someone please review this code?
```
#include
#include
#include
#include
#include
#include
#include
using namespace std;
vector split(string &s, char delim) {
vector elems;
stringstream ss(s);
string item;
while(getline(ss,item,delim))
elems.push_back(item);
return elems;
}
void load_hashes(map > &active, string &fileName) {
ifstream file(fileName);
string str;
while(getline(file,str)) {
vector elems = split(str,' ');
active[elems[0]] = {elems[1],elems[2]};
}
}
bool check_username_exists(map > &active, string username) {
if(active.find(username)!=active.end())
return true;
return false;
}
char md5_conversion(const char str) {
MD5_CTX c;
MD5_Init(&c);
MD5_Update(&c, str, 30);
unsigned char digest[16];
MD5_Final(digest, &c);
char md5string = (char) malloc(sizeof(char)*33);
for(int i = 0; i > &active, string& username, const char* password) {
if(check_username_exists(active,username)) {
cout > &active, string& username, const char* password) {
if(!check_username_exists(active,username)) {
cout > &active, string& username, const char* password) {
if(!check_username_exists(active,username)) {
cout > &active) {
for(auto elem : active)
cout > &active,string &fileName) {
ofstream file(fileName);
for(auto elems: active)
file > active;
string fileName = "secret.txt";
load_hashes(active,fileName);
print_map(active);
string username = "shubham";
// Limit password length to 20 characters
const char* password = "darkknight";
new_entry(active, username, password);
print_map(active);
check_entry(active,username, password);
const char* wrong_password = "fastestmanalive";
check_entry(active,username, wrong_password)
```
#include
#include
#include
#include
#include
#include
#include
using namespace std;
vector split(string &s, char delim) {
vector elems;
stringstream ss(s);
string item;
while(getline(ss,item,delim))
elems.push_back(item);
return elems;
}
void load_hashes(map > &active, string &fileName) {
ifstream file(fileName);
string str;
while(getline(file,str)) {
vector elems = split(str,' ');
active[elems[0]] = {elems[1],elems[2]};
}
}
bool check_username_exists(map > &active, string username) {
if(active.find(username)!=active.end())
return true;
return false;
}
char md5_conversion(const char str) {
MD5_CTX c;
MD5_Init(&c);
MD5_Update(&c, str, 30);
unsigned char digest[16];
MD5_Final(digest, &c);
char md5string = (char) malloc(sizeof(char)*33);
for(int i = 0; i > &active, string& username, const char* password) {
if(check_username_exists(active,username)) {
cout > &active, string& username, const char* password) {
if(!check_username_exists(active,username)) {
cout > &active, string& username, const char* password) {
if(!check_username_exists(active,username)) {
cout > &active) {
for(auto elem : active)
cout > &active,string &fileName) {
ofstream file(fileName);
for(auto elems: active)
file > active;
string fileName = "secret.txt";
load_hashes(active,fileName);
print_map(active);
string username = "shubham";
// Limit password length to 20 characters
const char* password = "darkknight";
new_entry(active, username, password);
print_map(active);
check_entry(active,username, password);
const char* wrong_password = "fastestmanalive";
check_entry(active,username, wrong_password)
Solution
- Half of your code is written in C, the other half in C++. There is no reason to use plain
char[]when you can have the powerfulstd::string.
- When you work with plain arrays (like for passwords), make sure you don't overflow them. Every array access must provably have a valid index.
- Instead of computing
md5(password + salt), feed the two parts independently into the MD5 computation. That way you don't have to concatenate them, so the buffer overflow vulnerability goes away.
- Don't use
using namespace std.
- You must check array indexes when loading data from untrusted files (e.g. after the
split).
- Passing a
map>around is bad for a human reader, since it is totally unclear what each of thestringmeans.
- The variable name
activeis usually of typeboolean, notmap. Yiu should find a better name for that.
- Error messages typically go to
std::cerr, notstd::cout.
- The function
testshould fail automatically instead of letting a human check its complete output.
- When storing the hashes, first write to a temporary file. When all has gone well (check for errors!), rename the temporary file to its final destination. This prevents massive data loss in case the disk gets full.
- Enable compiler warnings.
- 0 is not a boolean value. At least not for humans. So when you return from a
boolfunction, don't return0, returnfalseinstead.
- There is a requirement (limit password to 20 chars) that you haven't yet implemented. Nor should you, since passwords should not have an upper limit for the length. So delete that comment.
- Your code leaks the plaintext password, since it is copied to
password_plus_salt, but that array is not cleared after use. The point of using plain char arrays for passwords is exactly to be able to clear them after use. Whenever you clean an array after use, make sure that the generated machine code actually does clean. Many compilers optimize it away if it is improperly written. OpenSSL has a utility function to do this.
Context
StackExchange Code Review Q#132734, answer score: 2
Revisions (0)
No revisions yet.