Using RSA to Encrypt and Decrypt PHP Development Interface

Keywords: PHP encoding less network

Network security is very important, especially to ensure data security. Many programmers who are writing interfaces transmit data directly in plaintext, which seems to me to be very unprofessional. I advocate that the data through the interface should be encrypted and decrypted before use.

This article mainly introduces the use of PHP development interface, data encryption and decryption after RSA use, example analysis of PHP custom RSA class to achieve encryption and decryption skills, very practical value, the friends you need can refer to.

A brief introduction to RSA:

RSA encryption algorithm is the most commonly used asymmetric encryption algorithm, CFCA can not leave it in certificate service. But many novices don't know much about it. The following is a brief introduction. RSA is the first perfect public key algorithm. It can be used for both encryption and digital signature. RSA is named after its three inventors Ron Rivest, Adi Shamir and Leonard Adleman. This algorithm has withstood many years of in-depth cryptanalysis. Although cryptanalysts can neither prove nor deny the security of RSA, it just shows that the algorithm has certain credibility. At present, it has become the most popular public key algorithm. RSA security is based on the difficulty of large number decomposition. Its public and private keys are functions of a pair of prime numbers (100 to 200 decimal numbers or larger). The difficulty of recovering plaintext from a public key and ciphertext is equivalent to decomposing the product of two large prime numbers (which is a recognized mathematical problem).  


The following are specific classes and examples:

    <?php
    
    /**
     * RSA Algorithmic class
     * Signature and ciphertext encoding: base64 string/hexadecimal string/binary string stream
     * Filling mode: PKCS1 Padding (encryption and decryption)/NOPadding (decryption)
     *
     * Notice:Only accepts a single block. Block size is equal to the RSA key size!
     * If the key length is 1024 bit s, the encrypted data should be less than 128 bytes, plus 11 bytes of information of PKCS1 Padding itself, so the plaintext should be less than 117 bytes.
     *
     * @author: ZHIHUA_WEI
     * @version: 1.0.0
     * @date: 2017/06/30
     */
    class RSA
    {
        private $pubKey = null;
        private $priKey = null;
    
        /**
         * Constructor
         *
         * @param string Public key file (passed in when checking and encrypting)
         * @param string Private key file (incoming when signing and decrypting)
         */
        public function __construct($public_key_file = '', $private_key_file = '')
        {
            if ($public_key_file) {
                $this->_getPublicKey($public_key_file);
            }
            if ($private_key_file) {
                $this->_getPrivateKey($private_key_file);
            }
        }
    
        // Private methods
        /**
         * Custom error handling
         */
        private function _error($msg)
        {
            die('RSA Error:' . $msg); //TODO
        }
    
        /**
         * Detecting Filling Type
         * Encryption only supports PKCS1_PADDING
         * Decryption supports PKCS1_PADDING and NO_PADDING
         *
         * @param int Filling mode
         * @param string Encryption en/decryption de
         * @return bool
         */
        private function _checkPadding($padding, $type)
        {
            if ($type == 'en') {
                switch ($padding) {
                    case OPENSSL_PKCS1_PADDING:
                        $ret = true;
                        break;
                    default:
                        $ret = false;
                }
            } else {
                switch ($padding) {
                    case OPENSSL_PKCS1_PADDING:
                    case OPENSSL_NO_PADDING:
                        $ret = true;
                        break;
                    default:
                        $ret = false;
                }
            }
            return $ret;
        }
    
        private function _encode($data, $code)
        {
            switch (strtolower($code)) {
                case 'base64':
                    $data = base64_encode('' . $data);
                    break;
                case 'hex':
                    $data = bin2hex($data);
                    break;
                case 'bin':
                default:
            }
            return $data;
        }
    
        private function _decode($data, $code)
        {
            switch (strtolower($code)) {
                case 'base64':
                    $data = base64_decode($data);
                    break;
                case 'hex':
                    $data = $this->_hex2bin($data);
                    break;
                case 'bin':
                default:
            }
            return $data;
        }
    
        private function _getPublicKey($file)
        {
            $key_content = $this->_readFile($file);
            if ($key_content) {
                $this->pubKey = openssl_get_publickey($key_content);
            }
        }
    
        private function _getPrivateKey($file)
        {
            $key_content = $this->_readFile($file);
            if ($key_content) {
                $this->priKey = openssl_get_privatekey($key_content);
            }
        }
    
        private function _readFile($file)
        {
            $ret = false;
            if (!file_exists($file)) {
                $this->_error("The file {$file} is not exists");
            } else {
                $ret = file_get_contents($file);
            }
            return $ret;
        }
    
        private function _hex2bin($hex = false)
        {
            $ret = $hex !== false && preg_match('/^[0-9a-fA-F]+$/i', $hex) ? pack("H*", $hex) : false;
            return $ret;
        }
    
        /**
         * Generate signature
         *
         * @param string Signature material
         * @param string Signature encoding (base64/hex/bin)
         * @return Signature value
         */
        public function sign($data, $code = 'base64')
        {
            $ret = false;
            if (openssl_sign($data, $ret, $this->priKey)) {
                $ret = $this->_encode($ret, $code);
            }
            return $ret;
        }
    
        /**
         * Verify signature
         *
         * @param string Signature material
         * @param string Signature value
         * @param string Signature encoding (base64/hex/bin)
         * @return bool
         */
        public function verify($data, $sign, $code = 'base64')
        {
            $ret = false;
            $sign = $this->_decode($sign, $code);
            if ($sign !== false) {
                switch (openssl_verify($data, $sign, $this->pubKey)) {
                    case 1:
                        $ret = true;
                        break;
                    case 0:
                    case -1:
                    default:
                        $ret = false;
                }
            }
            return $ret;
        }
    
        /**
         * encryption
         *
         * @param string Plaintext
         * @param string Ciphertext encoding (base64/hex/bin)
         * @param int Filling mode (apparently php has bug s, so only OPENSSL_PKCS1_PADDING is currently supported)
         * @return string ciphertext
         */
        public function encrypt($data, $code = 'base64', $padding = OPENSSL_PKCS1_PADDING)
        {
            $ret = false;
            if (!$this->_checkPadding($padding, 'en')) $this->_error('padding error');
            if (openssl_public_encrypt($data, $result, $this->pubKey, $padding)) {
                $ret = $this->_encode($result, $code);
            }
            return $ret;
        }
    
        /**
         * Decrypt
         *
         * @param string ciphertext
         * @param string Ciphertext encoding (base64/hex/bin)
         * @param int Filling mode (OPENSSL_PKCS1_PADDING/OPENSSL_NO_PADDING)
         * @param bool Whether to flip plaintext (When passing Microsoft CryptoAPI-generated RSA cyphertext, revert the bytes in the block)
         * @return string Plaintext
         */
        public function decrypt($data, $code = 'base64', $padding = OPENSSL_PKCS1_PADDING, $rev = false)
        {
            $ret = false;
            $data = $this->_decode($data, $code);
            if (!$this->_checkPadding($padding, 'de')) $this->_error('padding error');
            if ($data !== false) {
                if (openssl_private_decrypt($data, $result, $this->priKey, $padding)) {
                    $ret = $rev ? rtrim(strrev($result), "\0") : '' . $result;
                }
            }
            return $ret;
        }
    }
    

This is the specific RSA class.


    <?php
    /**
     * Author: Wei ZhiHua
     * Date: 2017/6/30 0030
     * Time: 10:15 a.m.
     */
    header('Content-Type:text/html;Charset=utf-8;');
    include "RSA.php";
    echo '<pre>';
    
    $pubfile = 'D:\WWW\test\rsa_public_key.pem';
    $prifile = 'D:\WWW\test\rsa_private_key.pem';
    $rsa = new RSA($pubfile, $prifile);
    $rst = array(
        'ret' => 200,
        'code' => 1,
        'data' => array(1, 2, 3, 4, 5, 6),
        'msg' => "success",
    );
    $ex = json_encode($rst);
    //encryption
    $ret_e = $rsa->encrypt($ex);
    //Decrypt
    $ret_d = $rsa->decrypt($ret_e);
    echo $ret_e;
    echo '<pre>';
    echo $ret_d;
    
    echo '<pre>';
    
    $a = 'test';
    //autograph
    $x = $rsa->sign($a);
    //Verification
    $y = $rsa->verify($a, $x);
    var_dump($x, $y);
    exit;

Usage method.

Posted by Jeller on Mon, 17 Jun 2019 16:23:03 -0700