Skip to content

Commit

Permalink
Try automatically signing outgoing emails if a keypair is present.
Browse files Browse the repository at this point in the history
  • Loading branch information
fabacab committed Feb 23, 2016
1 parent cfafaaa commit 2324e11
Show file tree
Hide file tree
Showing 3 changed files with 330 additions and 31 deletions.
57 changes: 54 additions & 3 deletions class-wp-openpgp.php
Expand Up @@ -31,6 +31,8 @@ public static function register () {
add_filter('openpgp_enarmor', array(__CLASS__, 'enarmor'), 10, 3);
add_filter('openpgp_encrypt', array(__CLASS__, 'encrypt'), 10, 3);
add_filter('openpgp_key', array(__CLASS__, 'getKey'));
add_filter('openpgp_sign', array(__CLASS__, 'sign'), 10, 2);
add_filter('openpgp_sign_and_encrypt', array(__CLASS__, 'signAndEncrypt'), 10, 4);
}

/**
Expand All @@ -42,12 +44,60 @@ public static function register () {
*/
public static function getKey ($key, $ascii = true) {
if ($ascii) {
$key = OpenPGP::unarmor($key, 'PGP PUBLIC KEY BLOCK');
preg_match('/-----BEGIN ([A-Za-z ]+)-----/', $key, $matches);
$marker = (empty($matches[1])) ? 'MESSAGE' : $matches[1];
$key = OpenPGP::unarmor($key, $marker);
}
$openpgp_msg = OpenPGP_Message::parse($key);
return (is_null($openpgp_msg)) ? false : $openpgp_msg;
}

/**
* Sign arbitrary data with a key.
*
* @param string $data
* @param string $signing_key
*
* @return string
*/
public static function clearsign ($data, $signing_key) {
$signer = new OpenPGP_Crypt_RSA($signing_key[0]);
$m = $signer->sign($data);
$packets = $m->signatures()[0];
$clearsign = "-----BEGIN PGP SIGNED MESSAGE-----\nHash: SHA256\n\n";
$clearsign .= preg_replace("/^-/", "- -", $packets[0]->data)."\n";
return $clearsign.apply_filters('openpgp_enarmor', $packets[1][0]->to_bytes(), 'PGP SIGNATURE');
}

/**
* Signing is an alias to clearsign() right now.
*
* @param string $data
* @param string $signing_key
*
* @return string
*/
public static function sign ($data, $signing_key) {
return self::clearsign($data, $signing_key);
}

/**
* Signs and then encrypts data.
*
* This is a shortcut for calling `sign()` and then `encrypt()`.
*
* @param string $data
* @param OpenPGP_SecretKeyPacket $signing_key
* @param array|string $recipient_keys_and_passphrases
* @param bool $armor
*
* return string
*/
public static function signAndEncrypt ($data, $signing_key, $recipient_keys_and_passphrases, $armor = true) {
$signed_data = apply_filters('openpgp_sign', $data, $signing_key);
return apply_filters('openpgp_encrypt', $signed_data, $recipient_keys_and_passphrases, $armor);
}

/**
* Encrypts data to a PGP public key, passphrase, or set of passphrases or keys.
*
Expand Down Expand Up @@ -104,7 +154,7 @@ public static function enarmor ($data, $marker = 'MESSAGE', $headers = array())
*
* @return OpenPGP_Message[]
*/
public static function generateKeypair ($identity, $bits = 4096) {
public static function generateKeypair ($identity, $bits = 2048) {
if (2048 > $bits) {
$error_msg = 'RSA keys with less than 2048 bits are unacceptable.';
throw new UnexpectedValueException($error_msg);
Expand All @@ -117,8 +167,9 @@ public static function generateKeypair ($identity, $bits = 4096) {
// but would LOOOOOVE to have someone more knowledgeable than
// I am about this stuff double-check me here. Patches welcome!

$rsa = new Crypt_RSA(); // This is the line that causes the error.
$rsa = new \phpseclib\Crypt\RSA();
$k = $rsa->createKey($bits);

$rsa->loadKey($k['privatekey']);

$nkey = new OpenPGP_SecretKeyPacket(array(
Expand Down
40 changes: 34 additions & 6 deletions readme.txt
Expand Up @@ -8,15 +8,15 @@ Stable tag: 0.4.0
License: GPLv3
License URI: https://www.gnu.org/licenses/gpl-3.0.html

Encrypts emails WordPress sends using PGP public keys. Provides OpenPGP functions via WordPress plugin API.
Signs and encrypts emails WordPress sends using PGP keys. Provides OpenPGP functions via WordPress plugin API.

== Description ==

WP PGP Encrypted Emails automatically encrypts any email that WordPress sends to your site's admin email address or user email addresses after you give it a copy of the recipient's PGP public key. This protects your user's privacy by ensuring that emails intended for them can be read only by them and them alone.
WP PGP Encrypted Emails automatically signs and encrypts any email that WordPress sends to your site's admin email address or user email addresses after you give it a copy of the recipient's PGP public key or generate a signing keypair to use. This protects your user's privacy by ensuring that emails intended for them can be read only by them and them alone. Signing helps your users verify that email they receive purporting to be from your site actually was sent by your server.

*Donations for this and [my other free software plugins](https://profiles.wordpress.org/meitar#content-plugins) make up a chunk of my income. If you continue to enjoy this plugin, please consider [making a donation](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=TJLPJYXHSRBEE&lc=US&item_name=WP%20PGP%20Encrypted%20Emails&item_number=wp-pgp-encrypted-emails&currency_code=USD&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted). :) Thank you for your support!*

The plugin works transparently for *all email* your site generates, and will also encrypt outgoing email generated by other plugins (such as contact form plugins) or the built-in WordPress notification emails. All you have to do is add a PGP public key to the General Settings screen. You can also remove envelope information such as email subject lines, which PGP cannot encrypt. There is no longer any need to pay for the "pro" version of your favorite contact form plugin to get the benefit of email privacy.
The plugin works transparently for *all email* your site generates, and will also sign and encrypt outgoing email generated by other plugins (such as contact form plugins) or the built-in WordPress notification emails. All you have to do is add one or more PGP keys to the General Settings screen. You can also remove envelope information such as email subject lines, which PGP cannot encrypt. There is no longer any need to pay for the "pro" version of your favorite contact form plugin to get the benefit of email privacy.

Additionally, each of your site's users can supply their own, personal public key for their own email address to have WordPress automatically encrypt any email destined for them. (They merely need to update their user profile pages.) Once saved, all future emails WordPress sends to that user will be encrypted with their public key.

Expand Down Expand Up @@ -101,15 +101,19 @@ We might add support for an in-browser client based on [OpenPGP.js](http://openp

3. Authors who add a PGP public key to their profile also let readers leave semi-private comments on their posts. These are comments that are automatically encrypted to the author's public key upon submission. Commenters who want to send a "Private" comment simply write their comment normally and ensure the encryption checkbox is enabled when they submit their comment.

4. Administrators can generate an OpenPGP signing keypair with which to automatically sign outgoing emails. This helps recipients verify that email they receive actually came from your website. Admins can regenerate the keypair automatically by clicking the "Regenerate keypair" button, or they can manually paste an ASCII-armored keypair for the site to use.

5. For security, the private key part of the site's signing key will only be transmitted over a secure (HTTPS) connection, so you will see the following prompt to switch to a secure connection if you try to view it insecurely. You can still (re)generate a keypair, including the private key part, over an insecure connection because the key is generated on the server itself.

== Change log ==

= Version 0.4.0 =

* [Feature](https://github.com/meitar/wp-pgp-encrypted-emails/issues/1): Automatically generate a PGP keypair for the blog itself upon activation if one is missing.
* This keypair is used for signing outgoing encrypted emails. It is *not* intended to be used for any other purpose. *Do not* use this keypair for emails you send yourself. *Do not* export this key for use in any other system. This keypair should be treated as a low-trust, single-purpose keypair reserved exclusively for your website itself.
* [Feature](https://github.com/meitar/wp-pgp-encrypted-emails/issues/1): Admins can now generate a PGP signing keypair for the blog itself. If a signing keypair exists, outgoing emails will be automatically signed.
* This keypair is intended to be used for signing outgoing emails. It is *not* intended to be used for any other purpose. *Do not* use this keypair for emails you send yourself. *Do not* export this key for use in any other system. This keypair should be treated as a low-trust, single-purpose keypair reserved exclusively for your website itself.
* Developer: New filter hooks. These are documented on the [Other Notes](https://wordpress.org/plugins/wp-pgp-encrypted-emails/other_notes/) page.
* `openpgp_enarmor` filter for ASCII-armoring arbitrary OpenPGP data.
* `openpgp_sign` filter for signing an arbitrary message.
* `openpgp_sign` filter for (clear)signing an arbitrary message.

= Version 0.3.0 =

Expand Down Expand Up @@ -167,6 +171,21 @@ Example: Get a key saved as an ASCII string in the WordPress database option `my

$key = apply_filters('openpgp_key', get_option('my_plugin_pgp_public_key'));

= `openpgp_sign` =

[Clearsigns](https://www.gnupg.org/gph/en/manual/x135.html#AEN152) a message using a given private key.

* Required parameters:
* `string` `$data` - The message data to sign.
* `OpenPGP_SecretKeyPacket` `$signing_key` - The signing key to use, obtained by passing the ASCII-armored private key through the `openpgp_key` filter.

Example: Sign a short string.

$message = 'This is a message to sign.';
$signing_key = apply_filters('openpgp_key', $ascii_key);
$signed_message = apply_filters('openpgp_sign', $message, $signing_key);
// $signed_message is now a clearsigned message

= `openpgp_encrypt` =

Encrypts data to one or more PGP public keys or passphrases.
Expand Down Expand Up @@ -205,3 +224,12 @@ Example: Send a signed, encrypted JSON payload to a remote, insecure server.
$url = 'http://insecure.example.com/';
$response = wp_safe_remote_post($url, array(
));

= `openpgp_sign_and_encrypt` =

A convenience filter that applies `openpgp_sign` and then `openpgp_encrypt` to the result.

* Required arguments:
* `string` `$data` - The data to sign and encrypt.
* `string` `$signing_key` - The signing key to use.
* `array|string` `$recipient_keys_and_passphrases` - Public key(s) of the recipient(s), or passphrases to encrypt to.

0 comments on commit 2324e11

Please sign in to comment.