327 Using Encryption in PHP This will give you a binary file suitable for importing into the GPG or PGP keyring on another machine. If you want to email this key to people, so they can import it into their key rings, you can instead create an ASCII version like this: gpg export –a > filename Having extracted the public key, you can upload the file to your account on the Web server.You can do this with FTP. The following commands assume that you are using UNIX.The steps are the same for Windows, but directory names and system commands will be different. Log into your account on the Web server and change the permissions on the file so that other users will be able to read it.Type chmod 644 filename You will need to create a keyring so that the user who your PHP scripts get executed as can use GPG.Which user this is depends on how your server is setup. It is often the user 'nobody',but could be something else. Change to being the Web server user.You will need to have root access to the server to do this. On many systems, the Web server runs as nobody.The following examples assume this. (You can change it to the appropriate user on your system.) If this is the case on your system, type su root su nobody Create a directory for nobody to store their key ring and other GPG configuration information in.This will need to be in nobody’s home directory. The home directory for each user is specified in /etc/passwd. On many Linux sys- tems, nobody’s home directory defaults to /, which nobody will not have permission to write to. On many BSD systems, nobody’s home directory defaults to /nonexistent, which, as it doesn’t exist, cannot be written to. On our system, nobody has been assigned the home directory /tmp.You will need to make sure your Web server user has a home directory that he can write to. Type cd ~ mkdir .gnupg The user nobody will need a signing key of her own.To create this, run this command again: gpg gen-key As your nobody user probably receives very little personal email, you can create a signing only key for them.This key’s only purpose is to allow us to trust the public key we extracted earlier. 19 525x ch15 1/24/03 3:41 PM Page 327 328 Chapter 15 Implementing Secure Transactions with PHP and MySQL To import the pubic key we exported earlier, use the following: gpg import filename To tell GPG that we want to trust this key, we need to edit the key’s properties using gpg edit-key 'Luke Welling <luke@tangledweb.com.au>' On this line, the text in quotes is the name of the key. Obviously, the name of your key will not be 'Luke Welling <luke@tangledweb.com.au>',but a combination of the name, comment, and email address you provided when generating it. Options within this program include help, which will describe the available com- mands—trust, sign,and save. Type trust and tell GPG that you trust your key fully.Type sign to sign this public key using nobody’s private key. Finally, type save to exit this program, keeping your changes. Testing GPG GPG should now be set up and ready to use. Creating a file containing some text and saving it as test.txt will allow us to test it. Ty ping the following command (modified to use the name of your key) gpg -a recipient 'Luke Welling <luke@tangledweb.com.au>' encrypt test.txt should give you the warning gpg: Warning: using insecure memory! and create a file named test.txt.asc. If you open test.txt.asc you should see an encrypted message like this: BEGIN PGP MESSAGE Version: GnuPG v1.0.3 (GNU/Linux) Comment: For info see http://www.gnupg.org hQEOA0DU7hVGgdtnEAQAhr4HgR7xpIBsK9CiELQw85+k1QdQ+p/FzqL8tICrQ+B3 0GJTEehPUDErwqUw/uQLTds0r1oPSrIAZ7c6GVkh0YEVBj2MskT81IIBvdo95OyH K9PUCvg/rLxJ1kxe4Vp8QFET5E3FdII/ly8VP5gSTE7gAgm0SbFf3S91PqwMyTkD /2oJEvL6e3cP384s0i8lrBbDbOUAAhCjjXt2DX/uX9q6P18QW56UICUOn4DPaW1G /gnNZCkcVDgLcKfBjbkB/TCWWhpA7o7kX4CIcIh7KlIMHY4RKdnCWQf271oE+8i9 cJRSCMsFIoI6MMNRCQHY6p9bfxL2uE39IRJrQbe6xoEe0nkB0uTYxiL0TG+FrNrE tvBVMS0nsHu7HJey+oY4Z833pk5+MeVwYumJwlvHjdZxZmV6wz46GO2XGT17b28V wSBnWOoBHSZsPvkQXHTOq65EixP8y+YJvBN3z4pzdH0Xa+NpqbH7q3+xXmd30hDR +u7t6MxTLDbgC+NR =gfQu END PGP MESSAGE You should be able to transfer this file to the system where you generated the key initial- ly and run gpg test.txt.asc to see your original text again. 19 525x ch15 1/24/03 3:41 PM Page 328 329 Using Encryption in PHP To place the text in a file, rather than output it to the screen, you can use the -o flag and specify an output file like this: gpg –do test.out test.txt.asc If you have GPG set up so that the user your PHP scripts run as can use it from the command line, you are most of the way there. If this is not working, see your system administrator or the GPG documentation. Listings 15.1 and 15.2 enable people to send encrypted email by using PHP to call GPG. Listing 15.1 private_mail.php—Our HTML Form to Send Encrypted Email <html> <body> <h1>Send Me Private Mail</h1> <?php // you might need to change this line, if you do not use // the default ports, 80 for normal traffic and 443 for SSL if($HTTP_SERVER_VARS['SERVER_PORT']!=443) echo '<p><font color="red"> WARNING: you have not connected to this page using SSL. Your message could be read by others.</font></p>'; ?> <form method="post" action="send_private_mail.php"><br /> Your email address:<br /> <input type="text" name="from" size"="38"><br /> Subject:<br /> <input type="text" name="title" size="38"><br /> Your message:<br /> <textarea name="body" cols="30" rows="10"> </textarea><br /> <input type="submit" value="Send!"> </form> </body> </html> Listing 15.2 send_private_mail.php—Our PHP Script to Call GPG and Send Encrypted Email <?php //create short variable names $from = $HTTP_POST_VARS['from']; $title = $HTTP_POST_VARS['title']; $body = $HTTP_POST_VARS['body']; 19 525x ch15 1/24/03 3:41 PM Page 329 330 Chapter 15 Implementing Secure Transactions with PHP and MySQL $to_email = 'luke@localhost'; // Tell gpg where to find the key ring // On this system, user nobody's home directory is /tmp/ putenv('GNUPGHOME=/tmp/.gnupg'); //create a unique file name $infile = tempnam('', 'pgp'); $outfile = $infile.'.asc'; //write the user's text to the file $fp = fopen($infile, 'w'); fwrite($fp, $body); fclose($fp); //set up our command $command = "/usr/local/bin/gpg -a \\ recipient 'Luke Welling <luke@tangledweb.com.au>' \\ encrypt -o $outfile $infile"; // execute our gpg command system($command, $result); //delete the unencrypted temp file unlink($infile); if($result==0) { $fp = fopen($outfile, 'r'); if(!$fp||filesize ($outfile)==0) { $result = -1; } else { //read the encrypted file $contents = fread ($fp, filesize ($outfile)); //delete the encrypted temp file unlink($outfile); mail($to_email, $title, $contents, "From: $from\n"); echo '<h1>Message Sent</h1> <p>Your message was encrypted and sent.</p> <p>Thank you.'</p>'; Listing 15.2 Continued 19 525x ch15 1/24/03 3:41 PM Page 330 331 Using Encryption in PHP } } if($result!=0) { echo '<h1>Error:</h1> <p>Your message could not be encrypted, so has not been sent.</p> <p>Sorry.</p>'; } ?> In order to make this code work for you, you will need to change a few things. Email will be sent to the address in $to_email. The line putenv('GNUPGHOME=/tmp/.gnupg'); will need to be changed to reflect the location of your GPG keyring. On our system, the Web server runs as the user nobody, and has the home directory /tmp/. We are using the function tempnam() to create a unique temporary filename.You can specify both the directory and a filename prefix.We are going to create and delete these files in around one second, so it is not very important what we call them.We are specify- ing a prefix of ‘pgp’, but letting PHP use the system temporary directory. The statement $command = '/usr/local/bin/gpg -a '. ' recipient 'Luke Welling <luke@tangledweb.com.au>' '. ' encrypt -o $outfile $infile'; sets up the command and parameters that will be used to call gpg. It will need to be modified to suit you. As with when we used it on the command line, you need to tell GPG which key to use to encrypt the message. The statement system($command, $result); executes the instructions stored in $command and stores the return value in $result. We could ignore the return value, but it lets us have an if statement and tell the user that something went wrong. When we have finished with the temporary files that we use, we delete them using the unlink() function.This means that our user’s unencrypted email is being stored on the server for a short time. It is even possible that if the server failed during execution, the file could be left on the server. While we are thinking about the security of our script, it is important to consider all flows of information within our system. GPG will encrypt our email and allow our recipient to decrypt it, but how does the information originally come from the sender? Listing 15.2 Continued 19 525x ch15 1/24/03 3:41 PM Page 331 . our command $command = "/usr/local/bin/gpg -a \ recipient 'Luke Welling <luke@tangledweb.com.au>' \ encrypt -o $outfile $infile"; // execute our gpg command system($command,. statement $command = '/usr/local/bin/gpg -a '. ' recipient 'Luke Welling <luke@tangledweb.com.au>' '. ' encrypt -o $outfile $infile'; sets up the command and. set up and ready to use. Creating a file containing some text and saving it as test.txt will allow us to test it. Ty ping the following command (modified to use the name of your key) gpg -a recipient