PHP中的RSA非對(duì)稱加密城榛,讓數(shù)據(jù)不再裸跑

前言:由于項(xiàng)目快速發(fā)展,敏感數(shù)據(jù)的保密傳輸也不夠完善歉提,前期開發(fā)寫的比較簡陋從而埋下隱患浙炼。迫切需要提升安全。翻閱相關(guān)文檔也寫到:‘’PHP服務(wù)端客戶端交互或者提供開放API時(shí)唯袄,通常需要對(duì)敏感的數(shù)據(jù)進(jìn)行加密弯屈。這時(shí)候RSA非對(duì)稱加密就可以派上用處×悼剑“對(duì)此記錄開發(fā)過程资厉,總結(jié)心得。

翻閱資料,先了解什么是非對(duì)稱加密算法

在非對(duì)稱加密中使用的主要算法有:RSA蔬顾、Elgamal宴偿、ESA、背包算法诀豁、Rabin窄刘、D-H、ECC(橢圓曲線加密算法)等舷胜。不同算法的實(shí)現(xiàn)機(jī)制不同娩践,可參考對(duì)應(yīng)算法的詳細(xì)資料。

非對(duì)稱加密算法:
需要兩個(gè)密鑰來進(jìn)行加密和解密烹骨,這兩個(gè)秘鑰是公開密鑰(public key翻伺,簡稱公鑰)私有密鑰(private key,簡稱私鑰)沮焕。

工作原理:用公開密鑰對(duì)數(shù)據(jù)進(jìn)行加密吨岭,只有用對(duì)應(yīng)的私有密鑰才能解密;
如果用私有密鑰對(duì)數(shù)據(jù)進(jìn)行加密峦树,那么只有用對(duì)應(yīng)的公開密鑰才能解密辣辫。
因?yàn)榧用芎徒饷苁褂玫氖莾蓚€(gè)不同的密鑰,所以這種算法叫作[非對(duì)稱加密算法]魁巩。

與對(duì)稱加密算法的對(duì)比
優(yōu)點(diǎn):其安全性更好急灭,對(duì)稱加密的通信雙方使用相同的秘鑰,如果一方的秘鑰遭泄露歪赢,那么整個(gè)通信就會(huì)被破解化戳。而非對(duì)稱加密使用一對(duì)秘鑰,一個(gè)用來加密,一個(gè)用來解密点楼,而且公鑰是公開的扫尖,秘鑰是自己保存的,不需要像對(duì)稱加密那樣在通信之前要先同步秘鑰掠廓。
缺點(diǎn):非對(duì)稱加密的缺點(diǎn)是加密和解密花費(fèi)時(shí)間長换怖、速度慢,只適合對(duì)少量數(shù)據(jù)進(jìn)行加密蟀瞧。

前期準(zhǔn)備

前提:本文章是在TP5下操作沉颂。

1.準(zhǔn)備RSA算法類https://www.kancloud.cn/mikkle/thinkphp5_study/343303
2.準(zhǔn)備jsencrypt.js悦污。https://www.bootcdn.cn/jsencrypt/
3.在線生產(chǎn)RSA秘鑰工具铸屉。http://web.chacuo.net/netrsakeypair

開始實(shí)操

先上一個(gè)我修改過的RSA算法類

<?php

/**
 * Created by PhpStorm.
 * User: ***
 * Date: 2020/3/4
 */

namespace Library;

/**
 * RSA算法類
 * 簽名及密文編碼:base64字符串/十六進(jìn)制字符串/二進(jìn)制字符串流
 * 填充方式: PKCS1Padding(加解密)/NOPadding(解密)
 *
 * Notice:Only accepts a single block. Block size is equal to the RSA key size!
 * 如密鑰長度為1024 bit,則加密時(shí)數(shù)據(jù)需小于128字節(jié)切端,加上PKCS1Padding本身的11字節(jié)信息彻坛,所以明文需小于117字節(jié)
 *
 * 加入生成私匙和公匙
 */
class RsaEncryption
{

    public $pubKey;

    private $priKey;


    /**
     * 初始化
     *
     */
    public function __construct()
    {
        $this->pubKey = '你的公鑰';
        $this->priKey = '你的私鑰';
    }

    /**
     * 自定義錯(cuò)誤處理
     */

    private function _error($msg)
    {
        die('RSA Error:' . $msg); //TODO
    }

    /**
     * 生成簽名
     *
     * @param string 簽名材料
     * @param string 簽名編碼(base64/hex/bin)
     * @return 簽名值
     */

    public function sign($data, $code = 'base64')
    {
        $ret = false;
        if (openssl_sign($data, $ret, $this->priKey)) {
            $ret = $this->_encode($ret, $code);
        }
        return $ret;
    }


    /**
     * 加密
     *
     * @param string 明文
     * @param string 密文編碼(base64/hex/bin)
     * @param int 填充方式(貌似php有bug,所以目前僅支持OPENSSL_PKCS1_PADDING)
     * @return string 密文
     */

    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;
    }

    /**
     * 解密
     * @param string $encryptString
     * @return string
     */
    public function privateDecrypt($encryptString = '')
    {
        $decrypted = '';
        $key = $this->priKey;
        $key_eol   = (string) implode("\n", str_split((string) $key, 64));
        $privateKey = (string) "-----BEGIN RSA PRIVATE KEY-----\n" . $key_eol . "\n-----END RSA PRIVATE KEY-----";

        openssl_private_decrypt(base64_decode($encryptString), $decrypted, $privateKey);
        return $decrypted;
    }

    /**
     * 加密
     * @param string $data
     * @return string
     */
    public function publicEncrypt($data = '')
    {
        $encrypt_data = '';
        $key = $this->pubKey;

        $key_eol   = (string) implode("\n", str_split((string) $key, 64));
        $publicKey = (string) "-----BEGIN PUBLIC KEY-----\n" . $key_eol . "\n-----END PUBLIC KEY-----";
        openssl_public_encrypt($data, $encrypt_data, $publicKey);
        $encrypt_data = base64_encode($encrypt_data);
        return $encrypt_data;
    }

    // 私有方法

    /**
     * 檢測填充類型
     * 加密只支持PKCS1_PADDING
     * 解密支持PKCS1_PADDING和NO_PADDING
     *
     * @param int 填充模式
     * @param string 加密en/解密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;
    }
}

1.先引用RSA

use Library\RsaEncryption;

2.在需要加密數(shù)據(jù)的頁面給公鑰

public function index()
    {
        $rsa = new RsaEncryption();
        $key = $rsa->pubKey;
        $this->assign('key', $key);
        //$redisInstall = Cache::getInstance('redis');
        return $this->fetch();
    }

3.前端頁面進(jìn)行加密處理
比如在表單提交需要對(duì)密碼加密

//需要加密的數(shù)據(jù)
var pas = $('#password').val();

var encrypt = new JSEncrypt();
//用傳來的公鑰進(jìn)行加密
encrypt.setPublicKey('拿到的公鑰');
var encrypted = encrypt.encrypt(pas);

//返給后端加密過后的數(shù)據(jù)
var pwd = document.getElementById('pwd');
pwd.value = encrypted;

4.在后端解密

$rsa = new RsaEncryption();
$rsaPass = $rsa->privateDecrypt('傳回來的數(shù)據(jù)');
注意

密鑰不對(duì)可是會(huì)報(bào)以下錯(cuò)誤踏枣。


image.png

切記格式要正確昌屉,不可有換行,要去頭去尾茵瀑。


image.png

總結(jié)

以上是我對(duì)RSA加解密一些簡單操作的一個(gè)記錄间驮,如果有幫助到大家,就可以了~ 望大佬勿噴勿噴马昨。竞帽。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請(qǐng)通過簡信或評(píng)論聯(lián)系作者偏陪。
  • 序言:七十年代末抢呆,一起剝皮案震驚了整個(gè)濱河市煮嫌,隨后出現(xiàn)的幾起案子笛谦,更是在濱河造成了極大的恐慌,老刑警劉巖昌阿,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件饥脑,死亡現(xiàn)場離奇詭異,居然都是意外死亡懦冰,警方通過查閱死者的電腦和手機(jī)灶轰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來刷钢,“玉大人笋颤,你說我怎么就攤上這事。” “怎么了伴澄?”我有些...
    開封第一講書人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵赋除,是天一觀的道長。 經(jīng)常有香客問我非凌,道長举农,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任敞嗡,我火速辦了婚禮颁糟,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘喉悴。我一直安慰自己棱貌,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開白布箕肃。 她就那樣靜靜地躺著键畴,像睡著了一般。 火紅的嫁衣襯著肌膚如雪突雪。 梳的紋絲不亂的頭發(fā)上起惕,一...
    開封第一講書人閱讀 49,764評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音咏删,去河邊找鬼惹想。 笑死,一個(gè)胖子當(dāng)著我的面吹牛督函,可吹牛的內(nèi)容都是我干的嘀粱。 我是一名探鬼主播,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼辰狡,長吁一口氣:“原來是場噩夢啊……” “哼锋叨!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起宛篇,我...
    開封第一講書人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤娃磺,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后叫倍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體偷卧,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年吆倦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了听诸。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蚕泽,死狀恐怖晌梨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤仔蝌,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布砸逊,位于F島的核電站,受9級(jí)特大地震影響掌逛,放射性物質(zhì)發(fā)生泄漏师逸。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一豆混、第九天 我趴在偏房一處隱蔽的房頂上張望篓像。 院中可真熱鬧,春花似錦皿伺、人聲如沸员辩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽奠滑。三九已至,卻和暖如春妒穴,著一層夾襖步出監(jiān)牢的瞬間宋税,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來泰國打工讼油, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留杰赛,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓矮台,卻偏偏與公主長得像乏屯,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子瘦赫,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容