base_64 encode with key and salt

Discussions of secure PHP coding. Security in software is important, so don't be afraid to ask. And when answering: be anal. Nitpick. No security vulnerability is too small.

Moderator: General Moderators

Post Reply
User avatar
egg82
Forum Contributor
Posts: 156
Joined: Sat Oct 01, 2011 9:29 pm
Location: Colorado, USA

base_64 encode with key and salt

Post by egg82 »

My college asked me to lead a team and design and develop a website for a project they're putting out. It's a long story.
Anyway, this site will be viewed and used by colleges throughout the US. It will be a place for students and teachers to
share files and collaborate on said project.

I thought I might need to include some security with this. Just a thought.
I needed a way to encrypt data for storage and then decrypt it for readability.

I looked at PHPs mcrypt, but I had a problem with it: It wasn't core. I had absolutely no idea what my or any other college was going to do with or where they were going to put it this once it was done, so I need the whole thing to be as flexible and ready-to-go as possible.
So I looked at base_64 - too easy to just rewash through the decode.

I finally found, on another forum, a set of functions that pretty much solved my problem. encrypt($string, $key) and decrypt($string, $key)
Well, I wanted one solid key for this, so I simply hard-coded it into another require()d page (this other page checks to see if the server's name is on a whitelist and connects to the DB if it is)

Still wasn't good enough. I'm going to potentially be dealing with everyone in the US (and I guarantee a whole bunch of security experts are going to run through my code before it goes live). I needed a salt, but I didn't want to have to type in a salt every single time I wanted to run the function. In essence, I wanted an encrypt($string) and a decrypt($string) which I pretty much achieved by having a "master" password. The point of this encryption is the encrypted data is stored in the database so in case the DB is compromised, all the attacker will get is a bunch of who knows what.

I edited and re-edited and finally came up with this:

Code: Select all

function encrypt($string, $key){
	$result = "";
	for($i=0; $i<strlen($string); $i++){
		$char = substr($string, $i, 1);
		$keychar = substr($key, ($i % strlen($key))-1, 1);
		$char = chr(ord($char)+ord($keychar));
		$result.=$char;
	}
	$salt_string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxys0123456789~!@#$^&*()_+`-={}|:<>?[]\;',./";
	$length = rand(1, 15);
	$salt = "";
	for($i=0; $i<=$length; $i++){
		$salt .= substr($salt_string, rand(0, strlen($salt_string)), 1);
	}
	$salt_length = strlen($salt);
	$end_length = strlen(strval($salt_length));
	return base64_encode($result.$salt.$salt_length.$end_length);
}
function decrypt($string, $key){
	$result = "";
	$string = base64_decode($string);
	$end_length = intval(substr($string, -1, 1));
	$string = substr($string, 0, -1);
	$salt_length = intval(substr($string, $end_length*-1, $end_length));
	$string = substr($string, 0, $end_length*-1+$salt_length*-1);
	for($i=0; $i<strlen($string); $i++){
		$char = substr($string, $i, 1);
		$keychar = substr($key, ($i % strlen($key))-1, 1);
		$char = chr(ord($char)-ord($keychar));
		$result.=$char;
	}
	return $result;
}
For obvious reasons this isn't the whole code, but you can get the gist of it.
So my question is this: Is this secure enough for a database? I will use this on top of an md5() for passwords
User avatar
Mordred
DevNet Resident
Posts: 1579
Joined: Sun Sep 03, 2006 5:19 am
Location: Sofia, Bulgaria

Re: base_64 encode with key and salt

Post by Mordred »

This is a really really stupid code. It was written by someone who hasn't even read a basic book on cryptography.
No offense, but you yourself should not take security decisions like that either. Especially you should *not* eschew proven cryptographic primitives and replacing them with homebrew code.
About your concerns about support for mcrypt - wouldn't you control the installation environment? Having mcrypt installed should be pretty standard for any hosting.
Another concern you *should* have is that there are lots of interesting ways you can screw your encryption security even with mcrypt :)
What data will you encrypt and why? For how long? How would you manage the keys? How and when would it be decrypted?
User avatar
egg82
Forum Contributor
Posts: 156
Joined: Sat Oct 01, 2011 9:29 pm
Location: Colorado, USA

Re: base_64 encode with key and salt

Post by egg82 »

I understand that having a salt with a way around it in the string is a semi-bad idea. However, I would like to make a few points.

First, this is not the entire encryption. I also use another encryption method on top of it, as well as a few modifications to this one as well as another salt.
The only reason i'm using a "homebrew" method is - of course - because it will be more difficult for the attacker to get (or in this case, create) a solution.
the method above is by no means a replacement. It's simply an add-in.

Another note: I discovered my mistake with the salt. The string is now salted before it is encrypted.

Next, why would I add a way around the salt in the encrypted string? Because, to me, a salt does two things:
1) it makes the entire thing harder to decrypt, and
2) it gives the string a more "random" appearance, to help deter attackers.
So, being honest with myself, if they really want to get around the salt, storing it separately will not help. I might as well make it easier on myself.

To answer your question: I honestly have no idea how much control i'm going to have. They promise me that i'm going to be running the entire thing, but... Well, let's just say i've been promised that before by people like this. Eventually they're going to take over in one way or another; I might as well make sure they can't screw too much up. The only reason i'm doing this is because if it succeeds, I will end up with one hell of a boost on my resume.

And last: I will encrypt almost everything going into the database. Passwords will be md5()d under the encryption (ie. encrypt(md5($password), $key))
I say "almost" because there's a few things that really don't need to be encrypted (ie. Online status, date and time of last action, etc.)
The data will be stored indefinitely. Or at least until someone decides to delete the database. There is only one key. The key used is... I don't even know how long. I think around 25 characters, all of which are semi-random. The data will only be decrypted when it needs to be used. So far only in two cases: When logging in, and when viewing data in the database (for administrative purposes, mostly)
User avatar
egg82
Forum Contributor
Posts: 156
Joined: Sat Oct 01, 2011 9:29 pm
Location: Colorado, USA

Re: base_64 encode with key and salt

Post by egg82 »

I do appreciate your thoughts, though :D

I showed the whole PHP code to my security professor and he approved it, so I think it should be good enough. However, I still haven't really stored anything in the actual database and would be glad for some improvements
User avatar
Mordred
DevNet Resident
Posts: 1579
Joined: Sun Sep 03, 2006 5:19 am
Location: Sofia, Bulgaria

Re: base_64 encode with key and salt

Post by Mordred »

You seem to be mixing up one-way hashing and encryption. Salting is something you do for plaintexts that are to be hashed. When using block ciphers there is a similar concept, Initialization Vectors. What you do with that "encryption" (and I use the term losely ;) ) will not benefit from it. Encrypt more than a couple of k plaintext or more than a couple of m non-random binaries and your 25 character password will fail.

If I see such code on your resume, you'll have to have a hell of a reason why you did it this way. "Because the homebrew algorithm is unknown to the attacker" is a classic cryptography pitfall. The idea not to do that has been around since the 19th century.
I don't know what is the speciality of your "security professor", but if I, a layman, can see the glaring hole, it puts serious doubt to his knowledge (or of course he might just have said "yeah, it's fine" without giving it a read at all - gotta love the academia ;) )

If you wanted advice, it's "don't do it man!" :) But of course everyone is entitled to make his own mistakes, it's your funeral :)
User avatar
egg82
Forum Contributor
Posts: 156
Joined: Sat Oct 01, 2011 9:29 pm
Location: Colorado, USA

Re: base_64 encode with key and salt

Post by egg82 »

haha, it's always a possibility he didn't actually read it.

Though a few questions:
1. Why not use salts for encryption and decryption as well?
The way I implemented it, it's not supposed to make it 100% infallible; just a pain in the rear for someone looking to forcefully decrypt it.

2. Why would the 25-character password fail?
I don't see a reason for it to; 100000/25 = 4000
30-4000 = ohhhhhhhhhhhhhhhhh
in that case, i'll check for a negative number and, if true, multiply it by -1 (-100*-1 = 100)
i'll also have to see how ord() handles ridiculously large numbers, and make corrections there if necessary
Well, thank you!

I read the wiki, and it seems (as I would have thought) that there is no problem in keeping the method a secret; as long as i'm not relying solely on that (which, thankfully, i'm not)
The point of this encryption is that it is simply (as wiki put it) another hurdle to overcome. It will not and should not ever be used in place of an encryption. I will be using it as an "add-in"

On a side note: I have just found out (in the last 2 seconds) that it seems that the host I will be working on supports mcrypt()
I'm going to toss this function completely, but I think I will keep the salt and pepper. True, they don't help much. However; they're not hurting anything, and it's kinda funny to watch my friend's faces when I encrypt "test" 3000 times and every single one is a different length. (that and i've already set up the register and login scripts to handle the "ever-changing" return)

My final question is on mcrypt():
Rijndael 256? Or something better?
Post Reply