PHP Classes

File: src/GPGMailer.php

Recommend this page to a friend!
  Classes of Scott Arciszewski   PHP GPG Email Encrypt   src/GPGMailer.php   Download  
File: src/GPGMailer.php
Role: Class source
Content type: text/plain
Description: Class source
Class: PHP GPG Email Encrypt
Encrypt, decrypt and sign email messages with GPG
Author: By
Last change: Update of src/GPGMailer.php
Date: 2 years ago
Size: 11,094 bytes
 

Contents

Class file image Download
<?php declare(strict_types=1); namespace ParagonIE\GPGMailer; use Laminas\Mail\{ Message, Transport\TransportInterface }; /** * Class GPGMailer * @package ParagonIE\GPGMailer */ class GPGMailer { /** * @var TransportInterface */ protected $mailer; /** * @var array<string, string|int|float|bool|null|array> */ protected $options; /** * @var string */ protected $serverKeyFingerprint = ''; /** * GPGMailer constructor. * * @param TransportInterface $transport * @param array<string, string|int|float|bool|null|array> $options * For Crypt_GPG * @param string $serverKey * * @throws GPGMailerException */ public function __construct( TransportInterface $transport, array $options = [], string $serverKey = '' ) { $this->mailer = $transport; $this->options = $options; if (!empty($serverKey)) { $this->serverKeyFingerprint = $this->import($serverKey); } } /** * Get the public key corresponding to a fingerprint. * * @param string $fingerprint * @return string * @throws \Crypt_GPG_Exception * @throws \Crypt_GPG_FileException * @throws GPGMailerException * @throws \PEAR_Exception */ public function export(string $fingerprint): string { $gnupg = new \Crypt_GPG($this->options); try { $gnupg->addEncryptKey($fingerprint); return $gnupg->exportPublicKey($fingerprint, true); } catch (\PEAR_Exception $ex) { throw new GPGMailerException( 'Could not export fingerprint "' . $fingerprint . '": ' . $ex->getMessage(), (int) $ex->getCode(), $ex ); } } /** * Encrypt the body of an email. * * @param Message $message * @return Message * @throws \Crypt_GPG_FileException * @throws GPGMailerException * @throws \PEAR_Exception */ public function decrypt(Message $message): Message { $gnupg = new \Crypt_GPG($this->options); try { $gnupg->addDecryptKey($this->serverKeyFingerprint); // Replace the message with its encrypted counterpart $decrypted = $gnupg->decrypt($message->getBodyText()); return (clone $message)->setBody($decrypted); } catch (\PEAR_Exception $ex) { throw new GPGMailerException( 'Could not decrypt message: ' . $ex->getMessage(), (int) $ex->getCode(), $ex ); } } /** * Encrypt the body of an email. * * @param Message $message * @param string $fingerprint * @return Message * @throws \Crypt_GPG_Exception * @throws \Crypt_GPG_FileException * @throws GPGMailerException * @throws \PEAR_Exception */ public function encrypt(Message $message, string $fingerprint): Message { $gnupg = new \Crypt_GPG($this->options); try { $gnupg->addEncryptKey($fingerprint); // Replace the message with its encrypted counterpart $encrypted = $gnupg->encrypt($message->getBodyText(), true); return (clone $message)->setBody($encrypted); } catch (\PEAR_Exception $ex) { throw new GPGMailerException( 'Could not encrypt message: ' . $ex->getMessage(), (int) $ex->getCode(), $ex ); } } /** * Encrypt and sign the body of an email. * * @param Message $message * @param string $fingerprint * @return Message * @throws GPGMailerException * @throws \Crypt_GPG_Exception * @throws \Crypt_GPG_FileException * @throws \PEAR_Exception */ public function encryptAndSign(Message $message, string $fingerprint): Message { if (!$this->serverKeyFingerprint) { throw new GPGMailerException('No signing key provided'); } $gnupg = new \Crypt_GPG($this->options); $gnupg->addEncryptKey($fingerprint); $gnupg->addSignKey($this->serverKeyFingerprint); try { // Replace the message with its encrypted counterpart $encrypted = $gnupg->encryptAndSign($message->getBodyText(), true); return (clone $message)->setBody($encrypted); } catch (\PEAR_Exception $ex) { throw new GPGMailerException( 'Could not encrypt and sign message: ' . $ex->getMessage(), (int) $ex->getCode(), $ex ); } } /** * Return the stored Transport. * * @return TransportInterface */ public function getTransport(): TransportInterface { return $this->mailer; } /** * Import a public key, return the fingerprint * * @param string $gpgKey An ASCII armored public key * @return string The GPG fingerprint for this key * @throws GPGMailerException */ public function import(string $gpgKey): string { try { $gnupg = new \Crypt_GPG($this->options); /** @var array<string, string> $data */ $data = $gnupg->importKey($gpgKey); return $data['fingerprint']; } catch (\PEAR_Exception $ex) { throw new GPGMailerException( 'Could not import public key: ' . $ex->getMessage(), (int) $ex->getCode(), $ex ); } } /** * Encrypt then email a message * * @param Message $message The message data * @param string $fingerprint Which public key fingerprint to use * @return void * * @throws \Crypt_GPG_Exception * @throws \Crypt_GPG_FileException * @throws GPGMailerException * @throws \PEAR_Exception */ public function send(Message $message, string $fingerprint) { if ($this->serverKeyFingerprint) { $this->mailer->send( // Encrypted, signed $this->encryptAndSign($message, $fingerprint) ); } else { $this->mailer->send( // Encrypted, unsigned $this->encrypt($message, $fingerprint) ); } } /** * Email a message without encrypting it. * * @param Message $message The message data * @param bool $force Send even if we don't have a private key? * @return void * * @throws GPGMailerException * @throws \Crypt_GPG_FileException * @throws \PEAR_Exception */ public function sendUnencrypted(Message $message, bool $force = false) { if (!$this->serverKeyFingerprint) { if ($force) { // Unencrypted, unsigned $message->setBody($message->getBodyText()); } return; } $this->mailer->send( // Unencrypted, signed: $this->sign($message) ); } /** * @param string $key * @return string|int|float|bool|null|array * * @throws GPGMailerException */ public function getOption(string $key) { if (!\array_key_exists($key, $this->options)) { throw new GPGMailerException('Key ' . $key . ' not defined'); } return $this->options[$key]; } /** * @return array<string, string|int|float|bool|null|array> */ public function getOptions(): array { return $this->options; } /** * Override an option at runtime * * @param string $key * @param string|int|float|bool|null|array $value * * @return self * @throws GPGMailerException */ public function setOption(string $key, $value): self { $options = $this->options; $options[$key] = $value; // Try to set this, so it will throw an exception try { (new \Crypt_GPG($options)); } catch (\PEAR_Exception $ex) { throw new GPGMailerException( 'Could not set option "' . $key . '": ' . $ex->getMessage(), (int) $ex->getCode(), $ex ); } $this->options = $options; return $this; } /** * Sets the private key for signing. * * @param string $serverKey * @return self * @throws GPGMailerException */ public function setPrivateKey(string $serverKey): self { $this->serverKeyFingerprint = $this->import($serverKey); return $this; } /** * @param TransportInterface $transport * * @return self */ public function setTransport(TransportInterface $transport): self { $this->mailer = $transport; return $this; } /** * Sign a message (but don't encrypt) * * @param Message $message * @return Message * * @throws \Crypt_GPG_FileException * @throws GPGMailerException * @throws \PEAR_Exception */ public function sign(Message $message): Message { if (!$this->serverKeyFingerprint) { throw new GPGMailerException('No signing key provided'); } $gnupg = new \Crypt_GPG($this->options); $gnupg->addSignKey($this->serverKeyFingerprint); try { return (clone $message)->setBody( $gnupg->sign( $message->getBodyText(), \Crypt_GPG::SIGN_MODE_CLEAR, true ) ); } catch (\PEAR_Exception $ex) { throw new GPGMailerException( 'Could not sign message: ' . $ex->getMessage(), (int) $ex->getCode(), $ex ); } } /** * Verify a message * * @param Message $message * @param string $fingerprint * @return bool * * @throws \Crypt_GPG_FileException * @throws GPGMailerException * @throws \PEAR_Exception */ public function verify(Message $message, string $fingerprint): bool { $gnupg = new \Crypt_GPG($this->options); $gnupg->addSignKey($fingerprint); /** * @var \Crypt_GPG_Signature[] $verified */ try { $verified = $gnupg->verify($message->getBodyText()); /** * @var \Crypt_GPG_Signature $sig */ foreach ($verified as $sig) { if ($sig->isValid()) { return true; } } return false; } catch (\PEAR_Exception $ex) { throw new GPGMailerException( 'An error occurred trying to verify this message: ' . $ex->getMessage(), (int) $ex->getCode(), $ex ); } } }