做者: Angus.Fenying <i.am.x.fenying@gmail.com>算法
日期: 2016-11-10 10:35 PM服務器
本文介紹 OpenSSL 命令行進行 RSA 加密、解密、簽名、驗證的操做,但不涉及 RSA 算法原理解析,若有興趣,能夠閱讀阮一峯的《RSA算法原理》。若是你只想知道 RSA 是什麼,那麼你只要記住:RSA 是一種加密算法,使用兩個密鑰,一個叫公鑰,一個 叫私鑰,使用公鑰加密的密文只有使用私鑰才能夠解密,反之亦然。加密
因爲 OpenSSL 建立密鑰文件是隨機生成的,所以有必要爲之提供一份隨機數據源。命令行
能夠用 openssl 的 rand
命令建立一個 64MB 的隨機文件,保存爲文件 randSrc.bin。3d
openssl rand -out ./randSrc.bin 67108864
還可使用 -base64
或者 -hex
兩個參數之一指定輸出格式爲 BASE64 或者 HEX。code
小貼士:md5
- 根據目前的廣泛需求,應當使用 AES256 爲加密標準。
- 一般 RSA 私鑰文件命名爲 name.pem,公鑰文件名爲 name_pub.pem。
- OpenSSL 生成的密鑰文件默認是 PEM 格式的。
openssl genrsa \ -rand randSrc.bin \ -aes256 \ -out rsa.pem 2048
這個命令的意思是:ssl
genrsa
: 生成 RSA 密鑰文件。-aes256
: 使用 AES256 算法加密生成的密鑰文件, 所以你須要輸入加密用的密碼(並記住)。-rand randSrc.bin
使用文件 randSrc.bin 做爲隨機數來源。-out rsa.pem
: 將生成的密鑰文件保存爲 rsa.pem
。2048
: 生成 2048 Bits 的 RSA 密鑰文件。2048 Bits 是指 RSA 算法裏 N 的長度,而不是說公鑰和私鑰都是 2048 Bits。get
生成文件樣例:openssl
-----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: AES-256-CBC,A6F8DD9D1D994363907C278CDF9B644C MfsPjXK6izOmmzMseG3M2aBKque20ao13+oFg/JdJtlCK0Vb11hLqq8h/ICnY3lI z1xuBKiXVykl521YumeTS6C+WtSkb71cy1u6lHBwdO44tWxklEqcl1sLYIWKyNaB VgKmS4BhfuUq8XlSt3LnuQT/BJWPP7+GUUaZG6/stMWAx+XBg9mMahxGCqo7aRcz ............... nLGRE27iklwGgSagaK40FDiSe69HcIBkHCUQYaYtXQzHNgjoQRkcotzo+vxM7XcL 5y5DHwA8IFwt9c5f14lxZ2cXF9p54JA3UMy+T7XggINDgBFuOPR/U3eBS2x6hHW6 eoGX+khw+s5atpNJaF4s6n2ViDseQsW+b8NfSdlX0j5f5xSasFcYgFsDZtBy/FqZ -----END RSA PRIVATE KEY-----
這是一個密鑰文件,而不是一個純粹的私鑰文件,它包含了完整的密鑰信息,便是說,裏面 既有公鑰也有私鑰。可是隻能把它當成私鑰使用,公鑰部分請參考 Section 3。
從 Section 1 生成的密鑰文件中提取沒有密碼的密鑰文件,以便給 Nginx 等服務器使用。
openssl rsa -in rsa.pem -out rsa_pri.pem
從 Section 1 生成的私鑰文件中提取公鑰文件。
openssl rsa -in rsa.pem -pubout -out rsa_pub.pem
RSA 加密和解密都是使用 openssl 的 rsautl 命令。
在 Section 3 裏面生成了公鑰文件 rsa_pub.pem,下面使用它進行加密。 (先生成個數據文件)
echo 1234567890 > test.txt md5sum test.txt openssl rsautl \ -encrypt \ -in test.txt \ -out test.secret \ -pubin \ -inkey rsa_pub.pem
能夠看到源文件 test.txt 的 MD5 值爲 7c12772809c1c0c3deda6103b10fdfa0
。
源文件 test.txt 只有 10 個字節大小,可是加密結果文件 test.secret* 竟然有 256 字節(2048 位長),這是由於 RSA 密鑰是 2048 位長度的,而 RSA 加解密算法的操做 單位必須和密鑰長度一致。因此加密結果的大小必定和密鑰長度的一致。因此加密長度必須小於
密鑰長度 - 填充長度
。關於填充數據,默認使用
PKCS#1 v1.5
填充格式。
在 Section 1 裏面生成了密鑰文件 rsa.pem,下面使用它進行加密。
openssl rsautl -decrypt -in test.secret -out test.raw -inkey rsa.pem md5sum test.raw
這裏使用的是帶密碼的密鑰文件,所以須要輸入 AES 密碼先把密鑰文件解密出來。若是使用的是 Section 2 中生成的無密碼密鑰文件,那麼則不須要輸入密碼了。
能夠看到解密出來的文件 test.raw 的 MD5 值爲 7c12772809c1c0c3deda6103b10fdfa0
。
加解密是使用公鑰加密,私鑰解密,由於公鑰是公開的,私鑰是保密的。簽名和校驗則反過來, 私鑰簽名,公鑰校驗。
這裏假設你要發送消息給你朋友,消息存在文件 test.txt 中,你已經擁有了你朋友的 公鑰文件 fr_pub.pem。
那麼先用他的公鑰對文件進行加密:
openssl rsautl -encrypt -in test.txt -out test.msg -pubin -inkey fr_pub.pem
獲得了加密後的文件 test.msg,下面使用你本身的私鑰進行簽名。
先用 SHA256 算法生成文件的哈希校驗碼:
openssl sha256 -out test.hash test.msg
獲得了哈希校驗文件 test.hash,內容以下:
SHA256(test.msg)= ************************
下面使用 RSA 私鑰對其進行簽名:
openssl pkeyutl \ -sign \ -in test.hash \ -out test.sign \ -inkey rsa_raw.pem
或者
openssl rsautl \ -sign \ -in test.hash \ -out test.sign \ -inkey rsa_raw.pem
RSA 私鑰簽名的實質是:使用 RSA 私鑰對數據的哈希校驗碼進行加密,這樣就能夠用 對應的 RSA 公鑰解密獲得數據的哈希校驗碼。
獲得了簽名後的文件 test.sign,將它和 test.msg、rsa_pub.pem 一塊兒發給你的朋友。
如今你的朋友收到了你發給他的三個文件,分別是:公鑰、簽名、消息。如今他怎麼肯定 消息是發給他的呢?固然是使用公鑰校驗啦。
首先,他一樣使用 openssl 生成文件 test.msg 的哈希校驗碼。
openssl sha256 -out test.hash test.msg
而後使用你的公鑰文件對其進行校驗:
openssl pkeyutl \ -verify \ -in test.hash \ -sigfile test.sign \ -pubin \ -inkey rsa_pub.pem
若是校驗經過,則會看到提示:Signature Verified Successfully
。
而後他再使用他的私鑰解密 test.msg 文件便可獲得你發給他的消息了。
這裏不使用
openssl rsautl -verify
命令,由於rsautl
的-verify
指令 僅僅是將輸入的文件用公鑰解密,但不與計算出來的哈希校驗碼進行比較,不如 pkeyutl 的-verify
方便:openssl rsautl \ -verify \ -in test.sign \ -pubin \ -inkey rsa_pub.pem
前面說了,rsa.pem 裏面既包含私鑰又包含公鑰,這裏能夠小小地證實一下。 直接使用 rsa_raw.pem 文件進行簽名校驗。
openssl pkeyutl \ -verify \ -in test.hash \ -sigfile test.sign \ -pubin \ -inkey rsa_raw.pem如何,結果是否是同樣呢?
那麼,問題來了。若是傳輸過程被人攔截了怎麼辦?這就是下一篇文章的內容了。