PHP通過OpenSSL生成證書、密鑰並且加密解密數據,以及公鑰,私鑰和數字簽名的理解


一、公鑰加密

假設一下,我找了兩個數字,一個是1,一個是2。我喜歡2這個數字,就保留起來,不告訴你們(私鑰),然后我告訴大家,1是我的公鑰。

我有一個文件,不能讓別人看,我就用1加密了。別人找到了這個文件,但是他不知道2就是解密的私鑰啊,所以他解不開,只有我可以用
數字2,就是我的私鑰,來解密。這樣我就可以保護數據了。

我的好朋友x用我的公鑰1加密了字符a,加密后成了b,放在網上。別人偷到了這個文件,但是別人解不開,因為別人不知道2就是我的私鑰,
只有我才能解密,解密后就得到a。這樣,我們就可以傳送加密的數據了。

 

二、私鑰簽名

如果我用私鑰加密一段數據(當然只有我可以用私鑰加密,因為只有我知道2是我的私鑰),結果所有的人都看到我的內容了,因為他們都知道我的公鑰是1,那么這種加密有什么用處呢?

但是我的好朋友x說有人冒充我給他發信。怎么辦呢?我把我要發的信,內容是c,用我的私鑰2,加密,加密后的內容是d,發給x,再告訴他
解密看是不是c。他用我的公鑰1解密,發現果然是c。
這個時候,他會想到,能夠用我的公鑰解密的數據,必然是用我的私鑰加的密。只有我知道我得私鑰,因此他就可以確認確實是我發的東西。
這樣我們就能確認發送方身份了。這個過程叫做數字簽名。當然具體的過程要稍微復雜一些。用私鑰來加密數據,用途就是數字簽名

 

總結:公鑰和私鑰是成對的,它們互相解密。

公鑰加密,私鑰解密。

私鑰數字簽名,公鑰驗證

 

准備工作

找到php.ini 去掉openssl.dll前面的';'。找到openssl.cnf的位置,我的在D:\xampp\apache\conf。
配置apache以支持SSL:打開apache的配置文件conf/httpd.conf
LoadModule ssl_module modules/mod_ssl.so、Include conf/extra/httpd-ssl.conf

 

三、示例代碼

 1 $config = array(
 2     "private_key_bits" => 1024,                     //字節數    512 1024  2048   4096 等
 3     "private_key_type" => OPENSSL_KEYTYPE_RSA,     //加密類型
 4     "config" => "D:/phpStudy/PHPTutorial/Apache/conf/openssl.cnf"
 5 );
 6 
 7 $privkeypass = '123456789'; //私鑰密碼
 8 $numberofdays = 365;     //有效時長
 9 $cerpath = "./test.cer"; //生成證書路徑
10 $pfxpath = "./test.pfx"; //密鑰文件路徑
11 
12 $dn = array(    
13     "countryName" => "UK",                                  //所在國家
14     "stateOrProvinceName" => "Somerset",                    //所在省份
15     "localityName" => "Glastonbury",                        //所在城市
16     "organizationName" => "The Brain Room Limited",         //注冊人姓名
17     "organizationalUnitName" => "PHP Documentation Team",   //組織名稱
18     "commonName" => "Wez Furlong",                          //公共名稱
19     "emailAddress" => "wez@example.com"                     //郵箱
20 );
21 
22 // 生成公鑰私鑰資源
23 $res = openssl_pkey_new($config);
24 
25 // 導出私鑰 $priKey
26 openssl_pkey_export($res, $priKey,null,$config);
27 
28 //  導出公鑰 $pubKey
29 $pubKey = openssl_pkey_get_details($res);
30 $pubKey = $pubKey["key"];
31 //print_r($priKey); 私鑰
32 //print_r($pubKey); 公鑰
33 
34 //直接測試私鑰 公鑰
35 echo '-------------------公私鑰加解密-START---------------------','<br>';
36 $data = '測試公私鑰加解密成功!';
37 // 公鑰加密
38 openssl_public_encrypt($data, $encrypted, $pubKey);
39 // 私鑰解密
40 openssl_private_decrypt($encrypted, $decrypted, $priKey);
41 
42 echo '公鑰加密:',base64_encode($encrypted),'私鑰解密:','<br>',$decrypted,'<br>';
43 echo '-------------------公私鑰加解密-END---------------------','<br>';
44 
45 //生成文件
46 $csr = openssl_csr_new($dn, $priKey,$config); //基於$dn生成新的 CSR (證書簽名請求)
47 $sscert = openssl_csr_sign($csr, null, $priKey, 365,$config);//根據配置自己對證書進行簽名
48 openssl_x509_export($sscert, $csrkey); //將公鑰證書存儲到一個變量 $csrkey,由 PEM 編碼格式命名。
49 openssl_pkcs12_export($sscert, $privatekey, $priKey, $privkeypass); //將私鑰存儲到名為的出 PKCS12 文件格式的字符串。 導出密鑰$privatekey
50 
51 //生成證書文件
52 $fp = fopen($cerpath, "w");
53 fwrite($fp, $csrkey);
54 fclose($fp);
55 //生成密鑰文件
56 $fp = fopen($pfxpath, "w");
57 fwrite($fp, $privatekey);
58 fclose($fp);
59 
60 
61 echo '<br>','<br>','<br>','<br>';
62 echo '----------------------自簽名驗證-START----------------------','<br>';
63 // 測試私鑰 秘鑰
64 $privkeypass = '123456789'; //私鑰密碼
65 $pfxpath = "./test.pfx"; //密鑰文件路徑
66 $priv_key = file_get_contents($pfxpath); //獲取密鑰文件內容
67 $data = "測試數據!"; //加密數據測試test
68 //私鑰加密
69 openssl_pkcs12_read($priv_key, $certs, $privkeypass); //讀取公鑰、私鑰
70 $prikeyid = $certs['pkey']; //私鑰
71 openssl_sign($data, $signMsg, $prikeyid,OPENSSL_ALGO_SHA1); //注冊生成加密信息
72 $signMsg = base64_encode($signMsg); //base64轉碼加密信息
73 
74 
75 //公鑰解密
76 $unsignMsg=base64_decode($signMsg);//base64解碼加密信息
77 openssl_pkcs12_read($priv_key, $certs, $privkeypass); //讀取公鑰、私鑰
78 $pubkeyid = $certs['cert']; //公鑰
79 $res = openssl_verify($data, $unsignMsg, $pubkeyid); //驗證
80 echo $res?'證書測試成功!':'證書測試失敗!';echo '<br>'; //輸出驗證結果,1:驗證成功,0:驗證失敗
81 
82 echo '-----------------------簽名驗證-END------------------------','<br>';

openssl_sign 默認signature_alg參數是OPENSSL_ALGO_SHA1

  如果使用DSA加密方式需要使用OPENSSL_ALGO_DSS1參數

  signature_alg 其他參數

  OPENSSL_ALGO_DSS1 (integer)

  OPENSSL_ALGO_SHA1 (integer)

  OPENSSL_ALGO_SHA224 (integer)

  OPENSSL_ALGO_SHA256 (integer)

  OPENSSL_ALGO_SHA384 (integer)

  OPENSSL_ALGO_SHA512 (integer)

  OPENSSL_ALGO_RMD160 (integer)

  OPENSSL_ALGO_MD5 (integer)

  OPENSSL_ALGO_MD4 (integer)

  OPENSSL_ALGO_MD2 (integer)

過程出現的問題集錦:http://blog.sina.com.cn/s/blog_8da982ac0101lqh1.html

 

特別說明:

x509,公鑰證書,只有公鑰。
p7,簽名或加密。可以往里面塞x509,同時沒有簽名或加密內容。
p12,含有私鑰,同時可以有公鑰,有口令保護。
p7的作用就是電子信封。
X509是基本規范
P7和P12是兩個實現規范,P7是數字信封,P12是帶有私鑰的證書規范。
x509是數字證書的規范,P7和P12是兩種封裝形式。比如說同樣的電影,有的是avi格式,有的是mpg,大概就這個意思。

P7一般是把證書分成兩個文件,一個公鑰一個私鑰,有PEM和DER兩種編碼方式。PEM比較多見,就是純文本的,P7一般是分發公鑰用,看到的就是一串可見字符串,擴展名經常是.crt,.cer,.key等。DER是二進制編碼。
P12是把證書壓成一個文件,.pfx 。主要是考慮分發證書,私鑰是要絕對保密的,不能隨便以文本方式散播。所以P7格式不適合分發。.pfx中可以加密碼保護,所以相對安全些。
在實踐中要中,用戶證書都是放在USB Key中分發,服務器證書經常還是以文件方式分發。服務器證書和用戶證書,都是X509證書,就是里面的屬性有區別。

X509 是證書規范
PKCS#7 是消息語法 (常用於數字簽名與加密)
PKCS#12 個人消息交換與打包語法 (如.PFX .P12)打包成帶公鑰與私鑰


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM