PHP 非對稱加密實現

PHP 實現非對稱加密邏輯 -實現保護用戶數據安全

在日常設計及開發中,爲確保數據傳輸和數據存儲的安全,可通過特定的算法,將數據明文加密成複雜的密文。目前主流加密手段大致可分爲單向加密和雙向加密。

單向加密:通過對數據進行摘要計算生成密文,密文不可逆推還原。算法代表:Base64,MD5,SHA; 

雙向加密:與單向加密相反,可以把密文逆推還原成明文,雙向加密又分爲對稱加密和非對稱加密。

對稱加密:指數據使用者必須擁有相同的密鑰纔可以進行加密解密,就像彼此約定的一串暗號。算法代表:DES,3DES,AES,IDEA,RC4,RC5;

非對稱加密:相對對稱加密而言,無需擁有同一組密鑰,非對稱加密是一種“信息公開的密鑰交換協議”。非對稱加密需要公開密鑰和私有密鑰兩組密鑰,公開密鑰和私有密鑰是配對起來的,
也就是說使用公開密鑰進行數據加密,只有對應的私有密鑰才能解密。這兩個密鑰是數學相關,用某用戶密鑰加密後的密文,只能使用該用戶的加密密鑰才能解密。如果知道了其中一個,並
不能計算出另外一個。因此如果公開了一對密鑰中的一個,並不會危害到另外一個密鑰性質。這裏把公開的密鑰爲公鑰,不公開的密鑰爲私鑰。算法代表:RSA,DSA。

非對稱加密算法

需要兩個密鑰:公開密鑰(publickey)和私有密鑰(privatekey)。
公開密鑰與私有密鑰是一對,如果用公開密鑰對數據進行加密,只有用對應的私有密鑰才能解密;
如果用私有密鑰對數據進行加密,那麼只有用對應的公開密鑰才能解密。
因爲加密和解密使用的是兩個不同的密鑰,所以這種算法叫作非對稱加密算法。

注意以上的一個點,公鑰加密的數據,只有對應的私鑰才能解密

在日常使用中是醬紫的:

將私鑰private_key.pem用在服務器端,公鑰發放給android跟ios等前端

客戶端用公鑰加密過後,數據只能被擁有唯一私鑰的服務器看懂。

代碼:

<?php
namespace Classes\Third\Utils;


/**
 * 非對稱加密
 * @author	田小濤
 * @date	2019年10月30日
 * @comment 數據安全機制
 *
 */
class RsaUtils
{
    
    //公鑰
    private $private;
    //私鑰
    private $public;
    //公-私鑰存儲位置
    private $keyPath;
    private $openssl;
    
    private static $_instance;
    private function __construct()
    {
        $this->keyPath = dirname( dirname( __FILE__ ) ) . DIRECTORY_SEPARATOR . 'rsa';
        $this->openssl = 'D:\Works\phpStudy\PHPTutorial\Apache\conf\openssl.cnf';
        $this->_init();
    }
    public static function getInstance()
    {
        if( null == self::$_instance )
        {
            self::$_instance = new self();
        }
        
        return self::$_instance;
    }
    
    /**
     * 初始化公-私鑰
     * @author	 田小濤
     * @datetime 2019年10月30日 下午1:14:01
     * @comment	
     * 
     * @return boolean
     */
    private function _init()
    {
        if( !file_exists( $this->keyPath . DIRECTORY_SEPARATOR . 'private_key.pem'  ) || !file_exists( $this->keyPath . DIRECTORY_SEPARATOR . 'public_key.pem' ) )
        {
            $this->initialization();
        }
        
        return true;
    }
    
    /**
     * 初始化公-私鑰
     * @author	 田小濤
     * @datetime 2019年10月30日 下午1:05:59
     * @comment	
     *
     */
    protected function initialization()
    {
        $config = array(
            'digest_alg'        => 'sha512',
            'private_key_bits'  => 2048,
            'private_key_type'  => OPENSSL_KEYTYPE_RSA,
            'config'            => $this->openssl,
        );
        try{
            //創建密鑰對
            $res = openssl_pkey_new( $config );
            //生成私鑰
            openssl_pkey_export($res, $privkey, null, $config);
            //生成公鑰
            $pubKey = openssl_pkey_get_details($res)[ 'key' ];
            file_put_contents( $this->keyPath . DIRECTORY_SEPARATOR . 'private_key.pem', $privkey );
            file_put_contents( $this->keyPath . DIRECTORY_SEPARATOR . 'public_key.pem', $pubKey );
            
            $this->private = openssl_pkey_get_private( $privkey );
            $this->public = openssl_pkey_get_public( $privkey );
        }catch ( \Exception $e ){
            
        }
        
        return true;
    }
    
    
    /**
     * 提取私鑰
     * @author	 田小濤
     * @datetime 2019年10月30日 上午11:38:02
     * @comment	
     * 
     * @return resource
     */
    private function _getPrivateKey()
    {
        $strPrivateKey = $this->keyPath . DIRECTORY_SEPARATOR. 'private_key.pem';
        $key = file_get_contents( $strPrivateKey );
        
        return openssl_pkey_get_private( $key );
    }
    
    
    /**
     * 提取公鑰
     * @author	 田小濤
     * @datetime 2019年10月30日 上午11:38:15
     * @comment	
     * 
     * @return resource
     */
    private function _getPublicKey()
    {
        $strPublicKey = $this->keyPath . DIRECTORY_SEPARATOR . 'public_key.pem';
        $key = file_get_contents( $strPublicKey );
        
        return openssl_pkey_get_public( $key );     
    }
    
    
    /**
     * 獲取公鑰
     * @author	 田小濤
     * @datetime 2019年10月30日 上午11:41:31
     * @comment	
     * 
     * @return resource
     */
    public function getPublicKey()
    {
        $this->public =  $this->_getPublicKey();
        
        return $this->public;
    }
    
    /**
     * 獲取私鑰
     * @author	 田小濤
     * @datetime 2019年10月30日 上午11:41:53
     * @comment	
     * 
     * @return resource
     */
    public function getPrivateKey()
    {
        $this->private =  $this->_getPrivateKey();
        
        return $this->private;
    }
    
    
    /**
     * 私鑰加密
     * @author	 田小濤
     * @datetime 2019年10月30日 上午11:43:42
     * @comment	
     * 
     * @param unknown $data
     */
    public function privEncrypt( $data = null )
    {
        if( is_null( $data ) )
        {
            return null;
        }
        if ( ( is_array( $data ) || is_object( $data ) ) && !empty( $data ) ) 
        {
            $data = json_encode( $data );
        }
        
        return openssl_private_encrypt( $data, $encrypted, $this->_getPrivateKey() ) ? base64_encode( $encrypted ) : null; 
    }
    
    /**
     * 公鑰加密
     * @author	 田小濤
     * @datetime 2019年10月30日 上午11:43:42
     * @comment	
     * 
     * @param unknown $data
     */
    public function publicEncrypt( $data = null )
    {
        if( is_null( $data ) )
        {
            return null;
        }
        if ( ( is_array( $data ) || is_object( $data ) ) && !empty( $data ) ) 
        {
            $data = json_encode( $data );
        }   
        
        return openssl_public_encrypt( $data, $encrypted, $this->_getPublicKey() ) ? base64_encode( $encrypted ) : null; 
    }
    
    
    /**
     * 私鑰解密
     * @author	 田小濤
     * @datetime 2019年10月30日 上午11:47:50
     * @comment	
     * 
     * @param unknown $encrypted
     */
    public function privDecrypt( $encrypted = null )
    {
        if( is_null( $encrypted ) || !is_string( $encrypted ) || strlen( $encrypted ) <= 0 )
        {
            return null;
        }
        
        return ( openssl_private_decrypt( base64_decode( $encrypted ), $decrypted, $this->_getPrivateKey() ) ) ? $decrypted : null;    
    }
    
    /**
     * 公鑰解密
     * @author	 田小濤
     * @datetime 2019年10月30日 上午11:47:50
     * @comment	
     * 
     * @param unknown $encrypted
     */
    public function publicDecrypt( $encrypted = null )
    {
        if( is_null( $encrypted ) || !is_string( $encrypted ) || strlen( $encrypted ) <= 0 )
        {
            return null;
        }
        
        return ( openssl_public_decrypt( base64_decode( $encrypted ), $decrypted, $this->_getPublicKey() ) ) ? $decrypted : null;    
    }
    
    
}

調用示例:

$en  = RsaUtils::getInstance();
$data = [ 'id' => 1, 'name' => '張三', 'age' => 12 ];
echo '<pre>';
var_dump( $data );
echo '<pre>';
$encrypt = $en->publicEncrypt( $data );
echo '加密字符串:' . $encrypt . '<br />';
$de = $en->privDecrypt( $encrypt );
    
echo '<pre>';
var_dump( json_decode( $de, true )  );
echo '<pre>';
exit;

**********************

那麼該類會在初始化的時候檢測公鑰/私鑰文件是否存在 若不存在則採用重新生成的方式生成

這個時候我們就可以實現每天/固定時間更新公鑰/私鑰確保更安全的數據傳輸

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章