PHP Cryptography

This article will define two-way key cryptography and explain how it differs from other well known PHP functions, like md5 and rot13, and when it is appropriate to use one-way hashing or two-way encryption. Then we will step through installing mcrypt as a dynamically loadable extension. We will explore two applications: encrypting cookies, and encrypting database information (such as credit card numbers). The article will point out some of the security implications of creating an encryption/decryption scheme in a plain text scripting language, and offer solutions such as encoding, source-compiling commands, and authoring new extensions.

Why Cryptography?
_The human heart has hidden treasures,
In secret kept, in silence sealed. _
-Charlotte Brontë, Evening Solace

Part of human nature is the desire to conceal. In computing, this is cryptography - the study of hiding and unhiding information. With the advent of the Internet, it has never been more relevant. One of the most useful forms of cryptography, made popular by PGP, is two-way key cryptography.
This article will define two-way key cryptography and explain how it differs from other well known PHP functions, like md5 and rot13, and when it is appropriate to use one-way hashing or two way encryption. Then we will step through installing mcrypt as a dynamically loadable extension. We will explore two applications: encrypting cookies, and encrypting database information (such as credit card numbers). The article will point out some of the security implications of creating an encryption/decryption scheme in a plain text scripting language, and offer solutions such as encoding, source-compiling commands, and authoring new extensions.

This article is aimed at more advanced users of PHP, though I have made every effort to make the conceptual information accessible. Readers interested in more secure methods for database encryption will benefit from knowledge of C and/or the Zend encoder. Readers may also find it useful to review Chris Shiflett's article on sessions security ( http://www.php-mag.net/itr/online_artikel/psecom,id,513,nodeid,114.html ), and Björn Schotte's article on encoding PHP and Zeev Suraski's article on authoring PHP extensions, from Issue 01.04 of the international php magazine.

Cryptography Defined
The Oxford English Dictionary defines cryptography as, "A secret manner of writing ... intelligible only to those possessing the key; also anything written in this way. Generally, the art of writing or solving ciphers." The word cipher (also spelled cypher) comes from the Arabic safira, which means, "of nothing", "empty", or "zero." Arabs were the first to formalize the concept of zero in mathematics as a placeholder that can increase the value of the numeral to its left by an order of ten (as in 1 becomes 10 and 10 becomes 100 by writing zeros out to the right). If you have ever tried to decipher large Roman numerals, you'll understand the value of the decimal system.
This often-misunderstood point of origin provides the missing link in the definition of cryptography: it is a mathematical (often algebraic - another Arabic invention) system of translating information into a new form (encrypting) and translating from the new form back to the original (decrypting).

A tremendous amount of information about cryptography is available in the hundreds of books written on this subject. There are also some very interesting historical accounts of early cryptographic systems, most notably in use during World War II. For now, we know what we're talking about.

Comparisons
We can gain a deeper understanding of cryptography by defining what it is not. The table in Table 1 illustrates the differences between the cryptography algorithms available in mcrypt and two other well-known systems.

**Tab.: 1: Comparison of md5, rot13, and mcrypt **

SchemeDirectionSecurity**Results **** **Key?Type
md5one-waysecuresamenohashing
rot13two-waynot securesamenomapping
mcrypttwo-waysecuredifferentyesencryption

First, we must point out that mcrypt cryptography is two-way. Although it is capable of generating one-way hashes, mcrypt for our purposes will be used to both encrypt and decrypt information. By contrast, md5 is a one-way scheme. What do we mean by this?
The simplest illustration of a one-way scheme would be to assign a numeric value to each ASCII character in a string, and then summate all those values. For purposes of our demonstration, we will use the existing numeric values (ordinal values) of ASCII characters (see Listing 1 and Listing 2).

Listing 1: A simple one-way mapping (one_way.php)

_ ```

//return an ordinal summation
function one_way ( $string){
for ( $i=0; $i < strlen( $string); $i++) {
$result += ord(substr( $string, $i));
}
return $result;
}

$test_1 = "Hello, world.";
$test_2 = "(%PHP Int'l Mag%)";
$test_3 = "foo";

print $test_1;
print ' = ';
print one_way( $test_1);
print '

1&lt;br/&gt;

';

print $test_2;
print ' = ';
print one_way( $test_2);
print '

1&lt;br/&gt;

';

print $test_3;
print ' = ';
print one_way( $test_3);

 1
 2**Listing 2: Browser Output**
 3
 4_Hello, world. = 1174  
 5(%PHP Int'l Mag%) = 1174   
 6foo = 324 _
 7
 8  
 9As you can see, there is more than one way to arrive at a value using one-way schemes. md5, unlike our simplistic summation example above, is designed to create unique outputs for each input.   
10md5 works on the principle that for every unique input a, it will generate a unique output b. But for every unique output b, it is very difficult (if not impossible) to guess the original value a. That is why it is considered both one-way and 'secure' for purposes of generating unique hashes. Md5 is used most commonly to create a unique signature for a file for purposes of comparison with another signature.   
11I have also seen md5 used to hash passwords for storage in a database of users. When the user enters their password in plain text, the system creates an md5 hash of the plain text password and compares it to the md5 hash stored in the system. If the hashes match, it is extremely likely that the passwords used to create the hashes also match. PHP's crypt function implements the same principle using DES, the standard for most UNIX passwords generated and stored in /etc/passwd. This can be useful if, for example, you want PHP to interface with an htaccess scheme, or even with /etc/password itself (don't try this at home).   
12  
13One of the simplest schemes for two-way encryption is rot13 (see Listing 3). This algorithm simply substitutes each character in the 26-letter English alphabet for a character 13 places to the right of the character, wrapping back to the beginning after z (see Listing 4).   
14  
15**Listing 3: A simple rot13 test (rot13.php)**
16
17_ ```
18   
19$s = 'abcdefghijklmonpqrstuvwxyz';   
20$s_0 = str_rot13( $s);   
21  
22print '

<code>';
print $s;
print "<br/>\n";
print $s_0;
print '</code>

 1';   
 2
 3``` _
 4
 5  
 6**Listing 4: Output**
 7
 8_abcdefghijklmonpqrstuvwxyz  
 9nopqrstuvwxyzbacdefghijklm _
10
11  
12The appeal of rot13 is that it is simple, not secure. Assuming a 26-character alphabet, you can use the same 13 character shift to encode as well as decode a string. rot13 was used on Usenet to obscure information others might find offensive, so that they would have to deliberately decode the information to read it. Wouldn't it be nice if modern day spammers did the same?   
13It should be noted that more advanced schemes like base_64 and rawurlencode fall into the same basic category as rot13: they are mappings. They simply map characters from one to another based on a table of values. For this reason, they can only be considered useful to temporarily obscure data. Because they are mathematically functional (two-way, with the same results every time) and therefore easily reversible, they should not be considered a secure encryption scheme.   
14By contrast, mcrypt algorithms seem to combine the best of the above two examples by introducing a key. Typically, this key is a password, though it can be anything (even binary data) with the right length for the algorithm. By combining both a key and an injection of random data (called `IV'), mcrypt encryption algorithms can encrypt information such that for each unique value called a, a different value (nearly every time) called b will be generated. This value b can only be returned to the original state a by passing the key and the same random data back into the mcrypt decryption algorithm. This is true encryption, and this is what the mcrypt library provides. 
15
16**Appropriate Use**   
17When do you need mcrypt? When will plain hashing or even mapping do?   
18  
19If you are looking to simply obscure information, simple mapping will do. By obscure, we mean make not immediately obvious, as in the Usenet use of rot13. If, however, you are passing along sensitive information you won't want to use rawurlencode. It doesn't really encrypt anything - it just maps characters in a predictable (i.e. insecure) way.   
20If you are just planning to compare something, use md5. This could be comparing files, comparing strings such as passwords, or even comparing a unique identifier you don't want someone to guess or reproduce. You can also introduce md5 at the stage where it is appropriate to provide additional security to true encryption/decryption schemes. We will discuss this more later in the article.   
21However, if you have information that needs to be stored somewhere insecure, information that will traverse the Internet (e.g. e-mail), or anything else where the data itself (not just the existence of the data, or the integrity of the data, for which md5 will suffice) needs to be secured, the kind of two way key cryptography provided by mcrypt is for you. 
22
23**Installation**   
24This installation will focus on Linux systems, however these instructions should be easily adaptable to other UNIXes (including Mac OS X, which I tested) and even Windows systems. For Debian users, getting mcrypt is as easy as   
25
26
27_# apt-get install php4-mcrypt  
28# apacectl restart _
29
30  
31For the rest of us, the process is a little more involved. I recommend building mcrypt as a dynamically loadable extension into PHP. It makes PHP more maintainable and upgradeable, since you don't have to keep recompiling. If you insist on compiling mcrypt into PHP, you can use the with mcrypt='/path/to/mcrypt' flag in your configure command after you have downloaded mcrypt.   
32Either way, you must first install libmcrypt. Libmcrypt is available at SourceForge . As root:   
33
34
35_# wget -c  
36'http://path/to/nearest/sourceforge/mirror/   
37for/latest/libmcrypt'   
38# gunzip libmcrypt-X.X.X.tar.gz   
39# tar -xvf libmcrypt-X.X.X.tar   
40# cd libmcrypt-X.X.X   
41# ./configure _
42
43  
44You should now have libmcrypt available as a shared module (but not a PHP shared module). Run:   
45
46
47_# ldconfig_
48
49  
50to make the shared object available on your Linux system for developing in C/C++. Next, compile the mcrypt dynamic module for PHP. First, you will need the PHP-devel package that contains the 'phpize' command. Red Hat currently supports this as an RPM. Other distributions may have to download and compile.   
51  
52Once you have PHP-devel, from the PHP source tree of the current version of PHP running on your server, type:   
53
54
55_# cd ext/mcrypt  
56# phpize   
57# aclocal   
58# ./configure   
59# make clean   
60# make   
61# make install _
62
63  
64You should now have mcrypt.so in /usr/lib/php4. Add the line:   
65
66
67_extension=mcrypt.so_
68
69  
70to /etc/php.ini, and issue:   
71
72
73_# apachectl restart_
74
75  
76Congratulations! You should now have mcrypt functions available in PHP. 
77
78**Testing Mcrypt**   
79I found the nested loop, shown in Listing 5, useful for checking the sanity of my libmcrypt install.   
80  
81**Listing 5: A simple loop to test all ciphers and modes (mcrypt_check_sanity.php)**
82
83_ ```
84   
85/* run a self-test through every listed   
86* cipher and mode   
87*/   
88function mcrypt_check_sanity() {   
89$modes = mcrypt_list_modes();   
90$algorithms = mcrypt_list_algorithms();   
91  
92foreach ( $algorithms as $cipher) {   
93if(mcrypt_module_self_test( $cipher)) {   
94print $cipher." ok.

<br/>

1\n";   
2} else {   
3print $cipher." not ok.

<br/>

 1\n";   
 2}   
 3foreach ( $modes as $mode) {   
 4if( $mode == 'stream') {   
 5$result = "not tested";   
 6} else   
 7if(mcrypt_test_module_mode   
 8( $cipher, $mode)) {   
 9$result = "ok";   
10} else {   
11$result = "not ok";   
12}   
13print $cipher." in mode   
14". $mode." ". $result."

<br/>

  1\n";   
  2}   
  3}   
  4}   
  5  
  6// a variant on the example posted in   
  7// mdecrypt_generic   
  8function mcrypt_test_module_mode   
  9( $module, $mode) {   
 10/* Data */   
 11$key = 'this is a very long key, even too   
 12long for the cipher';   
 13$plain_text = 'very important data';   
 14  
 15/* Open module, and create IV */   
 16$td = mcrypt_module_open( $module,   
 17'', $mode, '');   
 18$key = substr( $key, 0,   
 19mcrypt_enc_get_key_size( $td));   
 20$iv_size = mcrypt_enc_get_iv_size( $td);   
 21$iv = mcrypt_create_iv( $iv_size,   
 22MCRYPT_RAND);   
 23  
 24/* Initialize encryption handle */   
 25if (mcrypt_generic_init( $td, $key, $iv) !=   
 26-1) {   
 27  
 28/* Encrypt data */   
 29$c_t = mcrypt_generic( $td, $plain_text);   
 30mcrypt_generic_deinit( $td);   
 31  
 32// close the module   
 33mcrypt_module_close( $td);   
 34  
 35/* Reinitialize buffers for decryption*/   
 36/* Open module, and create IV */   
 37$td = mcrypt_module_open( $module, '',   
 38$mode, '');   
 39$key = substr( $key, 0,   
 40mcrypt_enc_get_key_size( $td));   
 41  
 42mcrypt_generic_init( $td, $key, $iv);   
 43$p_t = trim(mdecrypt_generic( $td,   
 44$c_t)); //trim to remove padding   
 45  
 46/* Clean up */   
 47mcrypt_generic_end( $td);   
 48mcrypt_module_close( $td);   
 49}   
 50  
 51if (strncmp( $p_t, $plain_text,   
 52strlen( $plain_text)) == 0) {   
 53return TRUE;   
 54} else {   
 55return FALSE;   
 56}   
 57}   
 58  
 59// function call:   
 60mcrypt_check_sanity();   
 61
 62``` _
 63
 64  
 65If you have at least a few algorithms (called ciphers) working correctly, you are ready to put mcrypt to use with these ciphers. If none of your ciphers (or worse, your favourite cipher) working, spend some time with the mcrypt manual at php.net. Otherwise, let's start encrypting and decrypting.   
 66  
 67**Encrypting Cookies**   
 68Cookies have long been branded as shameless spyware. This is because they have largely been used in predictable ways. Popular Web sites in particular used to contributed to this misperception by storing user information in plain text in cookies. Malicious sites posing as the original site that set the cookie could gain access to this information. Furthermore, this approach presents a security risk to the original site that set the cookie because such cookies can be manipulated in an attack on the site.   
 69Both of these scenarios - of a malicious third party using cookie information and of malicious users modifying their cookies in an attack - can be avoided by encrypting cookies. An encrypted cookie is useless to a third party, and is nearly impossible to tamper with.   
 70It should be said that the now infamous PHP sessions provide a layer of security to cookies they set by only setting a difficult to guess unique identifier that then keys into the rest of the information represented by a session. However, brute force attacks using the common cookie value 'PHPSESSID' would soon defeat this layer of "security." For more details on the security (and lack of security) in sessions, see Chris Shiflett's article, "The Truth About Sessions" ( www.php-mag.net/itr/online_artikel/psecom,id,513,nodeid,114.html ).   
 71The advantage of a true encryption scheme is that you are not limited to a single variable like a unique identifier. In fact, it is in cases where you must put valuable data into a cookie (like a password) that encryption is most appropriate. Wherever possible, simply keying into information stored on the server-side is preferred.   
 72For sake of simplicity, we will implement the two functions, shown in Listing 6, using the 'blowfish' algorithm in 'ecb' mode. This is because ecb mode does not rely on an IV, which makes the process slightly simpler.   
 73  
 74**Listing 6: cookie encryption/decryption functions (twofish_cookie.php)**
 75
 76_ ```
 77   
 78  
 79function my_encrypt( $string) {   
 80$key = 'supersecret';   
 81$key = md5( $key);   
 82  
 83/* Open module, trim key to max length */   
 84$td = mcrypt_module_open('twofish',   
 85'','ecb', '');   
 86$key = substr( $key, 0,   
 87mcrypt_enc_get_key_size( $td));   
 88  
 89/* Initialize encryption handle   
 90* (use blank IV)   
 91*/   
 92if (mcrypt_generic_init( $td, $key, `') !=   
 93-1) {   
 94  
 95/* Encrypt data */   
 96$c_t = mcrypt_generic( $td, $string);   
 97mcrypt_generic_end( $td);   
 98mcrypt_module_close( $td);   
 99return $c_t;   
100} //end if   
101}   
102  
103function my_decrypt( $string) {   
104$key = 'supersecret';   
105$key = md5( $key);   
106  
107/* Open module, trim key to max length */   
108$td = mcrypt_module_open('twofish',   
109'','ecb', '');   
110$key = substr( $key, 0,   
111mcrypt_enc_get_key_size( $td));   
112  
113/* Initialize encryption handle   
114* (use blank IV)   
115*/   
116if (mcrypt_generic_init( $td, $key, `') !=   
117-1) {   
118  
119/* Encrypt data */   
120$c_t = mdecrypt_generic( $td, $string);   
121mcrypt_generic_end( $td);   
122mcrypt_module_close( $td);   
123return trim( $c_t); //trim to remove   
124//padding   
125} //end if   
126}   
127  
128function my_encryptcookie( $string) {   
129return base64_encode(my_encrypt( $string));   
130}   
131  
132function my_decryptcookie( $string) {   
133return my_decrypt(base64_decode( $string));   
134}   
135
136``` _
137
138  
139Note that we have used md5 on our very secret string, 'supersecret' to generate a key that has more variance in it than traditional plain text. Because these ciphers are fixed-width, they will often pad their output to the correct length of characters using white space, so we also use trim() on the output to return the string to its original state.   
140We have also created wrapper functions to our core functions that transform the binary output of the encrypt function into a string, and transform the string to be decrypted back to binary before passing it to the core decrypt function. This is an important step for purposes of setting cookies and dealing with other types of data that should be MIME compliant. Next, we will try it out:   
141
142
143_ ```
144   
145include("twofish_cookie.php");   
146print my_decrypt(my_encrypt   
147("Hello, world.

<br/>

1\n"));   
2print my_decryptcookie   
3(my_encryptcookie("Hello, world.

<br/>

  1\n"));   
  2
  3``` _
  4
  5  
  6and the browser output is:   
  7
  8
  9_Hello, world.  
 10Hello, world. _
 11
 12  
 13Also note that because the cryptography functions we wrote are exact compliments of each other, you can run:   
 14
 15
 16_ ```
 17   
 18include("twofish_cookie.php");   
 19print my_encrypt(my_decrypt("Hello, world."));   
 20
 21``` _
 22
 23  
 24for which, the browser output is the following:   
 25
 26
 27_Hello, world._
 28
 29  
 30Note that the order of the base_64 functions used in the cryptcookie wrappers will not work:   
 31
 32
 33_ ```
 34   
 35include("twofish_cookie.php");   
 36print my_encryptcookie(my_decryptcookie("Hello, world."));   
 37
 38``` _
 39
 40  
 41in this case, the browser output is:   
 42
 43
 44_Hello+worlc_
 45
 46  
 47since the base64_decrypt function is acting on an already decrypted string. This is because base64 is a mapping scheme that overlaps. In rot13, the overlap was inconsequential since mapping is the same for encryption and decryption. Not so in base64. Let's set a cookie, as shown in Listing 7.   
 48  
 49**Listing 7: set_twofish_cookie.php**
 50
 51_ ```
 52   
 53include("twofish_cookie.php");   
 54if( $_COOKIE['test']) print   
 55my_decryptcookie( $_COOKIE['test']);   
 56else {   
 57$s = my_encryptcookie("Hello, world.");   
 58if(setcookie('test', $s, time()+3600)) {   
 59print 'Cookie set.';   
 60}   
 61}   
 62
 63``` _
 64
 65  
 66On first call, this page will set a cookie called 'test' with an encrypted version of the string, "Hello, world." On subsequent calls from the same client, it will decrypt and print the cookie.   
 67You have now successfully encrypted information in a cookie delivered to your client, and decrypted that information for use in your application. Used properly (with good variance in the key) this scheme will be much more effective than simply base64 or URL encoding your data, and should also provide a greater degree of security than using sessions. 
 68
 69**Encrypting SQL Data**   
 70Let us now consider a more advanced application. Suppose you run an e-commerce company that processes credit card information on a regular basis. You will need to store this information somewhere, and an SQL database may be a logical choice. You may need to store this information only between the time of purchase and the time of processing, or even longer in the case of subscription services that automatically renew. The longer you store the information, the more likely it is to accumulate; the more information that accumulates, the more your database grows in potential value to a malevolent intruder. If you are simply storing this information as plain text, be aware that if your database were compromised all of this information would be made immediately available to the attacker.   
 71Furthermore, with the advent of PHPMyAdmin and its prolific use in managing MySQL databases over the Web, it should be noted that attackers now have one more avenue to attempt to gain access to a MySQL database that does not require system privileges - only the privileges set up for the directory under which PHPMyAdmin resides. If this data is stored in plain text, an attacker could potentially access sensitive information from the convenience of their Web browser.   
 72The solution? Two-way encryption will allow you to store and retrieve this data, so that while it is in the database it is encrypted, and while it is being displayed to authorized individuals it is decrypted (see Listing 8).   
 73  
 74**Listing 8: AES Encryption (aes_sql.php)**
 75
 76_ ```
 77   
 78function my_encrypt( $string) {   
 79srand((double) microtime() * 1000000);   
 80//for sake of MCRYPT_RAND   
 81  
 82$key = 'supersecret';   
 83$key = md5( $key);   
 84  
 85/* Open module, and create IV */   
 86$td = mcrypt_module_open('rijndael-128',   
 87'','cfb', '');   
 88$key = substr( $key, 0,   
 89mcrypt_enc_get_key_size( $td));   
 90$iv_size = mcrypt_enc_get_iv_size( $td);   
 91$iv = mcrypt_create_iv( $iv_size,   
 92MCRYPT_RAND);   
 93/* Initialize encryption handle */   
 94if (mcrypt_generic_init( $td, $key, $iv) !=   
 95-1) {   
 96  
 97/* Encrypt data */   
 98$c_t = mcrypt_generic( $td, $string);   
 99mcrypt_generic_deinit( $td);   
100mcrypt_module_close( $td);   
101$c_t = $iv. $c_t;   
102return $c_t;   
103} //end if   
104}   
105  
106function my_decrypt( $string, $key) {   
107$key = md5( $key);   
108  
109/* Open module, and create IV */   
110$td = mcrypt_module_open('rijndael-128',   
111'','cfb', '');   
112$key = substr( $key, 0,   
113mcrypt_enc_get_key_size( $td));   
114$iv_size = mcrypt_enc_get_iv_size( $td);   
115$iv = substr( $string,0, $iv_size);   
116$string = substr( $string, $iv_size);   
117/* Initialize encryption handle */   
118if (mcrypt_generic_init( $td, $key, $iv) !=   
119-1) {   
120  
121/* Encrypt data */   
122$c_t = mdecrypt_generic( $td, $string);   
123mcrypt_generic_deinit( $td);   
124mcrypt_module_close( $td);   
125return $c_t;   
126} //end if   
127}   
128
129``` _
130
131  
132Here we are using cbc mode, which does regard the IV. So, we have prepended the IV to the resulting string and, because it is fixed width, we can easily retrieve it for decryption using substr(). Next, a simple test:   
133
134
135_ ```
136   
137include("aes_sql.php");   
138  
139$string = "Hello, world.";   
140print my_decrypt(my_encrypt( $string),   
141'supersecret');   
142
143``` _
144
145  
146Note that we have not created wrappers for this function like we did for the cookie functions, earlier in the article. If you are storing data as anything other than blob in your database, you may want to create the appropriate wrapper function akin to what we did in the cookies example to make sure SQL approves of your query.   
147This example also differs from the cookie example in that the decrypt function now accepts a key. For Web-based processing systems, it could be useful to have the decryption key (which must be the same as the encryption key) match some password required to access the system. This approach, of having the decryption password passed in to the function from an outside source, adds a layer of security to your application because an outside attacker would have to know the password to work the decrypt function.   
148However, an intruder that managed to get inside your system would have no trouble discovering the password - it is, after all, written in plain text in your PHP script.   
149  
150The next logical step toward greater security is to attempt to obfuscate the password used in the encryption function. You could use some other piece of information from the database (in which case you would need to use the same information as the decrypt key). You could encrypt your password. This approach becomes endlessly recursive, however, since for each encryption you need a password (which would have to be itself encrypted, and so on it goes...). The process of creating an automatic encryption scheme that is impervious to tampering if penetrated is ultimately beyond the scope of this article. We can, however, look at how to introduce some serious roadblocks.   
151The first approach to consider is to use a PHP encoder. We leave this exercise to the reader . The second approach is to compile a command-line application to do the job you were formerly trusting to PHP. The two examples, shown in Listing 9 and Listing 10, are adapted from the mcrypt man pages.   
152  
153**Listing 9: C my_crypt command line application**
154
155_#include

<mcrypt.h>
#include <stdio.h>
#include <stdlib.h>
/* #include <mhash.h> */
main( int argc, char *argv[] ) {
return my_crypt();
}

int my_crypt() {
MCRYPT td;
int i;
char *key;
char password[20];
char block_buffer;
char IV;
int keysize=16; /
128 bits /
key=calloc(1, keysize);
strcpy(password, "supersecret");
/
Generate the key using the password /
/

mhash_keygen( KEYGEN_MCRYPT, MHASH_MD5,
key, keysize, NULL, 0, password,
strlen(password));
*/

memmove( key, password, strlen(password));
td = mcrypt_module_open("rijndael-128",
"", "cfb", "");
if (td==MCRYPT_FAILED) {
return 1;
}
IV = malloc(mcrypt_enc_get_iv_size(td));
/* Put random data in IV. Note these are not

  • real random data, consider using
  • /dev/random or /dev/urandom.
    /
    /
    srand(time(0)); /
    for (i=0; i< mcrypt_enc_get_iv_size( td);
    i++) {
    IV[i]=rand();
    }
    i=mcrypt_generic_init( td, key, keysize,
    IV);
    if (i<0) {
    mcrypt_perror(i);
    return 1;
    }
    /
    Encryption in CFB is performed in bytes
    /
    while ( fread (█_buffer, 1, 1, stdin)
    == 1 ) {
    mcrypt_generic (td, █_buffer, 1);
    fwrite ( █_buffer, 1, 1, stdout);
    }
    /
    Deinit the encryption thread,
  • and unload the module
    */
    mcrypt_generic_end(td);
    return 0;
    }

Listing 10: C my_decrypt command line application
#include <mcrypt.h>
#include <stdio.h>
#include <stdlib.h>
/* #include <mhash.h> */
main( int argc, char *argv[] ) {
char password[20];
if (argc < 2) {
return 1;
} else {
strcpy(password, argv[1]);
return my_decrypt(password);
}
}

int my_decrypt(char *the_pass) {
MCRYPT td;
int i;
char *key;
char password[20];
char block_buffer;
char IV;
int keysize=16; /
128 bits /
key=calloc(1, keysize);
strcpy(password, the_pass);
/
Generate the key using the password /
/

mhash_keygen( KEYGEN_MCRYPT, MHASH_MD5,
key, keysize, NULL, 0, password,
strlen(password));
*/

memmove( key, password, strlen(password));
td = mcrypt_module_open("rijndael-128",
"", "cfb", "");
if (td==MCRYPT_FAILED) {
return 1;
}
IV = malloc(mcrypt_enc_get_iv_size(td));
/* Put random data in IV.

  • Note these are not real random data,
  • consider using /dev/random or
  • /dev/urandom.
    /
    /
    srand(time(0)); /
    for (i=0; i< mcrypt_enc_get_iv_size( td);
    i++) {
    IV[i]=rand();
    }
    i=mcrypt_generic_init( td, key, keysize,
    IV);
    if (i<0) {
    mcrypt_perror(i);
    return 1;
    }
    /
    Encryption in CFB is performed in bytes
    /
    while ( fread (█_buffer, 1, 1, stdin)
    == 1 ) {
    /
    mcrypt_generic (td, █_buffer,
    1); /
    /
    Comment below and uncomment above to
  • encrypt
    /
    mdecrypt_generic (td, █_buffer, 1);
    fwrite ( █_buffer, 1, 1, stdout);
    }
    /
    Deinit the encryption thread, and unload
  • the module */
    mcrypt_generic_end(td);
    return 0;
    } _

Also included in the CD-ROM under the my_crypt directory is a Makefile and simple shell script for testing these commands. In PHP, the test would look like:

_ ```

function my_crypt( $string) {
return echo " $string" | my_crypt;
}

function my_decrypt( $string, $password) {
return trim(echo " $string" | my_decrypt " $password");
}

 1
 2  
 3This approach suffers from one major drawback: because these calls are made on the command line, anyone on the system who types:   
 4
 5
 6_# ps -aux_
 7
 8  
 9at the time the my_crypt function is running, will see the string being encrypted. Worse, if they type this while my_decrypt is running, they can see the password and therefore potentially have access to everything that has ever been encrypted using this model.   
10The other option is to create your own PHP extension that uses the (C) mcrypt library. See Zeev Suraski's article on authoring PHP extensions (Issue 01.04, international php magazine) as well as the PHP manual for more information on how this is done. We leave this exercise to the reader.   
11Note that if you present a password in plain text, that password will be vulnerable to discovery in both the command line approach and the extension approach by anyone with 'read' access to the binary file. Compiling the command called my_crypt with the password 'supersecret' built in as plain text and running:   
12
13
14_grep 'supersecret' my_crypt_
15
16  
17will yield:   
18
19
20_grep: binary file my_crypt matches_
21
22  
23as indeed it does. Decompiling this binary file or simply calling it up in 'vi' reveals the string 'supersecret' amid the machine code.   
24The next level of security following down this path is to insert a password that is a hash of a plaintext password. Then, in the decrypt function, simply hash the plain text password before passing it as the key to mdecrypt_generic. Figuring out which hash function created the password embedded in your encryption function is going to be much more difficult than simply scanning the binary file for ASCII text. Difficult, but still not impossible.   
25  
26All of this is to say that you can continue to create barriers to people decrypting your data once they have penetrated your system. Ultimately, however, it is possible, particularly in the case of a root compromise. When the English captured a ciphering system called Enigma during World War II, despite the sophistication of the system for its time, they were eventually able to decode secret German messages . Likewise, in the scenario of a penetrated computer system running cryptography, the best you can do is buy some time in hopes of detecting the intrusion and regaining control. 
27
28**Conclusions**   
29If you have made it this far you should have a good working understanding of using mcrypt. Numerous issues surrounding cryptography still remain to be discovered. This is by design: this article is designed to get you acquainted with mcrypt and thinking about some of the basic issues of cryptography. It is not intended to be comprehensive.   
30  
31We have also examined some of the problems in automated encryption schemes of where and how to store the key, including how PHP as a plain text scripting language exacerbates this problem and how even techniques like encoding PHP or compiling to binary do not provide a foolproof solution.   
32More effective methods of encrypting data such that the keys used to encrypt data are not useful for decryption hold promise in schemes like PGP. As of this writing, PGP has not been successfully made into a PHP extension, however with the advent of Gnu PGP, this can't be far off. Still, schemes like mcrypt will be useful where powerful encryption using short keys (e.g. passwords) will be needed, as in the examples above.   
33We have looked at two examples: one for transmitting data client-side (via cookies), and one for storing data server-side (in SQL). The doors are now open, from applications as simple as encrypting and decrypting user passwords (since you can only change, not report, a password stored in a hash-and-compare scheme) to applications as complex as creating your own secure transport layer for transmitting data over untrusted networks. mcrypt combined with PHP can help you leverage the power of key cryptography on the Web, whether you are securing a flattened data structure or a late night love letter.</mhash.h></stdlib.h></stdio.h></mcrypt.h></mhash.h></stdlib.h></stdio.h></mcrypt.h>
Published At
Categories with Web编程
Tagged with
comments powered by Disqus