Alex Bor - Web Developer

Building a PGP Encrypted Contact Form with PHP

thumbnail

Emails are often an overlooked area for security even though they often contain important material. In this tutorial I will be showing how to build a contact form for a website that shall encrypt the email’s body before sending it.

Demo or Download

Here’s a couple of tools that we shall be using to get the encryption working.

1) https://gpgtools.org – A key generator and tool for adding the ability to read the messages directly in Mac Mail.
2) GPG pecl module to work with PHP

Step 1 – Generating your keys

If you’re on a mac, download and install GPG Tools. This is a great application for handling much of the needed work for reading encrypted emails as well as generating and storing your keys.

GPG_Keychain_Access

To generate, click on new and enter in your name, followed by the email address you’d like the keys to be generated for.

The tool will now generate two keys. A private key and a public key. You may also wish to send your public key to a key server to allow anyone to send you encrypted emails.

Your public key is exactly that, it’s public. The public key is what’s used to encrypt your message. Once this has been done it can only been decrypted with the private key.

It’s now a good idea to go and grab your keys’ fingerprint. This is done by right-clicking on the key and selecting “Show Info”

Key_Inspector_and_GPG_Keychain_Access_and_Netflix

Step 2 – Installing GPG on Ubuntu 14.04

This is where I got a few issues, if you’re lucky you can just run

$ sudo apt-get install libgpgme11-dev
$ sudo pecl install gnupg

followed by adding extension=gnupg.so to your php.ini file and restarting Apache services.

If this worked you’re all set to start using GPG on your server! If not, you may need to run the following:

# First run pear to download the packages. It will probably put the packages into
# /build/buildd/php5-5.5.9+dfsg/pear-build-download/
# but it can't install them.
$ pear upgrade

# Un-Gzip the downloaded packages.
$ gunzip /build/buildd/php5-5.5.9+dfsg/pear-build-download/*.tgz

$ pear upgrade /build/buildd/php5-5.5.9+dfsg/pear-build-download/gnupg-1.3.3.tar

Helping source: http://stackoverflow.com/questions/23762141/pear-succeeded-but-it-is-not-a-valid-package

You can check if it’s installed by typing

$ gpg

and you should a response of “Go ahead and type your message …“. Pressing control + C will exit this.

Step 3 – Building your contact form

This tutorial is more about the server side rather then the front end so I won’t be going into the following with much detail but here is the contact form along with the CSS and JS running Bootstrap.

 

<!doctype html>

<!--[if lt IE 7]><html lang="en-US" class="no-js lt-ie9 lt-ie8 lt-ie7"><![endif]-->
<!--[if (IE 7)&!(IEMobile)]><html lang="en-US" class="no-js lt-ie9 lt-ie8"><![endif]-->
<!--[if (IE 8)&!(IEMobile)]><html lang="en-US" class="no-js lt-ie9"><![endif]-->
<!--[if gt IE 8]><!--> <html lang="en-US" class="no-js"><!--<![endif]-->
<head>

	<meta charset="utf-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">

	<title>Encrypted Contact Form | Alex Bor - Demo | Web Developer</title>

	<!-- JS -->
	<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
	<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
	<script src="assets/js/scripts.js"></script>

	<!-- CSS -->
	<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">

	<link href="assets/css/style.css" rel="stylesheet"></link>
	<link href="/global/assets/css/demobase.css" rel='stylesheet'></link>

</head>

<body>
<div id="demo_header">
Alex Bor - Demo

<span style="float: right;"><a href="https://alexbor.com/blog/building-pgp-enctypted-contact-form">&lt; Back to turorial</a></span>
</div>
<div id="main" class="container">
	<div class="col-md-12">
		<form role="form" id="contact_form">

			<div class="form-group">
				<label for="name">Your Name</label>
				<input type="text" class="form-control" id="name" placeholder="Enter name">
			</div>

			<div class="form-group">
				<label for="email">Email address</label>
				<input type="email" class="form-control" id="email" placeholder="Enter email">
			</div>

			<div class="form-group">
				<label for="subject">Subject</label>
				<input type="text" id="subject" class="form-control"  placeholder="Enter subject">
			</div>

			<div class="form-group">
				<label for="message">Message</label><br /><small>Your message shall be encrypted before it is sent</small>
				<textarea class="form-control" id="message" placeholder="Enter your message"></textarea>
			</div>

			<button type="submit" data-loading-text="Sending Email..." data-complete-text="Email Sent!" id="submit_contact" class="btn btn-default">Send Email</button></p>

			<div class="alert alert-danger message_errors">Sorry, errors were found in the contact form. Each field is required.</div>

		</form>

		<div class="alert alert-success success_message">Your message has been encrypted and submitted successfully</div>
	</div>
</div>
</body>

 

$(function() {
	$('.success_message').hide();
	$('.message_errors').hide();

	//on submitting for them
    $("#contact_form").submit(function(e){

      	e.preventDefault();

        //reset warnings and make button show loading text
        $('.message_errors').fadeOut();
        $('#submit_contact').button('loading');

        //disable elements in the form
        $('#contact_form .form-control').each(
        	function(){

            $(this).attr("disabled", "disabled");
        });

        //gather inputs data
        var name = $('input#name').val();
		var email = $('input#email').val();
		var subject = $('input#subject').val();
		var message = $('textarea#message').val();

		//location of sendering script
		var $location = "sender.php";

		//ajax post
		$.ajax({
		    type: 'POST',
         	dataType: 'json',
         	data: 'name=' + name + '&email=' + email + "&subject=" + subject + '&message=' + message,
    		url: $location,
			success: function(json){
				//reset disabled items
                $('#contact_form .form-control').each(function(){
                    $(this).removeAttr("disabled", "disabled");
                });
                $('#submit_contact').button('reset');

                //if error in the contact form show them
                if(json.error === true){
                	$('.message_errors').html(json.error_messages);
                    $('.message_errors').fadeIn();

                //else hide the form
                } else {
                   $('#contact_form').slideUp(1000);
                   $('.success_message').fadeIn();
                }
          }
		});

    });

});

Step 4 – Importing your key

To encrypt a message you must import the public key for the email address that you will be sending a message to. As this is a self-hosted contact form that will be used to contact oneself we can hardcode the public key for the email address.

Create a PHP script, get your public key by exporting it and opening it up in a text editor then just paste it below in $pub_key to import it.

 

<?php

	$gpg = new gnupg();

	$pub_key = "-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG/MacGPG2 v2.0.22 (Darwin)
Comment: GPGTools - https://gpgtools.org

mQENBFLgVTky7hiXSTuPwmR4+GbNrZ
oFB2H/EZbtsVU0Gn8ROQvnvHannKFqu5vU+6Tdg4Wil0eqn9DkJH2d6zfDbrJY+G
Q9UzHgL5o23PVSDPs5WL0UpBlijjU...

...yMDPCscVRU6VvnPIaf0Dy+nw+ei6EjqJe9dJu6XodulzhjSOODhJ4M+btImqVirp
dzSw6M+pDQOPBhEsYDmtkeX/V5FZVWQb59PVOOl29IYDx5mmNeSBabyx8Ck=
=C12c
-----END PGP PUBLIC KEY BLOCK-----";

	$info = $gpg->import($pub_key);

	print_r($info);

?>

After running, if imported correctly you should see the following:

Array (
	[imported] => 1
	[unchanged] => 0
	[newuserids] => 0
	[newsubkeys] => 0
	[secretimported] => 0
	[secretunchanged] => 0
	[newsignatures] => 0
	[skippedkeys] => 0
	[fingerprint] => FINGERPRINT_CODE
)

If you didn’t copy the fingerprint from before you may wish to copy it from here. This fingerprint is how this key shall be identified.

Step 5 – Sending the contact form

Now your key is imported, GPG is installed and the contact form is sending data it’s time to put everything together and encrypt the message.

 


<?php

	//New GPG object
	$gpg = new gnupg();

	//fingerprint of the key we shall be using
	$pub_key_fingerprint = "FINGER PRINT"; 

	//adding/setting the key to the GPG resource object
	$gpg->addencryptkey($pub_key_fingerprint);

	//standard error correction for the contact form
    $error = false;
    $error_messages = array();

    $reciver_email = "you@example.com";
    $reciver_name = "FIRST LAST";

    if(!isset($_POST['name']) || empty($_POST['name'])){
        $error = true;
        $error_messages[] = "No Name Entered";
    }

    if(!isset($_POST['email']) || empty($_POST['email'])){
        $error = true;
        $error_messages[] = "No Email Address Entered";
    }

    if(!isset($_POST['subject']) || empty($_POST['subject'])){
        $error = true;
        $error_messages[] = "No Subject Entered";
    }

    if (!empty($_POST['email']) && !filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) {
        $error = true;
        $error_messages[] = "Email Address Not Valid";
    }

    if(!isset($_POST['message']) || empty($_POST['message'])){
        $error = true;
        $error_messages[] = "No Message Entered";
    }

    if($error){
    	$string_responce = "";
    	$total = sizeof($error_messages);
    	$i = 1; 

    	foreach($error_messages as $e):
    		$string_responce .= $e ;
    		if($i != $total) $string_responce .= '<br />';
    		$i++;
    	endforeach;

        $reply = array(
            'error' => true,
            'error_messages' => $string_responce
            );
        echo json_encode($reply);
        die();
    } else {

        $name = $_POST['name'];
        $email = $_POST['email'];
        $subject = $_POST['subject'];
        $message = $_POST['message'];

        $body = "";
		$body .= "Name: " . $name .  "\r\n";
		$body .= "Email: " . $email .  "\r\n";
		$body .= "Subject: " . $subject .  "\r\n";
		$body .= "Message:  ";
		$body .= $_POST['message'];

		//Encrypting the message
		$body = $gpg->encrypt($body);

		$headers .= "From: {$name} <{$email}>" . "\r\n";
		$headers .= "To: {$reciver_name} <{$reciver_email}>" . "\r\n";

		// 		to, 	sub, 	body, 	headers, 	param
		mail($reciver_email, $subject, $body, $headers);

		$reply = array(
        	'error' => false
        );
        echo json_encode($reply);

        die();
    }
?>

The main part in this being


    //New GPG object
    $gpg = new gnupg();

    //fingerprint of the key we shall be using
    $pub_key_fingerprint = "DE45CC66A7X6DF72EC57ERA9B40F0CF2AEF31343"; 

    //adding/setting the key to the GPG resource object
    $gpg->addencryptkey($pub_key_fingerprint);

    //Encrypting the message
    $body = $gpg->encrypt($body);

This shows how easy it is to encrypt messages with GPG in PHP.

Side Notes

Something to remember is though this gives good encryption for the email, to make the system secure as a whole you’ll want to make sure all is covered under HTTPS not just HTTP .

Also bear in mind if you want to view these emails on a mobile device you’ll need an email reader that includes GPG encryption. After a quick look, some do exist for iPhone.

Conclusion

I hope that this helped anyone who wanted to get started with sending encrypted emails. If you’d like to download the files click below and don’t forget to share and comment.

 

Demo or Download

Sharing is caring...Tweet about this on TwitterShare on FacebookShare on LinkedInPin on PinterestShare on RedditEmail this to someone