PHP Classes

File: src/EasyRSA.php

Recommend this page to a friend!
  Packages of Scott Arciszewski   Easy PHP RSA Library   src/EasyRSA.php   Download  
File: src/EasyRSA.php
Role: Class source
Content type: text/plain
Description: Class source
Class: Easy PHP RSA Library
RSA data encryption and decryption using phpseclib
Author: By
Last change:
Date: 5 years ago
Size: 6,342 bytes
 

Contents

Class file image Download
<?php
namespace ParagonIE\EasyRSA;

// PHPSecLib:
use ParagonIE\EasyRSA\Exception\InvalidKeyException;
use \phpseclib\Crypt\RSA;
// defuse/php-encryption:
use \ParagonIE\ConstantTime\Base64;
use \Defuse\Crypto\Key;
use \Defuse\Crypto\Crypto;
// Typed Exceptions:
use \ParagonIE\EasyRSA\Exception\InvalidChecksumException;
use \ParagonIE\EasyRSA\Exception\InvalidCiphertextException;

class EasyRSA implements EasyRSAInterface
{
    const SEPARATOR = '$';
    const VERSION_TAG = "EzR2";

    static private $rsa;

    /**
     * Set RSA to use in between calls
     *
     * @param RSA|null $rsa
     */
    public static function setRsa(RSA $rsa = null)
    {
        self::$rsa = $rsa;
    }

    /**
     * Get RSA
     *
     * @param int $mode
     *
     * @return RSA
     */
    public static function getRsa($mode)
    {
        if (self::$rsa) {
            $rsa = self::$rsa;
        } else {
            $rsa = new RSA();
            $rsa->setMGFHash('sha256');
        }

        $rsa->setSignatureMode($mode);

        return $rsa;
    }

    /**
     * KEM+DEM approach to RSA encryption.
     *
     * @param string $plaintext
     * @param PublicKey $rsaPublicKey
     *
     * @return string
     */
    public static function encrypt($plaintext, PublicKey $rsaPublicKey)
    {
        // Random encryption key
        $random_key = random_bytes(32);

        // Use RSA to encrypt the random key
        $rsaOut = self::rsaEncrypt($random_key, $rsaPublicKey);

        // Generate a symmetric key from the RSA output and plaintext
        $symmetricKey = hash_hmac(
            'sha256',
            $rsaOut,
            $random_key,
            true
        );
        $ephemeral = self::defuseKey(
            $symmetricKey
        );

        // Now we encrypt the actual message
        $symmetric = Base64::encode(
            Crypto::encrypt($plaintext, $ephemeral, true)
        );

        $packaged = \implode(self::SEPARATOR,
            array(
                self::VERSION_TAG,
                Base64::encode($rsaOut),
                $symmetric
            )
        );

        $checksum = \substr(
            \hash('sha256', $packaged),
            0,
            16
        );

        // Return the ciphertext
        return $packaged . self::SEPARATOR . $checksum;
    }

    /**
     * KEM+DEM approach to RSA encryption.
     *
     * @param string $ciphertext
     * @param PrivateKey $rsaPrivateKey
     *
     * @return string
     * @throws InvalidCiphertextException
     * @throws InvalidChecksumException
     */
    public static function decrypt($ciphertext, PrivateKey $rsaPrivateKey)
    {
        $split = explode(self::SEPARATOR, $ciphertext);
        if (\count($split) !== 4) {
            throw new InvalidCiphertextException('Invalid ciphertext message');
        }
        if (!\hash_equals($split[0], self::VERSION_TAG)) {
            throw new InvalidCiphertextException('Invalid version tag');
        }
        $checksum = \substr(
            \hash('sha256', implode('$', array_slice($split, 0, 3))),
            0,
            16
        );
        if (!\hash_equals($split[3], $checksum)) {
            throw new InvalidChecksumException('Invalid checksum');
        }

        $rsaCipher = Base64::decode($split[1]);
        $rsaPlain = self::rsaDecrypt(
            $rsaCipher,
            $rsaPrivateKey
        );
        $symmetricKey = hash_hmac(
            'sha256',
            $rsaCipher,
            $rsaPlain,
            true
        );

        $key = self::defuseKey($symmetricKey);
        return Crypto::decrypt(
            Base64::decode($split[2]),
            $key,
            true
        );
    }

    /**
     * Sign with RSASS-PSS + MGF1+SHA256
     *
     * @param string $message
     * @param PrivateKey $rsaPrivateKey
     * @return string
     */
    public static function sign($message, PrivateKey $rsaPrivateKey)
    {
        $rsa = self::getRsa(RSA::SIGNATURE_PSS);

        $return = $rsa->loadKey($rsaPrivateKey->getKey());
        if ($return === false) {
            throw new InvalidKeyException('Signing failed due to invalid key');
        }

        return $rsa->sign($message);
    }

    /**
     * Verify with RSASS-PSS + MGF1+SHA256
     *
     * @param string $message
     * @param string $signature
     * @param PublicKey $rsaPublicKey
     * @return bool
     */
    public static function verify($message, $signature, PublicKey $rsaPublicKey)
    {
        $rsa = self::getRsa(RSA::SIGNATURE_PSS);

        $return = $rsa->loadKey($rsaPublicKey->getKey());
        if ($return === false) {
            throw new InvalidKeyException('Verification failed due to invalid key');
        }

        return $rsa->verify($message, $signature);
    }

    /**
     * Decrypt with RSAES-OAEP + MGF1+SHA256
     *
     * @param string $plaintext
     * @param PublicKey $rsaPublicKey
     * @return string
     * @throws InvalidCiphertextException
     */
    protected static function rsaEncrypt($plaintext, PublicKey $rsaPublicKey)
    {
        $rsa = self::getRsa(RSA::ENCRYPTION_OAEP);

        $return = $rsa->loadKey($rsaPublicKey->getKey());
        if ($return === false) {
            throw new InvalidKeyException('Ecryption failed due to invalid key');
        }

        return $rsa->encrypt($plaintext);
    }

    /**
     * Decrypt with RSAES-OAEP + MGF1+SHA256
     *
     * @param string $ciphertext
     * @param PrivateKey $rsaPrivateKey
     * @return string
     * @throws InvalidCiphertextException
     */
    protected static function rsaDecrypt($ciphertext, PrivateKey $rsaPrivateKey)
    {
        $rsa = self::getRsa(RSA::ENCRYPTION_OAEP);

        $return = $rsa->loadKey($rsaPrivateKey->getKey());
        if ($return === false) {
            throw new InvalidKeyException('Decryption failed due to invalid key');
        }

        $return = @$rsa->decrypt($ciphertext);
        if ($return === false) {
            throw new InvalidCiphertextException('Decryption failed');
        }
        return $return;
    }

    /**
     * Use an internally generated key in a Defuse context
     *
     * @param string $randomBytes
     * @return Key
     */
    protected static function defuseKey($randomBytes)
    {
        $kludege = new Kludge();
        return $kludege->defuseKey($randomBytes);
    }
}