Last active
April 19, 2017 19:42
-
-
Save timnashcouk/dd1ff318489f6bfd8743 to your computer and use it in GitHub Desktop.
Using PGP in WordPress
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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; |
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.
@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)
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
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