18.6.2 测试GPG

到这里,我们应该已经成功安装GPG并可以开始使用GPG了。创建一个包含一些普通文本的文件并以test.txt名字保存它,这样我们对其进行测试。

输入如下所示的命令(可以对该命令进行修改,用你的密钥名称来替换其中的密钥名称):


gpg-a—recipient'Luke Welling<luke@tangledweb.com.au>'—encrypt test.txt


将给出如下所示的警告:


gpg:Warning:using insecure memory!


并且生成名为test.txt.asc的文件。如果打开文件test.txt.asc,将看到如下所示的加密信息:


——-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——-


可以将该文件发送给最初生成此密钥的系统,运行如下命令:


gpg test.txt.asc


这样,就能够再次看到原始文本。原始文本将被写入到一个具有相同文件名称的文件——在这个例子中,文件名称为test.txt。

要将此文本输出到显示器上,可以使用-d标记并按如下方式指定一个输出文件:


gpg-d test.txt.asc


要在选择的文件中保存文本(非默认的文件名),可以使用-o标记并且指定输出文件,如下所示:


gpg-do test.out test.txt.asc


请注意,先要给出输出文件的名称。

如果已经安装了GPG,运行PHP脚本的用户就能够通过命令行使用它,基本上我们也是以这种方式运行。如果它出现问题,请询问系统管理员或者查看GPG文档。

程序清单18-1和程序清单18-2是通过PHP调用GPG来发送加密后的电子邮件。

程序清单18-1 private_mail.php——发送加密邮件的HTML表单


<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($_SERVER['SERVER_PORT']!=443){

echo'<p style="color:red">WARNING:you have not

connected to this page using SSL.Your message could

be read by others.</p>';

}

?>

<form method="post"action="send_private_mail.php">

<p>Your email address:<br/>

<input type="text"name="from"size="40"/></p>

<p>Subject:<br/>

<input type="text"name="title"size="40"/></p>

<p>Your message:<br/>

<textarea name="body"cols="30"rows="10"></textarea></p>

<br/>

<input type="submit"name="submit"value="Send!"/>

</form>

</body>

</html>


程序清单18-2 send_private_mail.php——调用GPG和发送加密邮件的PHP脚本


<?php

//create short variable names

$from=$_POST['from'];

$title=$_POST['title'];

$body=$_POST['body'];

$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>';

}

}

if($result!=0){

echo'<h1>Error:</h1>

<p>Your message could not be encrypted.</p>

<p>It has not been sent.</p>

<p>Sorry.</p>';

}

?>


为了使这些代码能够适用于你的情况,需要对它进行一些修改。电子邮件要发送到$to_email的地址中。

在程序清单18-2中,必须修改以下代码行:


putenv('GNUPGHOME=/tmp/.gnupg');


从而指定GPG密钥环的地址。在我们的系统中,Web服务器是以nobody用户的名义运行的,而且拥有一个根目录/tmp/。

我们使用函数tempnam()创建一个唯一的临时文件名。可以指定目录名和文件名的前缀。我们只需要很短的时间就可以创建和删除这些文件,因此如何命名这些文件并不重要。我们指定了一个前缀'pgp',但是让PHP使用系统的临时目录。

如下语句:


$command="/usr/local/bin/gpg-a\

—recipient'Luke Welling<luke@tangledweb.com.au>'\

—encrypt-o$outfile$infile";


用来设置调用gpg的命令和参数。要将该命令适用于你的情况,必须对其进行一些修改。

在命令行上使用它时,需要告诉GPG哪一个密钥是用于加密信息的。如下语句:


system($command,$result);


执行存储在$command中的命令,并将返回值存储于$result。我们可以忽略返回值,但是利用该值,我们可以使用一个if语句并且告诉用户某些语句出错。

当利用临时文件完成任务后,可以调用函数unlink()删除这些文件。这就意味着,未加密电子邮件在服务器上只存储了很短的时间。但是如果服务器在执行过程中失败了,文件保留在服务器上也是可能的。

当提到脚本的安全性时,对系统中的信息流进行考虑也是很重要的。GPG将加密电子邮件并允许接收者对其解密,但这些信息最初是如何从发送方发送过来的呢?如果提供一个Web界面来发送GPG加密邮件,那么其信息流与图18-5类似。

18.6.2 测试GPG - 图1

图 18-5 在加密电子邮件的应用程序中,信息经过Internet发送3次

在本图中,第一个箭头代表消息从一台机器传输到另一台机器。消息每次发送后,它就在Internet上传输,并且中间可能经过许多网络和机器。

我们在此看到的脚本保存在上图中标记为服务器的机器上。在这个Web服务器中,消息将被收件人的公有密钥进行加密,并通过SMTP发送到收件人的邮件服务器。收件人连接邮件服务器(可能是利用POP或者IMAP),并通过邮件阅读程序下载此消息。然后可以用私有密钥解密消息。

如图18-5中所示的数据传输分别标记为1、2、3。在第2阶段和第3阶段中,传输的信息是一个加密的GPG消息,对任何没有私有密钥的人来说,该信息是没有价值的。在第1阶段中,传输的消息是发送者输入到表单中的文本。

如果信息非常重要,需要在上图的传输过程第2和第3阶段对消息进行加密,那么在第1阶段不加密是有些可笑的。因此,这个脚本属于使用SSL的服务器。

如果尝试不通过SSL连接这个脚本,该脚本将会给出警告信息。可以通过检查$_SERVER['SERVER_PORT']变量来确认。SSL连接的默认端口是443。任何其他的连接都将导致一个错误。

除了提供出错消息,我们还可以使用其他方式来处理这种情况。可以将用户重定向到一个经过SSL的URL,而且这个URL是相同的。我们还可以选择忽略它,这是因为如果表单是通过安全连接发送的,它通常就不是很重要的。通常,用户在表单中输入的具体内容安全地发送给我们才是重要的。我们可以将表单的动作指定为一个完整的URL。

目前,我们的form标记如下所示:


<form method="post"action="send_private_mail.php">


可以对其进行修改,使其通过SSL发送数据,即使用户没有使用SSL进行连接:


<form method="post"action="https://webserver/send_private_mail.php">


如果我们像以上代码那样,将完整的URL硬编码到form标记中,可以确保访问者的数据将通过SSL进行发送,但是当在另一台服务器上或在另一个目录下使用它时,必须对该URL进行修改。

尽管在这种情况以及许多其他情况下,通过SSL将一个空表单发送给用户并不是很重要的,但其实这样做却是一个非常不错的主意。看到浏览器的状态栏中的小挂锁符号,人们能够确信他们的信息将安全发送。他们无须查看HTML源代码中表单的动作属性是什么来确定数据是否安全。