I have been struggling to get openssl_pkcs7_encrypt() to work just as I need it to do but through my perseverence I have prevailed. The issues I came across were due to my very incomplete understanding of S/MIME, MIME and email headers.
First, both the example in the manual and the correction offered by msisolak above are also slightly incorrect. Let me explain in lay terms how the problem arises ...
email messages are constructed as follows
headers
blank line
content
For S/MIME, the message is encrypted (including headers) and further headers are wrapped around the encrypted message, like so:
S/MIME headers
blank line
encrypted MIME headers
encrypted blank line
encrypted content
If you have no headers in what you are encrypting then anything before the 1st blank line is regarded as headers and doesn't appear in the content of your message.
openssl_pkcs7_encrypt() creates the entire encrypted portion so if you do not include any headers in your infile then you will find that some of your message may be treated as headers unless you make the first line of your file a blank line.
There is also an error in the way the "From" S/MIME header is coded on the call to openssl_pkcs7_encrypt().
So the example, to work 100% correctly needs to read as follows:
// the message you want to encrypt and send to your secret agent
// in the field, known as nighthawk. You have his certificate
// in the file nighthawk.pem
//
//Note the first line must be blank as i am providing no headers inside the secure portion of the mail.
$data = <<<EOD
Nighthawk,
Top secret, for your eyes only!
The enemy is closing in! Meet me at the cafe at 8.30am
to collect your forged passport!
HQ
EOD;
// load key
$key = implode("", file("my.pem"));
// save message to file
$fp = fopen("msg.txt", "w");
fwrite($fp, $data);
fclose($fp);
// encrypt it
if (openssl_pkcs7_encrypt("msg.txt", "enc.txt", $key,
array("To" => "[email protected]", // keyed syntax
"From" => "HQ <[email protected]>", // indexed syntax
"Subject" => "Eyes only")))
{
// message encrypted - send it!
exec(ini_get("sendmail_path") . " < enc.txt");
}
Now, I wanted to make a couple of other enhancements. My email contained html content and must be formatted when displayed in the email client and I also wanted to use temporary file names to allow multiple users to use the script at the same time. Finally, I wanted to remove these temporary files afterwards.
Here is how the example ends up with these additional enhancements:
<?
// the message you want to encrypt and send to your secret agent
// in the field, known as nighthawk. You have his certificate
// in the file my.pem
//
//Note the blank line following the Content-type header
//
$data = <<<EOD
MIME-Version: 1.0
Content-type: text/html; charset=iso-8859-1
<html>
<b>Nighthawk</b>,
<h1>Top secret, for your eyes only!</h1>
<p>The enemy is closing in! Meet me at the cafe at 8.30am
to collect your forged passport!</p>
<p>HQ</p>
</html>
EOD;
// load key
$key = implode("", file("my.pem"));
// generate a unique temporary file name. Use .txt for the clear text version and .enc for the encrypted version.
$clearfile = tempnam("temp","email") . ".txt";
$encfile = $clearfile . ".enc";
$clearfile .= ".txt";
$fp = fopen($clearfile, "w");
fwrite($fp, $data);
fclose($fp);
// encrypt it
if (openssl_pkcs7_encrypt($clearfile,$encfile, $key,
array("To" => "[email protected]", // keyed syntax
"From" => "HQ <[email protected]>", // indexed syntax
"Subject" => "Eyes only")))
{
// message encrypted - send it!
exec(ini_get("sendmail_path") . " < $encfile");
};
// now erase the temp files
unlink($clearfile);
unlink($encfile);
?>