Simple hash algorithm

Hi guys,

I'm trying to create a hash algorithm (a very simple one) for homework exercise.

I basically have taken an input from the user and hash it using:

a = 1, b =2, c = 3 ... z = 26.

So if the user input is abc, it will store 123.

My functions for creating a username and password so far:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// registering an account
void regAccount()
{
	cout << "Please enter your username: ";
	cin >> inputUsername; cout << endl;
	if (inputUsername == username[0] || inputUsername == username[1] || inputUsername == username[2] || inputUsername == username[3] || inputUsername == username[4] ||
		inputUsername == username[5] || inputUsername == username[6] || inputUsername == username[7] || inputUsername == username[8] || inputUsername == username[9])
	{
		cout << "Username already exists" << endl;
	}
	else
	{
		for (i = 0; i < 10; i++)
		{
			if (username[i] == "Empty")
			{
				username[i] = inputUsername;
				hashPass();
				cout << "Is this account an admin?    -    1 = yes / 2 = no: ";
				cin >> input;
				if (input == 1)
				{
					admin[i] = true;
				}
				else
				{
					admin[i] = false;
				}
				break;
			}
		}
	}	
}

// hash the password
void hashPass()
{
	cout << "Please enter your password: ";
	cin >> password[i]; cout << endl;
	for (int j = 0; j < password[j].length(); j++)
	{
		// possibly a switch statement checking if password[i] == a, b, c...
	}
}


Thanks for having a look.
characters are integers, or bytes, and you can grab a few of them into an integer for a really quick approach.

A really easy way to do this is...

unsigned int *h;
char inputstring[10] = {0};
cin << inputstring;
h = (unsigned int*)(&inputstring[0]);

This works so long as the first few characters of input are unique.
Be sure to set ALL the characters in inputstring to 0 every time, or you will have problems!!

for a password, consider grabbing free code to generate sha1 from a string.
Hey jonnin thanks for the input.

Although i'm trying to learn basics of coding just now so probably doing things are not written optimally.

I'm basically storing 10 usernames in an array and 10 passwords in an array then checking then when taking the input from the user to login it will check the username[i] against password[i] to see if they are correct. However i've been asked to hash the password with a very basic algorithm i.e a =1, b = 2, c = 3 and i'm not quiet sure how to do this.

I thought I could just hash the password in a for loop such as:
1
2
3
4
5
6
7
8
9
10
for (int j = 0; j < password[j].length(); j++)
	{
		// possibly a switch statement checking if password[i] == a, b, c...

		//somthing like...
		// if password[i].substr(j, 1) == a
			//	password[i].substr(j, 1) = 1;
		// ....
	}
}


however the password array is a string and it will not allow me to use this in a switch statement.

Am I on the right track or?

Last edited on
So this is the idea I have for it

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void hashPass()
{
	cout << "Please enter your password: ";
	cin >> password[i]; cout << endl;
	for (int j = 0; j < password[j].length(); j++)
	{
		if (password[i].substr(j, 1) == "a")
		{
			password[i].substr(j, 1) = '1';
		}
		else if (password[i].substr(j, 1) == "b")
		{
			password[i].substr(j, 1) = '2';
		}
		else if (password[i].substr(j, 1) == "c")
		{
			password[i].substr(j, 1) = '3';
		}
                // continue on throughout the alphabet (i only need to use lower case at the moment)
	}
}


however it's giving me 'abort() has been called' error.
switch requires an integer.

Ok, lets start basic.
arrays are indexed from 0-n
typically you can hash into an array by creating a number from data, and then converting that into an array index. Typically you need to mash the number to fit into N and N typically needs to be significantly bigger than the input. You want to avoid having 2 or more inputs give the same array location.

you are on the right track.
But like I said, characters ARE integers.
so if you want to convert a letter to a number from 0-25 or whatever, just subtract.

val = password..blah.. - 'a';
will give you 0 for a, 1 for b, and so on. so you can just loop over the string this way!

Now, one way you could hash the thing is to build a number from that..

unsigned int hkey = -1;
for(I = 0; I < password...length; I++)
{
/// some sort of function to turn the above val into a hash key...
//how about
val = password..blah.. - 'a';
hkey ^= val;
}
hkey %= arraysize; //this is modulus, or "remainder"... it forces hkey into 0-arraysize!! This is critical...

now you can store the value
array[hkey] = inputstuff;

and remember, if you have 10 inputs, make array much bigger, so try 1000 maybe since this hash function is poorish, that would be safer to avoid collisions. Generally you would want to detect and handle collisions, but that can be done later, lets get this far first.


With all this info, try it once more. You seem to be on the right track, so I think you can do it now.



Last edited on
switches .. I do not use them much, but they work off ints.

so
ans = 0;
switch (password.substr...etc)
{
case 'a' : ans += 1;
case'b': ans += 2;
...
default: 35; //always use a default.
}

but this is not necessary because characters ARE integers ;)

there is really only 1 good use of a switch statement in my eyes.
that is, that if you leave off the break statements, everything after the case that is accepted executes.

here in my example, for a, ans = 3 and that is awesome.
if you put in breaks, it behaves differently...

ans = 0;
switch (password.substr...etc)
{
case 'a' : ans += 1; break;
case'b': ans += 2; break;
...
default: 35; //always use a default.
}

here, if you input a, ans is only 1.

The ability to perform the same tasks for several inputs and to cascade across multiple actions is really cool and powerful. It is also confusing to the reader though. Still, this is the one good use of them. Most of the rest of the time, because they only work off integers, they are inferior to if statements.


Don't worry about optimal. One of the best books ever written said (paraphrasing) "there is no such thing as the fastest code" ... someone will always be able to show you a better trick. (big black book of graphics programming). And honestly speed does not matter until you get to big data, dealing with millions of inputs / second. Getting stuff fast is a dying art among kids these days ... consider picking it up later ... but its really not important unless you develop real-time code, games, operating systems, drivers, or other performance critical software.
Last edited on
as for what is wrong with what you have,

password[i].substr(j, 1) = '3';

that seems wrong. I don't think substring function allows the result to be assigned directly. I could be wrong, but I suspect this statement.

it does not make a lot of sense anyway, '3' is a character, not the number 3.
you need an integer, and that integer can be built off converting the text to numbers in some fashion. You can convert a string of digits into a number, but if that is what you want, build up the digits by concatenation into a new string, don't damage your input data!

Last edited on
Hi jonnin thanks for all the input.

I have come a little further with this and it will correctly hash the password (albeit in a very poor way).

So I am using 3 functions at the moment, one to register a username and password into 2 arrays, both with 10 elements each. One to login with and one to hash the password.

The hashPass function will hash the password if I use it as a void hashPass(); and pass the array in as a global variable however this will cause problems when hashing what the user inputs as a password to login. So I have changed the function to a string hashPash(string passcheck); and return the string from it however it does not hash the password.

As far as I understand it its the same thing as I had written with the void function as when I call it i just pass password[i] as a parameter(this is what i had previously instead of 'passcheck' parameter).

The code is here as I don't think i'm explaining it very well.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// hash the password
string hashPass(string passcheck)
{
	// going through each letter in the password and changing the letter to its hash value
	// i.e a = 1, b = 2, c = 3... z = 26
	for (int j = 0; j < passcheck.length(); j++)
	{
		if (passcheck.substr(j, 1) == "a")
		{
			passcheck.replace(j, 1, "1");
		}
		else if (passcheck.substr(j, 1) == "b")
		{
			passcheck.replace(j, 1, "2");
		}
                // ......
                else if (passcheck.substr(j, 1) == "z")
		{
			passcheck.replace(j, 1, "26");
		}
         }
return passcheck;
}


and when I pass the parameters in using the register account function it looks like this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// registering an account
void regAccount()
{
	cout << "Please enter your username: ";
	cin >> inputUsername; cout << endl;
	for (int j = 0; j < 10; j++)
	{
		if (inputUsername == username[j])
		{
			cout << "Username already exists" << endl;
		}
	}
	for (int i = 0; i < 10; i++)
	{
		if (username[i] == "Empty")
		{
			username[i] = inputUsername;
			cout << "Please enter your password: ";
			cin >> password[i]; cout << endl;
			hashPass(password[i]); // <---- passing the password to be hashed in
			cout << "Is this account an admin?    -    1 = yes / 2 = no: ";
			cin >> input;
			if (input == 1)
			{
				admin[i] = true;
			}
			else
			{
				admin[i] = false;
			}
			break;
		}
	}
}


I realize there are much better ways to write this but for the purpose of this task I'm specifically asked to use this kind of algorithm


I hope this makes sense.
Last edited on
It seems ok... is it working as you needed?
No not when I pass in something as a parameter. When I call the function as a void function like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void hashPass()
{
	// going through each letter in the password and changing the letter to its hash value
	// i.e a = 1, b = 2, c = 3... z = 26
	for (int j = 0; j < password[i].length(); j++)
	{
		if (password[i].substr(j, 1) == "a")
		{
			password[i].replace(j, 1, "1");
		}
		else if (password[i].substr(j, 1) == "b")
		{
			password[i].replace(j, 1, "2");
		}
                //... and so forth 


It does infact hash the password the way I want it too.

HOWEVER...

I cannot use this method as it would not work correctly in the login function when it needs to hash the users input for the password and check if it matches the currently held hashed password.

The login function code is here:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// logging into an account
void login()
{
	cout << "Please enter your username: ";
	cin >> inputUsername; cout << endl;
	cout << "Please enter your password: ";
	cin >> inputPassword; cout << endl;
	hashPass();

	for (int i = 0; i < 10; i++)
	{
		
		if (inputUsername == username[i] && inputPassword == password[i])
		{		
			loginSuc = true;
			cout << "You have been logged in!" << endl;
			if (admin[i] == true)
			{
				cout << "This account is an admin" << endl;
			}
			else
			{
				cout << "This account is a normal user account" << endl;
			}
		}
	}
	for (int i = 0; i < 10; i++)
	{
		cout << "the hash for password " << i+1 << " is: " << password[i] << endl;
	}
}


As above when hashPass(); is called, it looks for password[i] in the function, but because this is not in a loop it will not work correctly.

I should note that password[i] is being used to check 10 different passwords in an array, same as username[i].

1
2
string username[10]{ "Empty", "Empty",  "Empty",  "Empty",  "Empty",  "Empty",  "Empty",  "Empty",  "Empty",  "Empty", }; // probably a better way to do this
string password[10]{ "Empty", "Empty",  "Empty",  "Empty",  "Empty",  "Empty",  "Empty",  "Empty",  "Empty",  "Empty", }; // probably a better way to do this 
Last edited on
I think you are missing the point of hashing. The output of the hash function should BE an array index. You should not be looping at all.. input the data, hash it, go to the location in the storage, if it is there, it matched. If it is not there, the data is new.

should literally flow like

read in str
x = hash(str)
if storage[x] is not empty...

I am really confused now. Are you trying to hash, or encrypt?

The output of the hash function should BE an array index

Quoting Wikipedia:
A hash function is any function that can be used to map data of arbitrary size to data of fixed size.
https://en.wikipedia.org/wiki/Hash_function

In the case of a hash-table, the result of hash applications are canonically used as indices into a collection of buckets. Maybe this is what you're confused about?

WRT encryption:
Certain cryptographically-secure hash functions are used in combination with a cryptographic salt in order to protect user data in the real world. This is what I believe OP is trying to do.

I should point out that the sorts of multiplicative hash functions that make decent general-purpose hashes for hash tables shouldn't be used in cryptography. But this is a toy, and so it's fine.
Last edited on
Yeah essentially all i'm doing is writing a very small program to store 10 usernames and passwords and then allow the user to login with these (it will only display a small message on successful login).

When they register there password it will convert it (i believe this is hashing) to numbers - very basic a = 1, b = 2, c =3 and so on.

Now when they enter the password to login, it will then hash this password and see if it matches the stored one.

So an example would be password entered is 'abc', this will be stored in the string as '123'. Now they login and enter 'abc' for password, it uses the same function and checks to see if 'abc' hashed = '123' which has been stored - it does so it logs them in.

The problem im having is when I pass parameters into the function it does not hash it, however when I just write in the actual function 'password[i]' instead of passing 'password[i]' into it through a parameter it does work.

Hope this cleared it up, sorry if i'm using the wrong terms as this is just a very basic program I assume is to help us learn hashing.
ok. I will look into it closely tonight. Its about noon here now, for reference.
OP: couln't you just use a std::map<char,int> to store the key(keyboard entry)/value (what you describe as 'hashing') pairs?
ohh, I think I see it.

I think you need to do this:
1) copy hashPass function into a new name or new overloaded version (same name, different parameters)
2) use a form like you had above: string hashPass(string passcheck) or string checkPass(string passcheck) or the like.

3) compute the password, but THIS new version must not mess with the password[i] variable. Instead, perform the same logic on a temp and return it.

so you get
string checkPass(string passcheck)
{
string temp;
// ... temp = ... a = 1, b =2 logic etc on passcheck
return temp;
}

and below

string result = checkPass(input);
if (result == password[i]. etc && inputname == password[i]...) //compare the user input name and the encrypted password values

then its good else fail .. you have this logic correct I THINK.

This brings up a bit of learning .... your code is not friendly to doing it in one function because your original hash function has hardcoded references to a variable. A better design is a function like the one above, then you could call that in a loop to populate the variable with 10 of them... but live and learn. This sort of thing takes a while to get a feel for. For now, 2 similar functions gets it done.



Last edited on
Ok so I have this working the way I want now.

Basically I was calling the function hashPass(password[i]); to hash the password then hashPass(inputPassword); to hash there input when logging in and checking if it matches the stored hash password.

However when I called it, it was only changing the local variable instead of the one being displayed in main.

So basically I had to write 'password[i] = hashPass(password[i]);' to change the variable I wanted to.

I am an idiot, today I learned I guess.

Thanks for all the input though I appreciate the time you've spared to help.
you are not an idiot, we all went thru our learning period. Glad to help somone who was trying. Sorry for the confusion; where I work hash = a lookup / storage and encryption = encryption. I missed what you were doing at first a bit.

Topic archived. No new replies allowed.