Skip to content

Instantly share code, notes, and snippets.

@timnashcouk
Last active April 19, 2017 19:42
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save timnashcouk/dd1ff318489f6bfd8743 to your computer and use it in GitHub Desktop.
Save timnashcouk/dd1ff318489f6bfd8743 to your computer and use it in GitHub Desktop.
Using PGP in WordPress
<?php
/**
* Plugin Name: WP PGP Email
* Version: 0.1
* Description: Provides mechanism to encrypt outgoing email using PGP
* Author: Tim Nash
* Author URI: https://timnash.co.uk
* Plugin URI: https://timnash.co.uk/wordpress-pgp-email
*
*
* License: GPLv2 or later
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* Don't call this file directly.
*/
if ( ! class_exists( 'WP' ) ) {
die();
}
class wpPGP{
function __construct()
{
add_action('init', array($this, 'init'));
}
function init()
{
//Add email filter
add_filter('wp_mail', array($this, 'filter_email'));
//Add Form actions for user profile
add_action('show_user_profile', array($this, 'add_profile_field'));
add_action('edit_user_profile', array($this, 'add_profile_field'));
add_action('personal_options_update', array($this, 'save_profile_field'));
add_action('edit_user_profile_update', array($this, 'save_profile_field'));
}
//Get key for user or return false if no key is found
static function get_key( $user_id = false )
{
if( !$user_id ) return null;
return get_user_meta( $user_id, 'pgp_key', true );
}
//Set a key for a specific user, overriding any existing key.
static function set_key( $user_id = false, $key = false )
{
if( !$user_id || !$key ) return null;
//@todo validate key
return update_user_meta( $user_id, 'pgp_key', $key);
}
//Remove key from database, if $match = true only remove if $key matches existing key otherwise error
static function remove_key( $user_id = false, $key = false, $match = false )
{
if( !$user_id || !$key ) return null;
$check_key = FALSE;
if($match)
{
$check_key = $key;
}
return delete_user_meta( $user_id, 'pgp_key', $check_key );
}
//Encrypt contents using users key, if force is set to false and no key found return unencrypted content, if set to true return false.
static function encrypt_contents( $user_id = false, $contents = false, $force = false )
{
if( !$user_id || !$contents ) return null;
require_once 'libs/GPG.php';
$gpg = new GPG();
$key = self::get_key( $user_id );
if(!$key){
if($force)
{
return false;
}
else
{
return $contents;
}
}
//we have a key and contents, let's encrypt it
// create an instance of a GPG public key object based on ASCII key
$pub_key = new GPG_Public_Key($key);
// using the key, encrypt your plain text using the public key
return $gpg->encrypt($pub_key,$contents);
}
static function validate_key_type( $key )
{
var_dump($key);
require_once 'libs/GPG.php';
$gpg = new GPG();
$pub_key = new GPG_Public_Key($key);
return $pub_key->GetKeyType();
}
//Filters WP_MAIL and encrypts content if being sent to a user with PGP key in the DB
function filter_email( $args )
{
//Check if the email is being sent to a user
$user = get_user_by( 'email', $args['to'] );
if($user){
if(self::get_key( $user->ID ))
{
if($args['message'])
{
$encrypted_contents = self::encrypt_contents( $user->ID, $args['message']);
if($encrypted_contents) $args['message'] = $encrypted_contents;
}
//For people using the Mandril plugin
elseif($args['html'])
{
$encrypted_contents = self::encrypt_contents( $user->ID, $args['html']);
if($encrypted_contents) $args['html'] = $encrypted_contents;
}
}
}
return $args;
}
/*
*
* Admin Views
* These really should be in there own class but for this example we will leave them here
*
*/
function add_profile_field( $user )
{
$pgp_key = self::get_key( $user->ID);
//Well this is unpleasant but very WordPressy
?>
<h3><?php _e('Email Encryption', 'wp-pgp-email'); ?></h3>
<table class="form-table">
<tbody>
<tr>
<th>
<label for="pgp"><?php _e('Public PGP Key','wp-pgp-email'); ?></label>
</th>
<td>
<textarea name="pgp" id="pgp" rows="5" cols="30"><?php if($pgp_key) echo $pgp_key; ?></textarea>
<br>
<?php if($pgp_key){ ?>
<span class="description">KeyType: <?php echo self::validate_key_type($pgp_key); ?></span>
<?php } ?>
</td>
</tr>
</tbody>
</table>
<?php
}
function save_profile_field( $user_id )
{
if ( !current_user_can( 'edit_user', $user_id ) )
return false;
$key = $_POST['pgp'];
return self::set_key( $user_id, $key );
}
}
$wp_pgp_email = new wpPGP;
@timnashcouk
Copy link
Author

@tobestool
Copy link

Hi,

Really useful code, thanks. However I've found a bug that stops it working. The incoming parameter to the encrypt_contents function is $contents plural. However the return on line 110 encrypts the variable $content (singular). This seems to result in a corrupt block that I can't decrypt.

Hope that saves someone else the head scratching I've just gone through!

Cheers,

--Toby

@fabacab
Copy link

fabacab commented Jan 22, 2016

This is a great general pattern but is missing a few key pun intended) features and WordPress integrations. Have a look at the WP PGP Encrypted Emails plugin for a more complete solution to protect outgoing emails.

@DanielRuf
Copy link

@meitar the mentioned plugin uses the same library, take a look at the code in the subversion repository.

Anyway, I highly recommend https://github.com/singpolyma/openpgp-php as there are many security related issues in php-gpg (ECB mode for example instead of CBC)

@fabacab
Copy link

fabacab commented Apr 7, 2016

Thanks Daniel! As you probably know, WP PGP Encrypted Emails is now using the library you suggested. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment