PHP's Encryption Functionality
Pages: 1, 2, 3
User authentication with crypt()
As an example of the use of the crypt() function, consider a scenario where
you are interested in creating a PHP script that restricts a certain
directory, allowing only those users supplying a correct user name and
password to enter this directory. I'll store this information in a table
residing on my favorite database server, MySQL. I'll begin by creating the table (titled "members"):
mysql>CREATE TABLE members (
->username CHAR(14) NOT NULL,
->password CHAR(32) NOT NULL,
->PRIMARY KEY(username)
->);
Next, assume that the following data is found in the members table:
| Username | Password |
| clark | keloD1C377lKE |
| bruce | ba1T7vnz9AWgk |
| peter | paLUvRWsRLZ4U |
These encrypted passwords correspond to "kent", "banner", and "parker",
respectively. Notice that the first two letters of each password correspond
to their unencrypted counterparts. This is because I used the following code
to create a salt based on the first two letters of the password:
// Password is entered in an administration
// form and stored as
$enteredPassword.
$salt = substr($enteredPassword, 0, 2);
$userPswd = crypt($enteredPassword, $salt);
// $userPswd is then stored in the MySQL
// database along with the username.
I'll make use of Apache's challenge-response authentication scheme to prompt
the user for a user name and password. A little-known fact about PHP is that
it recognizes Apache's challenge-response input user name and password as the
global variables $PHP_AUTH_USER and $PHP_AUTH_PW respectively, which I'll
make use of in the authentication script. Take a moment to read through the
following script, paying particular attention to the comments so as to
better understand the code flow:
Listing 1: Using crypt() and Apache's challenge-response authentication scheme.
<?php
$host = "localhost";
$user = "zorro";
$pswd = "hellodolly";
$db = "users";
// Set authorization to False
$authorization = 0;
// Verify that user has entered username and password
if (isset($PHP_AUTH_USER) && isset($PHP_AUTH_PW)) :
mysql_pconnect($host, $user, $pswd) or die("Can't connect to MySQL
server!");
mysql_select_db($db) or die("Can't select database!");
// Perform the encryption
$salt = substr($PHP_AUTH_PW, 0, 2);
$encrypted_pswd = crypt($PHP_AUTH_PW, $salt);
// Build the query
$query = "SELECT username FROM members WHERE
username = '$PHP_AUTH_USER' AND
password = '$encrypted_pswd'";
// Execute the query
if (mysql_numrows(mysql_query($query)) == 1) :
$authorization = 1;
endif;
endif;
// confirm authorization
if (! $authorization) :
header('WWW-Authenticate: Basic realm="Private"');
header('HTTP/1.0 401 Unauthorized');
print "You are unauthorized to enter this area.";
exit;
else :
print "This is the secret data!";
endif;
?>
There you have it -- a simple authentication scheme for verifying user access.
Before using crypt() to protect important secrets such as directions to the
secret hiding place of the family jewels, keep in mind that crypt() when
used in its default form is certainly not the most secure algorithm in the
world, and should not be used for anything other than low-level
authentication. For those of you searching for a more robust encryption
scheme, hold tight, as I'll be introducing several later in this article.
Next, I'll introduce another PHP-supported function -- md5(). This
function, which uses the MD5 hashing algorithm, has several interesting uses
worth noting.
Hashing
A hash function will transform some variable-length message into a
fixed-length hashed outcome, also known as a "message digest." This is useful
because this fixed-length string can then be used as a method for checking
file integrity and verifying digital signatures, in addition to things such
as user authentication. As it pertains to PHP, PHP's built-in md5() hashing function will
convert any variable-length message into a 128-bit (32-character)
message digest. The interesting thing about hashing is that it is impossible
to decode a message by examining the hash, because the hashed result is in no
way related to the content of the original plain text. To illustrate this,
consider that just changing one character of a string will cause
the MD5 hashing algorithm to calculate two vastly different outcomes. First
consider Listing 2 and its corresponding outcome.
Listing 2: A string hashed with md5().
<?php
$msg = "This is some message that I just wrote";
$enc_msg = md5($msg);
print "hash: $enc_msg
";
?>
The outcome:
hash: 81ea092649ca32b5ba375e81d8f4972c
Notice that the outcome is 32 characters long. Now consider Listing 3,
which contains a slightly modified $msg value:
Listing 3: A slightly modified string hashed with md5().
<?php
// Notice that 'message' is missing an 's'
$msg = "This is some mesage that I just wrote";
$enc_msg = md5($msg);
print "hash2: $enc_msg <br /><br />";
?>
The outcome:
hash2: e86cf511bd5490d46d5cd61738c82c0c
As you can see, a minor change in the message string will cause two
vastly different hashing outcomes, although each result is still 32 characters. And thus hashing and the md5() function are
great tools for checking for even the most minor differences in data.
While crypt() and md5() each have their uses, both are rather limited in
terms of functionality. In the next section, I'll introduce two very useful
PHP extensions, namely Mcrypt and Mhash, which greatly extend a PHP user's
encryption options.
While in the last section you learned just how useful one-way encryption could be, there are times when you will want the option to be able to both encrypt and subsequently decrypt data. Thankfully, PHP offers this possibility in the form of the Mcrypt library extension.
