A cryptography API wrapping the Sodium library, providing a simple object interface for symmetrical and asymmetrical encryption, decryption, digital signing and message authentication.

Overview

PHP Encryption

Build Status!

A cryptography API wrapping the Sodium library, providing a simple object interface for symmetrical and asymmetrical encryption, decryption, digital signing and message authentication.

The Encryption class is able to generate secrets and keypairs, encrypt and decrypt data, sign and verify data, and generate and verify digital signatures.

Encrypted messages are returned base64 encoded, while keys and secrets are returned as hexadecimal strings.

The transformation of these to and from binary data makes use of the sodium_* timing-safe functions.

All underlying cryptography is performed using the Sodium library.

This library requires PHP 7.2 or higher with libsodium installed (this is bundled with PHP 7.2 or above, so you probably already have it).

Installation

Install via Composer

composer require dwgebler/encryption

Usage

For a quick start, see the included demo.php file.

Create an instance of the Encryption class.

<?php
    use Gebler\Encryption\Encryption;
    
    $crypt = new Encryption();

Symmetric Encryption

Use the function encryptWithSecret(string $message, string $password, bool $hexEncoded = true) to encrypt a message with a secret key. This function expects the message or data to be encrypted as a string, and the secret key as a hexadecimal string. If your secret is not a hexadecimal encoded, you can pass false as the third parameter to indicate that the secret is not encoded.

You can either generate a secret key with generateSecret() or use a pre-existing one.

Alternatively, you can pass in a reference to a null or empty string to generate a secret key.

    $mySecret = null;
    $data = "Hello world! This is a secret message.";
    $result = $crypt->encryptWithSecret($data, $mySecret);
    // $mySecret has now been populated with a new secret key

    // Alternatively, generate a new key.
    $mySecret = $crypt->generateEncryptionSecret();
    $result = $crypt->encryptWithSecret($data, $mySecret);

    // Alternatively, create a key and encode it as hex.
    // Keys should be 32 bytes long - shorter keys are forced to this length by a deterministic hash,
    // but this is not recommended. Longer keys will throw an InvalidArgumentException.
    $mySecret = bin2hex("my_super_secret_key");
    // ...or use random_bytes() to generate a random key.
    $mySecret = bin2hex(random_bytes(32));
    $result = $crypt->encryptWithSecret($data, $mySecret);
    
    // Or, pass in a raw binary key by setting the `hex` parameter to false.
    $mySecret = random_bytes(32);
    $result = $crypt->encryptWithSecret($data, $mySecret, false);
    // $result is now base64 encoded, e.g.
    echo $result;
    // wgYwuB/by9bz+CvHj1EtylicXnRH6hl9hLALsUUPUHaZeO3sEj4hgi8+pKBZGZIG6ueRKw3xpvrG8dRWU9OCn3aMtlwLz8aapUX/oK3L 

To decrypt your message, use the function decryptWithSecret().

    $mySecret = "my_super_secret_key";
    $message = "This is a test message.";
    $encrypted = $crypt->encryptWithSecret($message, $mySecret, false);
    echo $encrypted, PHP_EOL;
    $decrypted = $crypt->decryptWithSecret($encrypted, $mySecret, false);
    echo $decrypted, PHP_EOL;

Asymmetric Encryption

To carry out authenticated asymmetric encryption (i.e. where the message is both encrypted and the sender of the message can be verified), you need to generate a public and private key pair for the sender. You will also need the public key of the recipient.

    // Generate a new random keypair.
    $keypair = $crypt->generateEncryptionKeypair();
    // Or provide a password to generate a deterministic keypair.
    $keypair = $crypt->generateEncryptionKeypair("my_super_secret_password");
    // Or use a pre-existing keypair.
    
    // Once you have a keypair, you can export the public key as a hexadecimal string,
    // for storage or transmission.
    $publicKey = $keypair['publicKey'];
    
    // The keypair also includes the private key.
    $privateKey = $keypair['privateKey'];    

    // The full keypair is also provided. This is a string containing both the private and public key.
    $fullKeypair = $keypair['keypair'];

As an example, let's encrypt a message from Alice to Bob.

    $aliceKeypair = $crypt->generateEncryptionKeypair("alice_secret");
    // In the real-world, Bob has provided Alice with his public key, but for demo purposes
    // we'll generate a keypair for him too.
    $bobKeypair = $crypt->generateEncryptionKeypair("bob_secret");
    
    // Alice encrypts a message for Bob, using his public key and her private key.
    $message = "Hello Bob! This is a secret message from Alice.";
    $encrypted = $crypt->encryptWithKey($message, $bobKeypair['publicKey'], $aliceKeypair['privateKey']);
    // Alice can now transmit $encrypted to Bob. It will look something like this:
    // hMvdJf2L78ZWcF38WRXJ16q3xXnlsWWfOsbJISPVwJhBtdcWbZ8SquS3oyJD1k6H/lAs+VHXPpDNfYLWO3wMLl+FB8rYUyCe+IZzti3dFL0YljeJ3QreGlrv
    echo $encrypted, PHP_EOL;
    
    // Bob decrypts the message using his private key and the public key of Alice.
    $decrypted = $crypt->decryptWithKey($encrypted, $bobKeypair['privateKey'], $aliceKeypair['publicKey']);
    // Hello Bob! This is a secret message from Alice.
    echo $decrypted, PHP_EOL;

You can also use this library to carry out anonymous asymmetric encryption, using only the public key of the recipient. In this case, the sender's private key is not required and although only the recipient (the holder of the corresponding private key) can decode the message, they cannot identify or authenticate the sender. This is similar to openssl_public_encrypt .

    $bobKeypair = $crypt->generateEncryptionKeypair("bob_secret");
    // Alice encrypts a message for Bob, using his public key.
    $message = "Hello Bob! This is a secret message from an unknown sender.";
    $encrypted = $crypt->encryptWithKey($message, $bobKeypair['publicKey']);
    // Alice can now transmit $encrypted to Bob.
    echo $encrypted, PHP_EOL;
    
    // Bob decrypts the message using his full keypair.
    $decrypted = $crypt->decryptWithKey($encrypted, $bobKeypair['keypair']);
    // Hello Bob! This is a secret message from an unknown sender.
    echo $decrypted, PHP_EOL;

Digital Signing

Asymmetric encryption is useful for securing messages, but it is also useful for authenticating the sender of a message.

Digital signatures are a way to authenticate the sender of a message, as well the message itself, ensuring it has not been tampered with or altered during transmission.

    // Generate a new random keypair.
    // Like generateEncryptionKeypair, you can also optionally provide a password to generate a deterministic keypair.
    $aliceSigningKeypair = $crypt->generateSigningKeypair();
    
    // Alice signs a message for Bob, using her private key.
    $message = "This is a message signed by Alice.";
    $signedMessage = $crypt->getSignedMessage($message, $aliceSigningKeypair['privateKey']);
    // Alice can now transmit $signedMessage to Bob. It will look something like this:
    // JaI6p6jb5qQ041DiK1Yqbk8u1r/wVAovzy57ELfwrWfhqLCUU9jTzBLH6K6v1VF/8vOxaOZe2r8ch/GUKmfgC1RoaXMgaXMgYSBtZXNzYWdlIHNpZ25lZCBieSBBbGljZS4=
    // Note: The message itself is NOT encrypted and can be viewed by anyone, by decoding the base64-encoded signed message.
    echo $signedMessage, PHP_EOL;
    
    // Bob can now use Alice's public key to verify the signature and obtain the message part.
    // If the message has been tampered with, the signature will be invalid and the message will be rejected.
    $verifiedMessage = $crypt->verifySignedMessage($signedMessage, $aliceSigningKeypair['publicKey']);
    // This is a message signed by Alice.
    echo $verifiedMessage, PHP_EOL;
    

We can also generate a signature for a message without attaching it to the message itself.

    $aliceSigningKeypair = $crypt->generateSigningKeypair();
    
    // Alice signs a message for Bob, using her private key.
    $message = "This is a message signed by Alice.";
    $signature = $crypt->getMessageSignature($message, $aliceSigningKeypair['privateKey']);
    
    // Alice can now transmit the message and signature separately to Bob.
    // Bob can now use Alice's public key to verify the signature.
    // If the message has been tampered with, the signature will be invalid and the message will be rejected.
    $messageAuthenticated = $crypt->verifyMessageSignature($message, $signature, $aliceSigningKeypair['publicKey']);
    if ($messageAuthenticated === true) {
        echo "The message has not been tampered with.", PHP_EOL;
    } 

Message Authentication

Instead of asymmetric keys, we can also use a shared secret to generate a Message Authentication Code (MAC) and use this to sign and authenticate messages.

    $message = "This is a message signed anonymously with a secret key.";
    // We can generate a secure, random 32 byte key, which is returned as a hexadecimal string.
    $secret = $crypt->generateSigningSecret();
    // Or, as long as the key is 32 bytes (256 bits), you can use any other string.
    $secret = hash("sha256", "my secret key");
    
    // Like with the symmetric encryption functions, you can pass an optional third parameter
    // to signWithSecret to specify that the secret key is NOT a hexadecimal string.
    $secret = hash("sha256", "my secret key", true);
    $signature = $crypt->signWithSecret($message, $secret, false);

    // Or omit this parameter if the secret is a hexadecimal string.
    $secret = $crypt->generateSigningSecret();
    $signature = $crypt->signWithSecret($message, $secret);
    
    // The message can now be either transmitted to someone else who also has the shared secret,
    // or later verified on the same system, e.g. after being retrieved from a database.
    $messageAuthenticated = $crypt->verifyWithSecret($signature, $message, $secret);
    
    if ($messageAuthenticated === true) {
        echo "The message has not been tampered with.", PHP_EOL;
    }
    
    // Similarly, pass false as the third parameter if the secret is NOT a hexadecimal string.
    $secret = hash("sha256", "my secret key", true);
    $signature = $crypt->signWithSecret($message, $secret, false);
    $messageAuthenticated = $crypt->verifyWithSecret($signature, $message, $secret, false);
    if ($messageAuthenticated === true) {
        echo "The message has not been tampered with.", PHP_EOL;
    }       

Licence

This software is released under the MIT License.

Bugs, questions, comments

Please raise a GitHub issue if you encounter any problems or have any questions.

You might also like...
Simple Encryption in PHP.

php-encryption composer require defuse/php-encryption This is a library for encrypting data with a key or password in PHP. It requires PHP 5.6 or new

Password manager featuring client-side encryption, vaults, folders and more.
Password manager featuring client-side encryption, vaults, folders and more.

vaults is a password manager featuring client side AES-256 encryption, PBKDF2 hashing, vaults, password generation & more. Features Technical overview

Encryption-free Private Messaging For Flarum

Whisper - Private Messaging for Flarum A Flarum extension. Add private messaging functionality to your Flarum Community! Simple to install, no setting

An experimental object oriented SSH api in PHP

PHP SSH (master) Provides an object-oriented wrapper for the php ssh2 extension. Requirements You need PHP version 5.3+ with the SSH2 extension. Insta

Windows and macOS Hardening Interface to make security more accessible.

Welcome to the Hardening Interface Introduction To use HardeningKitty service more easily, we have created an interface which permits better understan

Fast common interface for php_gmp and php_bcmath modules

BigInteger wrapper library for PHP Information This library is a common interface for php_gmp and php_bcmath modules. It automatically detects support

A PHP wrapper around the OpenSSL extension that provides a user-friendly interface for dealing with OpenSSL.

php-openssl-proxy About A PHP wrapper around the OpenSSL extension that provides a user-friendly interface for dealing with OpenSSL. What's up with th

[OUTDATED] Two-factor authentication for Symfony applications 🔐 (bunde version ≤ 4). Please use version 5 from https://github.com/scheb/2fa.

scheb/two-factor-bundle ⚠ Outdated version. Please use versions ≥ 5 from scheb/2fa. This bundle provides two-factor authentication for your Symfony ap

TCrypto is a simple and flexible PHP 5.3+ in-memory key-value storage library

About TCrypto is a simple and flexible PHP 5.3+ in-memory key-value storage library. By default, a cookie will be used as a storage backend. TCrypto h

Comments
  • sodium_memzero issue in PHP 7.2+

    sodium_memzero issue in PHP 7.2+

    I'm running into a "strange" issue. Which I don't quite understand.

    Currently I'm trying to make use of the encryptWithSecret() method to encrypt a piece of data. The thing is it's failing due to the sodium_memzero() lines you have here: https://github.com/dwgebler/php-encryption/blob/master/src/Encryption.php#L69-L71

    When I output the SodiumException error this is what it says:

    This is not implemented in sodium_compat, as it is not possible to securely wipe memory from PHP. To fix this error, make sure libsodium is installed and the PHP extension is enabled.

    --

    The thing is that seems to be an error that comes from a sodium_compat library: https://github.com/paragonie/sodium_compat/blob/v1.12.1/src/Compat.php#L3210 but since sodium is included by default in PHP 7.2+ I don't know why I'd be getting this exception?

    I did some googling and found these this thread: https://github.com/phpseclib/phpseclib/issues/1432 and this fix: https://github.com/phpseclib/phpseclib/commit/e3557220d7b4f10b4b8420ba71845e88b3b69c50 for that particular library. But this is for PHP <7.2 so why would I be getting that exception on PHP 8 which supposed to have its own included version of sodium with no need for a compat library?

    Currently the fix seems to be to instead use unset rather than sodium_memzero

    opened by UVLabs 1
  • Issue in PHP 7.2+

    Issue in PHP 7.2+

    Sodium was included by default in PHP 7.2+ without the need for an extension:

    Developers can use Sodium for PHP encryption and decryption with PHP 7.2 and newer without an extension. If you want to use Sodium with PHP 7.0 or 7.1, you need to install aPECL extension.

    Cited here: https://www.zend.com/blog/libsodium-and-php-encrypt

    On this line: https://github.com/dwgebler/php-encryption/blob/master/src/Encryption.php#L14 you're checking for the existence of the extension regardless of PHP version and stopping the script if it doesn't exist.

    I had to get around this by commenting out the line since I'm using PHP 8+ and know that the library is included.

    opened by UVLabs 1
Releases(1.1.0)
Owner
Developer, very minor PHP core contributor (okay, one implemented RFC but it still counts!), ❤ everything PHP, also versed in Node.js, Python, HTML/CSS/JS.
null
JSON Object Signing and Encryption library for PHP.

NAMSHI | JOSE Deprecation notice Hi there, as much as we'd like to be able to work on all of the OSS in the world, we don't actively use this library

Namshi 1.7k Dec 22, 2022
Simplest implementation of RSA algorithm encryption and decryption

Simplest RSA (Rivest–Shamir–Adleman) Simplest implementation of RSA algorithm encryption and decryption. Richard Feynman: What I cannot create, I do n

Max Base 8 Aug 30, 2022
AES 128 bit Encryption and Decryption algorithm excuted purely on PHP with no external libraries.

AES128 Executed with PHP Advanced Encryption Standard (AES) is a specification for the encryption of electronic data established by the U.S National I

Ahmed Mohamed Mostafa 2 Aug 8, 2022
Replaces Laravel's built-in encryption with an encryption based on AWS KMS

Laravel Kms Encryption Introduction This package replaces Laravel's built-in encryption with an encryption based on AWS KMS. Two major features provid

Arnaud Becher 3 Oct 26, 2021
High-level cryptography interface powered by libsodium

Halite Halite is a high-level cryptography interface that relies on libsodium for all of its underlying cryptography operations. Halite was created by

Paragon Initiative Enterprises 1.1k Dec 22, 2022
Fast, general Elliptic Curve Cryptography library. Supports curves used in Bitcoin, Ethereum and other cryptocurrencies (secp256k1, ed25519, ..)

Fast Elliptic Curve Cryptography in PHP Information This library is a PHP port of elliptic, a great JavaScript ECC library. Supported curve types: Sho

Simplito 178 Dec 28, 2022
Pretty Good Privacy (PGP) is an encryption program that provides cryptographic privacy and authentication for data communication.

Pretty Good Privacy (PGP) is an encryption program that provides cryptographic privacy and authentication for data communication. PGP is used for signing, encrypting, and decrypting texts, e-mails, files, directories, and whole disk partitions and to increase the security of e-mail communications. Phil Zimmermann developed PGP in 1991.

[sCRiPTz-TEAM] 3 Dec 31, 2021
Strong cryptography tools and password hashing

laminas-crypt ???? Русским гражданам Мы, участники Laminas, родились и живем в разных странах. У многих из нас есть друзья, родственники и коллеги как

Laminas Project 29 Dec 15, 2022
A simple php (lumen) app for sharing sensitive text (basically like onetimesecret), but with full end-to-end AES-256-GCM encryption so even the server has no access to the data, and developed with very simple deployment in mind.

A simple php (lumen) app for sharing sensitive text (basically like onetimesecret), but with full end-to-end AES-256-GCM encryption so even the server has no access to the data, and developed with very simple deployment in mind.

Alan Woo 51 Nov 21, 2022
A petite library of encryption functions for PHP

?? dcrypt A petite library of essential encryption functions for PHP 7.1+. For legacy PHP version support, look here. If you need a dcrypt inspired en

null 96 Oct 6, 2022