首頁 >後端開發 >PHP問題 >PHP如何使用OpenSSL加密中的非對稱加密

PHP如何使用OpenSSL加密中的非對稱加密

醉折花枝作酒筹
醉折花枝作酒筹原創
2021-06-02 17:50:282015瀏覽

這篇文章跟大家介紹一下PHP使用OpenSSL加密中非對稱加密的方法。有一定的參考價值,有需要的朋友可以參考一下,希望對大家有幫助。

PHP如何使用OpenSSL加密中的非對稱加密

上篇文章,我們了解了對稱和非對稱加密的一些相關的理論知識,也學習了使用 OpenSSL 來進行對稱加密的操作。今天,我們就更進一步,學習 OpenSSL 中的非對稱加密是如何實現的。

產生私鑰

透過先前的學習,我們知道非對稱加密是分別需要一個公鑰和一個私鑰的。我們就先來產生一個私鑰,也就是存放在我們這一端一個金鑰。請記住,在任何時候,私鑰都是不能給別人的!

$config = array(
    "private_key_bits" => 4096, // 指定应该使用多少位来生成私钥
);

$res = openssl_pkey_new($config); // 根据配置信息生成私钥

openssl_pkey_export($res, $privateKey); // 将一个密钥的可输出表示转换为字符串
var_dump($privateKey); 
// -----BEGIN PRIVATE KEY-----
// MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQDFMLW+9t3fNX4C
// YBuV0ILSyPAdSYVXtE4CLv32OvNk9yQZgF2nL/ZuIbBGRcYo2Hf5B31doGrAFDGu
// NoTR+WA7CBjKROFr/+yValsMFIeiKNtttWMkmBciysDJoEoyd6wjDD+kcHQdoJVo
// ……
// -----END PRIVATE KEY-----

非常簡單的一個函數 openssl_pkey_new() ,它接收一個參數,這個參數是可配置項並且是可選參數。產生的結果是一個私鑰句柄,不是我們能直接讀取的內容,所以我們再使用 openssl_pkey_export() 來提取可輸出的字串。

註解中的內容就是我們產生的私鑰資訊了,私鑰資訊一般會相對多些,所以省略了後面的內容。

抽取公鑰

接下來就是要產生公鑰了,其實,公鑰是從私鑰擷取出來的。所以我們使用進行加解密的時候,都可以使用私鑰或是公鑰互相操作。

$publicKey = openssl_pkey_get_details($res); // 抽取公钥信息
var_dump($publicKey);
// array(4) {
//     ["bits"]=>
//     int(4096)
//     ["key"]=>
//     string(800) "-----BEGIN PUBLIC KEY-----
//   MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtOIImDdS0W0vAr5Ra1+E
//   hR2AJwQQwxntYKgTku8EmJRBX2vU+x8th8W8SnoGiVM/sOItG0HIe4Egf1UxoZHt
//   gI6r+jpAp7JbTN0sD/VTPDE09F21+hFGjIVBqrkcLPjuEbf7+tjmgAx8cG8WLGId
//   G8Hsub70kRANKJe1bCXIBUggRFk0sQGllxA/hxiG5wANqHTrdpJgJba+ahSi2+4H
//   UWnyCV1O3AaPyz6a12HNUsG4Eio/tWv/hOB9POt6nAqwPHuIbhp56i5bv1ijMJZM
//   jwRen5f/kwdZ01Ig2fi0uBoTR2y/EEaus7xBYpF/gGzZ/uM7cNUXcDyG5YluM/4R
//   MEv4msPMVGB72izItED+C6Cqftxl98iBFRDc+PISFbRSgOU/HsuBhKkM5SYzyi3I
//   Ypaej25++qLPqcA+EDr3JNDhNZ0GOhofCRtPq4dsr7iLLLRnZ0TnhIYe9wAbmO49
//   uthABNBkM54bG+omOfY4Bkn5n39CKpELbhIiXgOd+lA684XUS/2Aw3Dvelc9Gbag
//   oIFvb/wljPYsd0Zmd64CXBpTWbfwXC8K4vCKvFLjytcz2Yp4T6fVjbLT5RA6u8su
//   E0WwE4QTFNKhnM5OvfiMN+NMc3Y/esVfcin3eyvotdz4N6Tt45dkybkf6aQE3Scg
//   E/JBLIEEA+gjGTveY4cNUiECAwEAAQ==
//   -----END PUBLIC KEY-----
//   "
//     ["rsa"]=>
// ……

$publicKey = $publicKey['key'];

使用 openssl_pkey_get_details() 抽取的內容包含很多內容。不過我們所需要的最主要的內容就是 key 下面的這個公鑰。

大家再回過頭來好好看看公鑰和私鑰的內容,是不是跟我們去申請的HTTPS 憑證中的公私鑰內容長得一樣,而且也和我們自己在系統中使用openssl命令列產生的本機的金鑰憑證一樣。它們本身就是一樣的東西啦,只是在不同的場景應用的不同而已。 HTTPS 憑證除了非對稱加密的金鑰之外,還包含有 CA 訊息,如果 CA 不通過,瀏覽器也會認為憑證是無效的,因此,我們使用自己產生的憑證來充當 HTTPS 憑證是不可以的。而本身產生的一般會用在 SSH 免密登入上,或是 GitHub 的免密程式碼倉庫操作。

加密解密資料

好了,公鑰和私鑰都產生完成了,那麼我們就要進行最重要的加密和解密作業了。

$data = '测试非对称加密';

// 公钥加密数据
openssl_public_encrypt($data, $encrypted, $publicKey);
var_dump($encrypted);
// string(512) 

// 私钥解密数据
openssl_private_decrypt($encrypted, $decrypted, $privateKey);
var_dump($decrypted);
// string(21) "测试非对称加密"

在這裡,我們使用的就是最標準的公鑰加密,私鑰解密來進行的測試。其實反過來也是可以的,OpenSSL 分別都為我們提供了公鑰的加解密和私鑰的加解密函數。

就像上篇文章的圖示那樣,對方取得我們的公鑰,然後加密資料傳輸過來,我們透過自己的私鑰解密資料取得原文。而我方也可以獲得對方的公鑰,並將傳回的資料加密後傳輸給對方,然後對方使用自己的私鑰進行解密來獲得我們傳遞給它的原文資料。

而 HTTPS 是透過 CA 頒發的憑證來取得公鑰的,瀏覽器透過公鑰加密請求資料傳輸給伺服器,伺服器也是透過相同的原理來向瀏覽器用戶端發送密文資料。因此,在資料傳輸過程中,使用 HTTPS 的傳輸會更加安全,即使被截獲了,對方也沒有憑證提供的金鑰來進行解密。這就是現在所有 App 和 小程式 應用程式都要求使用 HTTPS 的原因,當然,我們如果做網站開發也最好使用 HTTPS ,就連百度對 HTTPS 的收錄也有相應的調整。

簽章及驗證

接下來我們再接觸一個簽章的概念。當兩端進行通訊時,我們怎麼知道目前傳輸過來的資料一定是對端發送過來的呢,中間有沒有駭客進行了篡改呢?這個就可以透過簽章機制來驗證。

// 利用私钥生成签名
openssl_sign($data, $signature, $privateKey, OPENSSL_ALGO_SHA256);
var_dump($signature);

// 公钥验证签名
$r = openssl_verify($data, $signature, $publicKey, OPENSSL_ALGO_SHA256);
var_dump($r);
// int(1)

我們透過 openssl_sign() 來產生一個對原始資料的私鑰簽名,然後就可以使用 openssl_verify() 透過公鑰驗證資料簽名是否一致。

在使用的時候,發送者透過自己的私鑰產生簽名,由於簽名內容是亂碼的,我們可以將它 base64_encode() 一下,然後連同加密資料一起傳遞給接收方。然後接收者使用公鑰並根據簽名內容來驗證原文資料是否被篡改過。

// 发送方签名
$resquestSign = base64_encode($signature);

// 假设通过网络请求发送了数据
// ……
// 接收到获得签名及原始数据
// $signature = $_POST['sign'];
// openssl_private_decrypt($_POST['data'], $data, $privateKey); 

$responseSign = base64_decode($signature);
// 验证数据有没有被篡改
$r = openssl_verify($data, $signature, $publicKey, OPENSSL_ALGO_SHA256);
var_dump($r);
// int(1)

// 假设被篡改
$data = '我被修改了';
$r = openssl_verify($data, $signature, $publicKey, OPENSSL_ALGO_SHA256);
var_dump($r);
// int(0)

總結

今天的內容是不是感覺比對稱加密複雜了許多。特別新引進的簽章的這個概念,其實很多憑證相關的內容都會跟資料簽章有關係。也就是說,看似簡單的一個 HTTPS ,其實瀏覽器和服務端的 openssl 幫我們做了很多事情,遠不止你去 CA 申請一套憑證然後在 Nginx 配好那麼簡單。那麼,接下來,我們將要學習的就是產生憑證相關的內容了,繫好安全帶,車子還要繼續飆漲。

測試程式碼:

https://github.com/zhangyue0503/dev-blog/blob/master/php/202007/source/PHP%E7%9A%84OpenSSL%E5%8A%A0%E5%AF%86%E6%89%A9%E5%B1%95%E5%AD%A6%E4%B9%A0%EF%BC%88%E4%BA%8C%EF%BC%89%EF%BC%9A%E9%9D%9E%E5%AF%B9%E7%A7%B0%E5%8A%A0%E5%AF%86.php

推荐学习:php视频教程

以上是PHP如何使用OpenSSL加密中的非對稱加密的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn