在关于单独签名或加密电子邮件的众多讨论中,没有一个真正讨论过同时签名和加密电子邮件的难题。
根据RFC 2311,你可以先加密后签名或先签名后加密。但是,这取决于你正在为其编程的客户端。根据我的经验,在Outlook 2000中,它更倾向于先加密后签名。而在Outlook 2003中,它是先签名后加密。通常,你希望先签名后加密,因为它从信件的角度来看似乎更合乎逻辑。你首先签署一封信,然后将其放入信封中。某些客户端如果以它们不喜欢的顺序执行操作,就会抱怨,因此你可能需要尝试一下。
当你执行第一个函数时,不要在headers数组参数中放入任何头信息,你希望将其放入你想要执行的第二个函数中。如果你在第一个函数中放入头信息,第二个函数会将其隐藏在邮件服务器之外。你不想那样。这里我将先签名后加密。
<?php
$headers = array("To" => "someone@nowhere.net",
"From" => "noone@somewhere.net",
"Subject" => "A signed and encrypted message.");
openssl_pkcs7_sign("msg.txt","signed.txt",
"signing_cert.pem",array("private_key.pem",
"password"),array());
$pubkey = file_get_contents("cert.pem");
openssl_pkcs7_encrypt("signed.txt", "enc.txt",
$pubkey,$headers,0,1);
$data = file_get_contents("enc.txt");
$parts = explode("\n\n", $data, 2);
mail($mail, $subject, $parts[1], $parts[0]);
?>
请注意,如果你使用一个从磁盘获取数据并在程序中的另一个函数中使用该数据的函数,请记住你可能使用了explode("\n\n",$data,2)函数,该函数可能删除了头信息和消息内容之间的空格。
当你获取已签名的消息并将其馈送到加密部分时,你必须记住,行间距也必须作为消息正文的一部分馈送!如果你计划先签名后加密,不要将签名生成的header输出作为headers数组参数的一部分馈送到加密函数中!签名的输出应保持为要加密的消息正文的一部分。(如果你正在执行先加密后签名的反向操作,也是如此。)签名和加密函数的示例,将其制作成一个可重用的例程,然后调用它来签名和加密消息。
这是错误的!
<?php
$signedOutputArray = signMessage($inputMessage,$headers);
$signedAndEncryptedArray = encryptMessage($signedOutputArray[1],
$signedOutputArray[0]);
mail($emailAddr,$subject,$signedAndEncryptedArray[1],
$signedAndEncryptedArray[0]);
?>
这是正确的!
<?php
$signedOutputArray = signMessage($inputMessage,array());
$signedAndEncryptedArray =
encryptMessage($signedOutputArray[0] . "\n\n" . $signedOutputArray[1],$headers);
mail($emailAddr,$subject,$signedAndEncryptedArray[1],
$signedAndEncryptedArray[0]);
?>