opensslaes加密解密
對稱加解密演算法中,當前最為安全的是 AES 加密演算法(以前應該是是 DES 加密演算法),PHP 提供了兩個可以用於 AES 加密演算法的函數簇: Mcrypt 和 OpenSSL 。
其中 Mcrypt 在 PHP 7.1.0 中被棄用(The Function Mycrypt is Deprecated),在 PHP 7.2.0 中被移除,所以即可起你應該使用 OpenSSL 來實現 AES 的數據加解密。
在一些場景下,我們不能保證兩套通信系統都使用了相函數簇去實現加密演算法,可能 siteA 使用了最新的 OpenSSL 來實現了 AES 加密,但作為第三方服務的 siteB 可能仍在使用 Mcrypt 演算法,這就要求我們必須清楚 Mcrypt 同 OpenSSL 之間的差異,以便保證數據加解密的一致性。
下文中我們將分別使用 Mcrypt 和 OpenSSL 來實現 AES-128/192/256-CBC 加解密,二者同步加解密的要點為:
協同好以上兩點,就可以讓 Mcrypt 和 OpenSSL 之間一致性的對數據進行加解密。
AES 是當前最為常用的安全對稱加密演算法,關於對稱加密這里就不在闡述了。
AES 有三種演算法,主要是對數據塊的大小存在區別:
AES-128:需要提供 16 位的密鑰 key
AES-192:需要提供 24 位的密鑰 key
AES-256:需要提供 32 位的密鑰 key
AES 是按數據塊大小(128/192/256)對待加密內容進行分塊處理的,會經常出現最後一段數據長度不足的場景,這時就需要填充數據長度到加密演算法對應的數據塊大小。
主要的填充演算法有填充 NUL("0") 和 PKCS7,Mcrypt 默認使用的 NUL("0") 填充演算法,當前已不被推薦,OpenSSL 則默認模式使用 PKCS7 對數據進行填充並對加密後的數據進行了 base64encode 編碼,所以建議開發中使用 PKCS7 對待加密數據進行填充,已保證通用性(alipay sdk 中雖然使用了 Mcrypt 加密簇,但使用 PKCS7 演算法對數據進行了填充,這樣在一定程度上親和了 OpenSSL 加密演算法)。
Mcrypt 的默認填充演算法。NUL 即為 Ascii 表的編號為 0 的元素,即空元素,轉移字元是 " ",PHP 的 pack 打包函數在 'a' 模式下就是以 NUL 字元對內容進行填充的,當然,使用 " " 手動拼接也是可以的。
OpenSSL的默認填充演算法。下面我們給出 PKCS7 填充演算法 PHP 的實現:
默認使用 NUL(" ") 自動對待加密數據進行填充以對齊加密演算法數據塊長度。
獲取 mcrypt 支持的演算法,這里我們只關注 AES 演算法。
注意:mcrypt 雖然支持 AES 三種演算法,但除 MCRYPT_RIJNDAEL_128 外, MCRYPT_RIJNDAEL_192/256 並未遵循 AES-192/256 標准進行加解密的演算法,即如果你同其他系統通信(java/.net),使用 MCRYPT_RIJNDAEL_192/256 可能無法被其他嚴格按照 AES-192/256 標準的系統正確的數據解密。官方文檔頁面中也有人在 User Contributed Notes 中提及。這里給出如何使用 mcrpyt 做標注的 AES-128/192/256 加解密
即演算法統一使用 MCRYPT_RIJNDAEL_128 ,並通過 key 的位數 來選定是以何種 AES 標准做的加密,iv 是建議添加且建議固定為16位(OpenSSL的 AES加密 iv 始終為 16 位,便於統一對齊),mode 選用的 CBC 模式。
mcrypt 在對數據進行加密處理時,如果發現數據長度與使用的加密演算法的數據塊長度未對齊,則會自動使用 " " 對待加密數據進行填充,但 " " 填充模式已不再被推薦,為了與其他系統有更好的兼容性,建議大家手動對數據進行 PKCS7 填充。
openssl 簇加密方法更為簡單明確,mcrypt 還要將加密演算法分為 cipher + mode 去指定,openssl 則只需要直接指定 method 為 AES-128-CBC,AES-192-CBC,AES-256-CBC 即可。且提供了三種數據處理模式,即 默認模式 0 / OPENSSL_RAW_DATA / OPENSSL_ZERO_PADDING 。
openssl 默認的數據填充方式是 PKCS7,為兼容 mcrpty 也提供處理 "0" 填充的數據的模式,具體為下:
options 參數即為重要,它是兼容 mcrpty 演算法的關鍵:
options = 0 : 默認模式,自動對明文進行 pkcs7 padding,且數據做 base64 編碼處理。
options = 1 : OPENSSL_RAW_DATA,自動對明文進行 pkcs7 padding, 且數據未經 base64 編碼處理。
options = 2 : OPENSSL_ZERO_PADDING,要求待加密的數據長度已按 "0" 填充與加密演算法數據塊長度對齊,即同 mcrpty 默認填充的方式一致,且對數據做 base64 編碼處理。注意,此模式下 openssl 要求待加密數據已按 "0" 填充好,其並不會自動幫你填充數據,如果未填充對齊,則會報錯。
故可以得出 mcrpty簇 與 openssl簇 的兼容條件如下:
建議將源碼復制到本地運行,根據運行結果更好理解。
1.二者使用的何種填充演算法。
2.二者對數據是否有 base64 編碼要求。
3.mcrypt 需固定使用 MCRYPT_RIJNDAEL_128,並通過調整 key 的長度 16, 24,32 來實現 ase-128/192/256 加密演算法。
Ⅱ PHP的aes加解密演算法
1. php的aes演算法,加密時會存在空格,0,\0等方式進行補長,所以解密後需要進行trim操作,才能得到原數據串
2. aes加密後進行base64_encode,但是解密時,直接用aes進行解密,不需要先base64_decode.【這個操作很騷氣】
function _decryptData($data,$password, $iv){
$decryptData=openssl_decrypt($data, 'aes-128-cbc', $password, OPENSSL_ZERO_PADDING, $iv);
$data =json_decode(trim($decryptData), true);
return $data;
}
function encryptData($data, $password, $iv){
$data = json_encode($data);//$data是一個數組,如果是字元串,請忽略此句.
$result = base64_encode(openssl_encrypt($data, 'aes-128-cbc', $password, OPENSSL_RAW_DATA, $iv));
return $result;
}
Ⅲ OpenSSL詳解
OpenSSL初接觸的人恐怕最難的在於先理解各種概念
公鑰/私鑰/簽名/驗證簽名/加密/解密/非對稱加密
我們一般的加密是用一個密碼加密文件,然後解密也用同樣的密碼.這很好理解,這個是對稱加密.而有些加密時,加密用的一個密碼,而解密用另外一組密碼,這個叫非對稱加密,意思就是加密解密的密碼不一樣.初次接觸的人恐怕無論如何都理解不了.其實這是數學上的一個素數積求因子的原理的應用,如果你一定要搞懂,網路有大把大把的資料可以看,其結果就是用這一組密鑰中的一個來加密數據,可以用另一個解開.是的沒錯,公鑰和私鑰都可以用來加密數據,相反用另一個解開,公鑰加密數據,然後私鑰解密的情況被稱為加密解密,私鑰加密數據,公鑰解密一般被稱為簽名和驗證簽名.
因為公鑰加密的數據只有它相對應的私鑰可以解開,所以你可以把公鑰給人和人,讓他加密他想要傳送給你的數據,這個數據只有到了有私鑰的你這里,才可以解開成有用的數據,其他人就是得到了,也看懂內容.同理,如果你用你的私鑰對數據進行簽名,那這個數據就只有配對的公鑰可以解開,有這個私鑰的只有你,所以如果配對的公鑰解開了數據,就說明這數據是你發的,相反,則不是.這個被稱為簽名.
實際應用中,一般都是和對方交換公鑰,然後你要發給對方的數據,用他的公鑰加密,他得到後用他的私鑰解密,他要發給你的數據,用你的公鑰加密,你得到後用你的私鑰解密,這樣最大程度保證了安全性.
RSA/DSA/SHA/MD5
非對稱加密的演算法有很多,比較著名的有RSA/DSA ,不同的是RSA可以用於加/解密,也可以用於簽名驗簽,DSA則只能用於簽名.至於SHA則是一種和md5相同的演算法,它不是用於加密解密或者簽名的,它被稱為摘要演算法.就是通過一種演算法,依據數據內容生成一種固定長度的摘要,這串摘要值與原數據存在對應關系,就是原數據會生成這個摘要,但是,這個摘要是不能還原成原數據的,嗯....,正常情況下是這樣的,這個演算法起的作用就是,如果你把原數據修改一點點,那麼生成的摘要都會不同,傳輸過程中把原數據給你再給你一個摘要,你把得到的原數據同樣做一次摘要演算法,與給你的摘要相比較就可以知道這個數據有沒有在傳輸過程中被修改了.
實際應用過程中,因為需要加密的數據可能會很大,進行加密費時費力,所以一般都會把原數據先進行摘要,然後對這個摘要值進行加密,將原數據的明文和加密後的摘要值一起傳給你.這樣你解開加密後的摘要值,再和你得到的數據進行的摘要值對應一下就可以知道數據有沒有被修改了,而且,因為私鑰只有你有,只有你能解密摘要值,所以別人就算把原數據做了修改,然後生成一個假的摘要給你也是不行的,你這邊用密鑰也根本解不開.
CA/PEM/DER/X509/PKCS
一般的公鑰不會用明文傳輸給別人的,正常情況下都會生成一個文件,這個文件就是公鑰文件,然後這個文件可以交給其他人用於加密,但是傳輸過程中如果有人惡意破壞,將你的公鑰換成了他的公鑰,然後得到公鑰的一方加密數據,不是他就可以用他自己的密鑰解密看到數據了嗎,為了解決這個問題,需要一個公證方來做這個事,任何人都可以找它來確認公鑰是誰發的.這就是CA,CA確認公鑰的原理也很簡單,它將它自己的公鑰發布給所有人,然後一個想要發布自己公鑰的人可以將自己的公鑰和一些身份信息發給CA,CA用自己的密鑰進行加密,這里也可以稱為簽名.然後這個包含了你的公鑰和你的信息的文件就可以稱為證書文件了.這樣一來所有得到一些公鑰文件的人,通過CA的公鑰解密了文件,如果正常解密那麼機密後裡面的信息一定是真的,因為加密方只可能是CA,其他人沒它的密鑰啊.這樣你解開公鑰文件,看看裡面的信息就知道這個是不是那個你需要用來加密的公鑰了.
實際應用中,一般人都不會找CA去簽名,因為那是收錢的,所以可以自己做一個自簽名的證書文件,就是自己生成一對密鑰,然後再用自己生成的另外一對密鑰對這對密鑰進行簽名,這個只用於真正需要簽名證書的人,普通的加密解密數據,直接用公鑰和私鑰來做就可以了.
密鑰文件的格式用OpenSSL生成的就只有PEM和DER兩種格式,PEM的是將密鑰用base64編碼表示出來的,直接打開你能看到一串的英文字母,DER格式是二進制的密鑰文件,直接打開,你可以看到........你什麼也看不懂!.X509是通用的證書文件格式定義.pkcs的一系列標準是指定的存放密鑰的文件標准,你只要知道PEM DER X509 PKCS這幾種格式是可以互相轉化的.
== End http://www.cnblogs.com/phpinfo/archive/2013/08/09/3246376.html ==
為了方便理解,我畫了一個圖,如下:
使用 openssl 生成證書(含openssl詳解)
一、openssl 簡介
openssl 是目前最流行的 SSL 密碼庫工具,其提供了一個通用、健壯、功能完備的工具套件,用以支持SSL/TLS 協議的實現。
官網: https://www.openssl.org/source/
構成部分
密碼演算法庫
密鑰和證書封裝管理功能
SSL通信API介面
用途
建立 RSA、DH、DSA key 參數
建立 X.509 證書、證書簽名請求(CSR)和CRLs(證書回收列表)
計算消息摘要
使用各種 Cipher加密/解密
SSL/TLS 客戶端以及伺服器的測試
處理S/MIME 或者加密郵件
二、RSA密鑰操作
默認情況下,openssl 輸出格式為 PKCS#1-PEM
生成RSA私鑰(無加密)
openssl genrsa -out rsa_private.key 2048
生成RSA公鑰
openssl rsa -in rsa_private.key -pubout -out rsa_public.key
生成RSA私鑰(使用aes256加密)
openssl genrsa -aes256 -passout pass:111111 -out rsa_aes_private.key 2048
其中 passout 代替shell 進行密碼輸入,否則會提示輸入密碼;
生成加密後的內容如:
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,
Base64 Encoded
Data-----END RSA PRIVATE KEY-----
此時若生成公鑰,需要提供密碼
openssl rsa -in rsa_aes_private.key -passin pass:111111 -pubout -out rsa_public.key
其中 passout 代替shell 進行密碼輸入,否則會提示輸入密碼;
轉換命令
私鑰轉非加密
openssl rsa -in rsa_aes_private.key -passin pass:111111 -out rsa_private.key
私鑰轉加密
openssl rsa -in rsa_private.key -aes256 -passout pass:111111 -out rsa_aes_private.key
私鑰PEM轉DER
openssl rsa -in rsa_private.key -outform der-out rsa_aes_private.der
-inform和-outform 參數制定輸入輸出格式,由der轉pem格式同理
查看私鑰明細
openssl rsa -in rsa_private.key -noout -text
使用-pubin參數可查看公鑰明細
私鑰PKCS#1轉PKCS#8
openssl pkcs8 -topk8 -in rsa_private.key -passout pass:111111 -out pkcs8_private.key
其中-passout指定了密碼,輸出的pkcs8格式密鑰為加密形式,pkcs8默認採用des3 加密演算法,內容如下:
-----BEGIN ENCRYPTED PRIVATE KEY-----
Base64 Encoded Data
-----END ENCRYPTED PRIVATE KEY-----
使用-nocrypt參數可以輸出無加密的pkcs8密鑰,如下:
-----BEGIN PRIVATE KEY-----
Base64 Encoded Data
-----END PRIVATE KEY-----
三、生成CA自簽名證書和RSA私鑰(測試場景步驟)
測試場景步驟1:生成 RSA 私鑰和自簽名證書:
openssl req -newkey rsa:2048 -nodes -keyout rsa_private.key -x509 -days 36500 -out cert.crt
注釋:
操作步驟如下:提示填寫過程中如果想刪除填寫的內容,用ctrl+Backspace刪除前面的字元
[root@szxelab01-web-100 cert]# openssl req -newkey rsa:2048 -nodes -keyout rsa_private.key -x509 -days 36500 -out cert.crt
Generating a 2048 bit RSA private key
.............+++
........................+++
writing new private key to 'rsa_private.key'
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:GuangDong
Locality Name (eg, city) [Default City]:ShenZhen
Organization Name (eg, company) [Default Company Ltd]:SunFoBank
Organizational Unit Name (eg, section) []:IT Dept
Common Name (eg, your name or your server's hostname) []:sunfobank.com
Email Address [] :[email protected]
[root@szxjdwins01-web-27 cert]# ll
total 8
-rw-r--r--. 1 root root 1452 Jun 22 14:29 cert.crt
-rw-r--r--. 1 root root 1708 Jun 22 14:29 rsa_private.key
openssl req -newkey rsa:2048 -nodes -keyout rsa_private.key -x509 -days 36500 -out cert.crt -subj "/C=CN/ST=GuangDong/L=ShenZhen/O=SunFoBank/OU=IT Dept/CN= sunfobank.com/[email protected] "
openssl req -new -x509 -days 36500 -key rsa_private.key -out cert.crt
四、生成伺服器簽名請求文件及CA 簽名頒發伺服器證書()
server.key建議不要加密碼,如果加密碼,重啟nginx的時候每次都需要密碼才可以啟動nginx影響效率。
nginx配置只需要server.key和server.crt兩個文件。
openssl genrsa -aes256 -passout pass:111111 -out server.key 2048
openssl req -new -key server.key -out server.csr
[root@szxjdwins01-web-27 cert]# openssl genrsa -aes256 -passout pass:111111 -out server.key 2048
Generating RSA private key, 2048 bit long molus
............................+++
.......+++
e is 65537 (0x10001)
[root@szxjdwins01-web-27 cert]# openssl genrsa -aes256 -out server.key 2048
Generating RSA private key, 2048 bit long molus
.............................................+++
........................................................+++
e is 65537 (0x10001)
Enter pass phrase for server.key: 111111手動輸入密碼
Verifying - Enter pass phrase for server.key: 111111手動輸入密碼
[root@szxelab01-web-27 cert]# openssl req -new -key server.key -out server.csr
Enter pass phrase for server.key:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:GuangDong
Locality Name (eg, city) [Default City]:ShenZhen
Organization Name (eg, company) [Default Company Ltd]:SunFoBank
Organizational Unit Name (eg, section) []:IT Dept
Common Name (eg, your name or your server's hostname) []:sunfobank.com
Email Address [] :[email protected]
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []: 不輸入密碼
An optional company name []: 不輸入密碼
此後輸入密碼、server證書信息完成,也可以命令行指定各類參數
openssl req -new -key server.key -passin pass:111111 -out server.csr -subj "/C=CN/ST=GuangDong/L=ShenZhen/O=SunFoBank/OU=IT Dept/CN= sunfobank.com/[email protected] "
*** 此時生成的 csr簽名請求文件可提交至 CA進行簽發 ***
cat server.csr
-----BEGIN CERTIFICATE REQUEST-----
Base64EncodedData
-----END CERTIFICATE REQUEST-----
openssl req -noout -text -in server.csr
openssl x509 -req -days 365000 -in server.csr -CA cert.crt -CAkey rsa_private.key -passin pass:111111 -CAcreateserial -out server.crt
[root@szxelab01-web-27 cert]# openssl x509 -req -days 365000 -in server.csr -CA cert.crt -CAkey rsa_private.key -passin pass:111111 -CAcreateserial -out server.crt
Signature ok
subject=/C=CN/ST=GuangDong/L=ShenZhen/O=SunFoBank/OU=IT Dept/CN= sunfobank.com/[email protected]
Getting CA Private Key
其中 CAxxx 選項用於指定CA 參數輸入
[root@szxelab01-web-27 cert]# ll
total 24
-rw-r--r--. 1 root root 1452 Jun 22 14:29 cert.crt
-rw-r--r--. 1 root root 17 Jun 22 15:07 cert.srl
-rw-r--r--. 1 root root 1708 Jun 22 14:29 rsa_private.key
-rw-r--r--. 1 root root 1334 Jun 22 15:07 server.crt
-rw-r--r--. 1 root root 1070 Jun 22 15:04 server.csr
-rw-r--r--. 1 root root 1766 Jun 22 14:54 server.key
此時對nginx任何操作,都需要提示輸入server.key的密碼才可以執行。
[root@szxelab01-web-27 nginx]# /application/nginx/sbin/nginx -t
Enter PEM pass phrase: 輸入密碼111111
nginx: the configuration file /application/nginx-1.12.2//conf/nginx.conf syntax is ok
為例不輸入密碼,需要把加密server.key轉換成不加密的server.key
[root@szxelab01-web-27 cert]# openssl rsa -in server.key -passin pass:111111 -out server.key
writing RSA key
此時nginx操作就不提示輸入密碼了:
[root@szxelab01-web-27 cert]# /application/nginx/sbin/nginx -t
nginx: the configuration file /application/nginx-1.12.2//conf/nginx.conf syntax is ok
nginx: configuration file /application/nginx-1.12.2//conf/nginx.conf test is successful
證書位置:
[root@szxelab01-web-27 cert]# pwd
/application/nginx/cert
[root@szxelab01-web-27 cert]# ll
total 24
-rw-r--r--. 1 root root 1452 Jun 22 14:29 cert.crt
-rw-r--r--. 1 root root 17 Jun 22 15:07 cert.srl
-rw-r--r--. 1 root root 1708 Jun 22 14:29 rsa_private.key
-rw-r--r--. 1 root root 1334 Jun 22 15:07 server.crt
-rw-r--r--. 1 root root 1070 Jun 22 15:04 server.csr
-rw-r--r--. 1 root root 1679 Jun 22 15:19 server.key
至此測試場景私有證書配置完成
五、證書查看及轉換
查看證書細節
openssl x509 -in cert.crt -noout -text
轉換證書編碼格式
openssl x509 -in cert.cer -inform DER -outform PEM -out cert.pem
合成 pkcs#12 證書(含私鑰)
** 將 pem 證書和私鑰轉 pkcs#12 證書 **
openssl pkcs12 -export -in server.crt -inkey server.key -passin pass:111111 -password pass:111111 -out server.p12
其中-export指導出pkcs#12 證書,-inkey 指定了私鑰文件,-passin 為私鑰(文件)密碼(nodes為無加密),-password 指定 p12文件的密碼(導入導出)
** 將 pem 證書和私鑰/CA 證書 合成pkcs#12 證書**
openssl pkcs12 -export -in server.crt -inkey server.key -passin pass:111111 \ -chain -CAfile ca.crt -password pass:111111 -out server-all.p12
其中-chain指示同時添加證書鏈,-CAfile 指定了CA證書,導出的p12文件將包含多個證書。(其他選項:-name可用於指定server證書別名;-caname用於指定ca證書別名)
** pcks#12 提取PEM文件(含私鑰) **
openssl pkcs12 -in server.p12 -password pass:111111 -passout pass:111111 -out out/server.pem
其中-password 指定 p12文件的密碼(導入導出),-passout指輸出私鑰的加密密碼(nodes為無加密)
導出的文件為pem格式,同時包含證書和私鑰(pkcs#8):
Bag Attributes
localKeyID: 97 DD 46 3D 1E 91 EF 01 3B 2E 4A 75 81 4F 11 A6 E7 1F 79 40 subject=/C=CN/ST=GD/L=SZ/O=vihoo/OU=dev/CN= vihoo.com/[email protected]
issuer=/C=CN/ST=GD/L=SZ/O=viroot/OU=dev/CN= viroot.com/[email protected] CERTIFICATE-----MIIDazCCAlMCCQCIOlA9/
1LpQCA+2B6dn4scZwaCD-----END CERTIFICATE-----Bag Attributes
localKeyID: 97 DD 46 3D 1E 91 EF 01 3B 2E 4A 75 81 4F 11 A6 E7 1F 79 40 Key Attributes: <No Attributes>
-----BEGIN ENCRYPTED PRIVATE KEY-----/6rAc1YaPRNf
K9ZLHbyBTKVaxehjxzJHHw==
-----END ENCRYPTED PRIVATE KEY-----
僅提取私鑰
openssl pkcs12 -in server.p12 -password pass:111111 -passout pass:111111 -nocerts -out out/key.pem
僅提取證書(所有證書)
openssl pkcs12 -in server.p12 -password pass:111111 -nokeys -out out/key.pem
僅提取ca證書
openssl pkcs12 -in server-all.p12 -password pass:111111 -nokeys -cacerts -out out/cacert.pem
僅提取server證書
openssl pkcs12 -in server-all.p12 -password pass:111111 -nokeys -clcerts -out out/cert.pem
六、openssl 命令參考
Ⅳ PHP 加密:AES & RSA
最近兩年一直從事與金融相關項目的開發與維護。但是,關於 PHP 加密解密的最佳實踐,網上沒有人給出一個完美的總結。恰逢最近看了《圖解密碼技術》一書,對 PHP 加解密有了更深刻的認識。
為了避免各位看枯燥的文字理論,開篇我就把總結給出:
一、對稱加密
對稱加密的特點是加解密速度快,加密後的密文強度目前還沒有硬解的可能性。但是,在未來隨著計算機性能的提升有可能會出現被破解的可能性。
對稱加密的缺點也很明顯。對稱加密的加密過程與解密過程使用的是同一把密鑰。一旦泄漏密鑰,加密就失去了任何意義。
根據《圖解密碼技術》一書的推薦,對稱加密目前推薦使用 AES。在 PHP 當中要實現 AES 加解密,是使用 openssl 擴展來實現。所以,請確保你的 PHP 已經開啟了 openssl 擴展。
可以通過如下方式檢測:
或者如下方式檢測:
AES 的加密模式屬於分組密碼模式。所謂分組密碼,是加密時把明文按照固定的長度分組,然後再進行加密。當然,細節之處很很多不同。AES 分組模式有多種:ECB、CBC、CFB、OFB、CTR 五種分組模式。目前優先推薦使用 CBC 模式。
如果使用 CBC 模式,那麼在加密的時候,就需要一個前置的加密向量 IV。當初博主在使用 AES 來加密的時候,就很奇怪一個對稱加密為何要這個向量。因為,在博主寒冰的潛意識里,對稱加密只需要一個密鑰就 Ok 了。沒想到 AES 加密還有多種模式,而這個 CBC 模式恰恰就需要一個這樣的向量值。關於這個向量大家可以在網上查閱相關的資料。這個東西非常重要,也非常好理解。
關於 PHP AES 加解密會用到的相關方法:
AES 支持三種強度:128、192、256。128 位的強度最低,但是,加密解密速度較快。256 位強度最高,但是,加密解密速度最低。所以,大家根據自己系統的重要程度選擇使用對應強度。通常普通的金融項目使用 192 位完整夠用了。頂級的就用 256 位。其他的就用 128 位吧。
二、非對稱加密
非對稱加密是指公鑰加密私鑰解密,私鑰加密公鑰解密的演算法。非對稱加密的演算法有很多。《圖解密碼技術》一書推薦使用 RSA 演算法。它使用起來也非常簡單。
要使用 RSA 演算法。首先,我們必須生成一對公鑰私鑰。其實生成公鑰私鑰很簡單。
在 Linux 系統,直接使用如下命令生成:
此命令會生 ~/.ssh/ 目錄下生成兩個文件:
id_rsa 是私鑰, is_rsa.pub 是公鑰。
關於 PHP RSA 加解密會用到的相關方法:
以上就是關於在 PHP 項目開發中,我們使用的加密解密演算法的一個總結。博主寒冰在總結過程中難免會有不足之處,還請大家指正!謝謝!
Ⅳ 為什麼OPENSSL在C++/PHP下AES加密解密結果不一致
結果應該是一樣的,你查看下是多少位加密 128位和256位肯定是不一樣的。
其次 看看 AES_KEY 是否一致,仔細比較下兩者的 key和iv,如果這兩個不一樣,那麼結果肯定不一樣。尤其是iv,PHP封裝的是否默認有了個iv。
你要比較AES_KEY 的key和iv中每個char,不僅僅是輸出的字元串。不能應為有\0字元串的結尾標志而忽略。
如果這些一致,加密加過肯定是一致的。
Ⅵ OpenSSL之AES用法
密碼學中的高級加密標准(Advanced Encryption Standard,AES),又稱Rijndael加密法,是美國聯邦政府採用的一種分組加密標准。這個標准用來替代原先的DES(Data Encryption Standard),已經被多方分析且廣為全世界所使用。經過五年的甄選流程,高級加密標准由美國國家標准與技術研究院 (NIST)於2001年11月26日發布於FIPS PUB 197,並在2002年5月26日成為有效的標准。2006年,高級加密標准已然成為對稱密鑰加密中最流行的演算法之一 。
本文假設你已經安裝好了OpenSSL,並且持有一份1.1.1的源碼。
AES相關的頭文件在aes.h中、源文件在crypto/aes目錄中。
這里定義了加密和解密的類型。
這里定義了分組最大輪數和塊大小。
這個結構定義了AES的密鑰上下文。相關欄位含義:
rd_key —— 每輪的子密鑰。
rounds —— 加解密輪數。
在1.1.1中,大多數的數據結構已經不再向使用者開放,從封裝的角度來看,這是更合理的。如果你在頭文件中找不到結構定義,不妨去源碼中搜一搜。
int AES_set_encrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key);
設置加密密鑰,bits必須是128、192、256,否則會失敗。
成功返回0,失敗返回負數。
int AES_set_decrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key);
設置解密密鑰,bits必須是128、192、256,否則會失敗。
成功返回0,失敗返回負數。
void AES_encrypt(const unsigned char *in, unsigned char *out, const AES_KEY *key);
執行AES ECB分組加密。
void AES_decrypt(const unsigned char *in, unsigned char *out, const AES_KEY *key);
執行AES ECB分組解密。
void AES_ecb_encrypt(const unsigned char *in, unsigned char *out, const AES_KEY *key, const int enc);
執行AES ECB分組加解密。其實是AES_encrypt()和AES_decrypt()的簡單封裝。
其內部實現為:
void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, size_t length,
const AES_KEY *key, unsigned char *ivec, const int enc);
執行AES CBC分組加解密。
ivec為16位元組的向量,每次加解密都需要,首次為初使向量,後續為前一次的密文分組。
其內部實現為:
下面這個例子演示了AES ECB分組加解密的基本用法。在實際項目中,需要程序員加以封裝,並充分考慮數據填充問題。
輸出:
AES_set_encrypt_key ret:0
AES_set_decrypt_key ret:0
Ⅶ 對於加密的總結(AES,RSA)
跟第三方聯調的時候會碰到各種加密演算法,所以總結一下。
AES不是將拿到的明文一次性加密,而是分組加密,就是先將明文切分成長度相等的塊,每塊大小128bit,再對每一小塊進行加密。那麼問題就來了,並不是所有的原始明文串能被等分成128bit,例如原串大小200bit,那麼第二個塊只有72bit,所以就需要對第二個塊進行填充處理,讓第二個塊的大小達到128bit。常見的填充模式有
不進行填充,要求原始加密串大小必須是128bit的整數倍;
假設塊大小8位元組,如果這個塊跟8位元組還差n個位元組,那麼就在原始塊填充n,直到滿8位元組。例:塊{1,2,3},跟8位元組差了5個位元組,那麼補全後的結果{1,2,3,5,5,5,5,5}後面是五個5,塊{1,2,3,..7}跟8位元組差了1個位元組,那麼補全後就是{1,2,3,...,7,1},就是補了一個1。
如果恰好8位元組又選擇了PKCS5Padding填充方式呢?塊{1,2,3...8}填充後變成{1,2,3...8,8...8},原串後面被補了8個8,這樣做的原因是方便解密,只需要看最後一位就能算出原塊的大小是多少。
跟PKCS5Padding的填充方式一樣,不同的是,PKCS5Padding只是對8位元組的進行填充,PKCS7Padding可以對1~256位元組大小的block進行填充。openssl里aes的默認填充方式就是PKCS7Padding
AES有多種加密模式,包括:ECB,CBC,CTR,OCF,CFB,最常見的還是ECB和CBC模式。
最簡單的一種加密模式,每個塊進行獨立加密,塊與塊之間加密互不影響,這樣就能並行,效率高。
雖然這樣加密很簡單,但是不安全,如果兩個塊的明文一模一樣,那麼加密出來的東西也一模一樣。
openssl的相關函數:
CBC模式中引入了一個新的概念,初始向量iv。iv的作用就是為了防止同樣的明文塊被加密成同樣的內容。原理是第一個明文塊跟初始向量做異或後加密,第二個塊跟第一個密文塊做異或再加密,依次類推,避免了同樣的塊被加密成同樣的內容。
openssl相關函數:
敲黑板!! 所以跟第三方對接的時候,如果對面說他們用aes加密,務必對他們發起靈魂三問:
簽名的作用是讓接受方驗證你傳過去的數據沒有被篡改;加密的作用是保證數據不被竊取。
原理:你有一個需要被驗簽的原串A。
步驟一:選擇hash演算法將A進行hash得到hash_a;
步驟二:將hash_a進行加密,得到加密值encrypt_a;
步驟三:將原串A和加密的encrypt_a發給第三方,第三方進行驗簽。第三方先解密encrypt_a,得到一個hash值hash_a1,然後對原串A使用同樣的hash演算法進行hash,得到的即為加密前的hash_a,如果hash_a = hash_a1, 那麼驗簽成功。
rsa使用私鑰對信息加密來做簽名,使用公鑰解密去驗簽。
openssl相關函數:
注意:兩個函數中的m,是原串hash後的值,type表示生成m的演算法,例如NID_sha256表示使用sha256對原串進行的hash,返回1為簽名成功或者驗簽成功,-1位為失敗。
再次敲黑板!! 所以如果第三方說使用rsa驗簽,要讓對方告知他們的hash演算法。
首先明確,私鑰加密不等於簽名。加密的時候,使用使用公鑰加密,第三方使用你的私鑰進行解密。
openssl里公鑰加密函數為RSA_public_encrypt,私鑰解密函數為RSA_private_decrypt,具體的可以自己去查看下官方文檔。
rsa也涉及到了填充方式,所以對接的時候也要問清楚
在使用公鑰進行加密時,會發現每次加密出的結果都不一樣,但使用私鑰加密時,每次的結果都一樣,網上查了一圈,說是因為填充方式的原因。
官方文檔說明:
那麼為什麼一定要使用私鑰做簽名,公鑰做加密,而不是公鑰做簽名,私鑰做加密呢?
舉個栗子: