I've been trying to concoct a PHP script to take a sensitive message, encrypt it using someone's public key and email it. I've looked at three different approaches I've found through google search and none seems to work
Approach 1
The first uses [man]openssl_pkcs7_encrypt[/man] and I followed the sample script here. Two problems. First, the encryption is not very strong:
openssl_pkcs7_encrypt() takes the contents of the file named infile and encrypts them using an RC2 40-bit cipher so that they can only be read by the intended recipients specified by recipcerts.
40-bit cipher doesn't sound particularly strong.
Secondly, the script doesn't work:
$headers = array(
"From" => "sender@example.com",
"To" => "recipient@example.com",
"Subject" => "Encrypted mail test",
"X-Mailer" => "PHP/".phpversion()
);
define("PUBLIC_KEY_PATH", "/path/to/public_key.pub");
// Get the public key certificate.
$pubkey = file_get_contents(PUBLIC_KEY_PATH);
// Remove some double headers for mail()
$headers_msg = $headers;
unset($headers_msg['To'], $headers_msg['Subject']);
$data = "This email is Encrypted!\nYou must have my certificate to view this email!\nMe\n";
//write msg to disk
$msgfile = "/path/to/msg.txt";
file_put_contents($msgfile, $data);
// Encrypt message
$encrypted_msgfile = "/path/to/encrypted_msg.txt";
$crypt_result = openssl_pkcs7_encrypt($msgfile, $encrypted_msgfile, $pubkey, $headers_msg, PKCS7_TEXT, 1);
if ($crypt_result === FALSE) {
die ("encryption failed\n");
}
// Separate headers and body for mail()
$data = file_get_contents($encrypted_msgfile);
$parts = explode("\n\n", $data, 2);
// Send mail
mail($headers['To'], $headers['Subject'], $parts[1], $parts[0]);
It dies with this error:
error:0906D066:PEM routines:PEM_read_bio:bad end line
encryption failed
I'm not certain, The problem might be with the $pubkey param I supply to openssl_pkcs7_encrypt -- this file is apparently not x.509. The key file looks something like this:
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v2.0.17 (MingW32)
mQINBFE2oIsBEACo1d7vsGdmWJqUHSHsDcOH8ZL+YJbNrghnvRe2V1QNF83JsF+C
LHfL3piH4MZ1FEQsAyUfqn7fqagIU0KrrsT4MeCR8msYAE64cTkwkT4J4Y4wEybj
...etc..
Pqvo9g9u2Vswm11CHZs9QsXm/9+5qf9Ww3ycZfmAOM8jkrtpO9gdpDF9zfmCQiVc
HX3gATz3HZoheHhOIA==
=Xnkl
-----END PGP PUBLIC KEY BLOCK-----
Approach 2
Although it doesn't mention email, I tried using the mcrypt sample code given in the manual for [man]mcrypt_module_open[/man]. That script does encrypt and decrypt some data but it does so by generating its own key for some reason:
/* Create key */
$key = substr(md5('very secret key'), 0, $ks);
And the key is quite short (32 chars in length). It's not clear to me if I would be allowed to use a public key belonging to the recipient. Additionally, the encrypted message appears to be binary instead of ASCII armored of base 64 encoded and it also lacks any sort of emailable headers to describe the encryption technique or whatever that would lend any clues to a remote email client. I tend to doubt a mail client would be able to make sense of the cipher. The documentation on mcrypt really seems to assume you know exactly what it is for.
Approach 3
The last approach is from an IBM article and relies on command line use of gpg to create the encrypted message. While I believe this approach would generate nice useful informative header information about the encrypted content, the script doesn't seem to allow me to specify a public key file directly and instead relies on me to manipulate the appropriate keyrings to manage keys for both the sender and the recipient. This script fails:
$from = "sneakyimp"; // local username on my ubuntu box
$to = "recipient@example.com"; // some email address
//cut the message down to size, remove HTML tags
$messagebody = "Here is my encrypted message.\nI have defined it in PHP and encrypted it using the example at http://www.ibm.com/developerworks/library/os-php-encrypt/index.html\n\nHope this works!";
$escaped_body = escapeshellarg($messagebody);
$gpg_path = '/usr/bin/gpg'; // this may vary from distro to distro
$home_dir = '/path/to/test/dir';
$user_env = 'sneakyimp';
$cmd = "echo $escaped_body | HOME=$home_dir USER=$user_env $gpg_path" .
"--quiet --no-secmem-warning --encrypt --sign --armor " .
"--recipient $to --local-user $from";
echo "cmd:\n";
echo $cmd . "\n\n";
$message_body = `$cmd`;
mail($to,'Encrypted Message', $message_body,"From:$from\r\n");
The approach obviously doesn't let me manually specify the location of the public key file for recipient@example.com This script produces an error:
cmd:
echo 'Here is my encrypted message.
I have defined it in PHP and encrypted it using the example at http://www.ibm.com/developerworks/library/os-php-encrypt/index.html
Hope this works!' | HOME=/path/to/test/dir USER=sneakyimp /usr/bin/gpg --quiet --no-secmem-warning --encrypt --sign --armor --recipient recipient@example.com --local-user sneakyimp
gpg: skipped "sneakyimp": secret key not available
gpg: [stdin]: sign+encrypt failed: secret key not available
Can anyone refer me to a working PHP script that accomplishes this? Or perhaps help me sort the issue? It seems to me it would be very useful to have a script that can send an encrypted message. I'm very much interested in portability and would like to avoid any steps where one must manipulate the keyring belonging to a user and one could instead specify a specific key file, etc. Any advice would be much appreciated.