本章講解下openssl相關概念和加解密算法的基本使用
這篇文章講述以下幾點
- 什么是OpenSSL
- 基本功能
- 密鑰、證書的編碼格式和后綴名
- 對稱加密的基本使用
- 生成公私鑰對
- 非對稱加密的基本使用
1. 什么是OpenSSL
OpenSSL 是一個安全套接字層密碼庫,囊括主要的密碼算法、常用的密鑰和證書封裝管理功能及SSL協議,并提供豐富的應用程序供測試或其它目的使用。
2. 基本功能
openssl是一個開源程序的套件、這個套件有三個部分組成:一是libcryto,這是一個具有通用功能的加密庫,里面實現了眾多的加密庫;二是libssl,這個是實現ssl機制的,它是用于實現TLS/SSL的功能;三是openssl,是個多功能命令行工具,它可以實現加密解密,甚至還可以當CA來用,可以讓你創建證書、吊銷證書。
為了做個更簡單的區分,我分成下面3種,可能你看著會親切一些
- 加解密庫(本章只討論加解密)
- SSL協議實現
- 一些經過封裝,方便你使用加解密和SSL的工具
****密鑰、證書的編碼格式和后綴名
目前有以下
兩種編碼
格式.
-
PEM - Privacy Enhanced Mail
打開看文本格式,以"-----BEGIN-----"開頭, "-----END-----"結尾,內容是Base64編碼,查看PEM格式的信息可以用命令
openssl rsa -in my.pem -text -noout
Unix服務器偏向于使用這種編碼格式. -
DER - Distinguished Encoding Rules
打開看是二進制格式,不可讀,查看DER格式的信息可以用命令
openssl rsa -in my.der -inform der -text -noout
Java和Windows服務器偏向于使用這種編碼格式.
我們平時見到的多種后綴名,都是
語義化
的后綴,在生成密鑰的時候,比如我們私鑰的后綴名可以寫.pem
.key
,都是可以的,以下幾種為常用后綴
CRT - CRT應該是certificate的三個字母,其實還是證書的意思,常見于Unix系統,有可能是PEM編碼,也有可能是DER編碼,大多數應該是PEM編碼,相信你已經知道怎么辨別.
CER - 還是certificate,還是證書,常見于Windows系統,同樣的,可能是PEM編碼,也可能是DER編碼,大多數應該是DER編碼.
KEY - 通常用來存放一個公鑰或者私鑰,并非X.509證書,編碼同樣的,可能是PEM,也可能是DER.
查看KEY的辦法:
openssl rsa -in mykey.key -text -noout
如果是DER格式的話,同理應該這樣了:
openssl rsa -in mykey.key -text -noout -inform der
CSR - Certificate Signing Request,即證書簽名請求,這個并不是證書,而是向權威證書頒發機構獲得簽名證書的申請,其核心內容是一個公鑰(當然還附帶了一些別的信息),在生成這個申請的時候,同時也會生成一個私鑰,私鑰要自己保管好,查看的辦法:
openssl req -noout -text -in my.csr
(如果是DER格式的話照舊加上-inform der
,這里不寫了)
3. 常用加解密算法使用
我們重點討論如何使用
1.對稱加密
我們需要用到 openssl enc
命令,先看下幫助文檔
$ openssl enc -h
:<<!
-in <file> 輸入文件
-out <file> 輸出文件
-pass <arg> 密碼
-S 鹽,用于加鹽加密,請避免人為輸入,下面討論
-e encrypt 加密操作
-d decrypt 解密操作
-a/-base64 base64 encode/decode, depending on encryption flag 是否將結果base64編碼
-k 已被-pass參數取代
-kfile 已被-pass參數取代
-md 指定密鑰生成的摘要算法 默認MD5
-K/-iv 加密所需的key和iv向量,由輸入的-pass生成
-[pP] print the iv/key (then exit if -P) 是否需要在控制臺輸出生成的 key和iv向量
-bufsize <n> 讀寫文件的I/O緩存,一般不需要指定
-engine e 指定三方加密設備,沒有環境,暫不實驗
Cipher Types 以下是部分算法,我們可以選擇用哪種算法加密
-aes-128-cbc -aes-128-cbc-hmac-sha1 -aes-128-cfb
-aes-128-cfb1 -aes-128-cfb8 -aes-128-ctr
-aes-128-ecb -aes-128-gcm -aes-128-ofb
…………
!
使用,默認從控制臺輸入密碼,如果不指定加密算法,是不會進行加密的,也不會報錯,比如我們不指定算法,只指定base64格式輸出,就相當于只做了base64編碼而已
/*對文件進行base64編碼*/
openssl enc -base64 -in plain.txt -out base64.txt
/*對base64格式文件進行解密*/
openssl enc -base64 -d -in base64.txt -out plain2.txt
/*使用diff命令查看可知解碼前后明文一樣*/
diff plain.txt plain2.txt
不同輸入密碼的方式
/*命令行輸入,密碼123456*/
openssl enc -aes-128-cbc -in plain.txt -out out.txt -pass pass:123456
/*文件輸入,密碼123456*/
echo 123456 > passwd.txt
openssl enc -aes-128-cbc -in plain.txt -out out.txt -pass file:passwd.txt
/*環境變量輸入,密碼123456*/
passwd=123456
export passwd
openssl enc -aes-128-cbc -in plain.txt -out out.txt -pass env:passwd
/*從文件描述輸入*/
openssl enc -aes-128-cbc -in plain.txt -out out.txt -pass fd:1
/*從標準輸入輸入*/
openssl enc -aes-128-cbc -in plain.txt -out out.txt -pass stdin
- 對稱加密的使用中,雖然我們輸入了-pass,指定了密碼,但是本質是采用key和iv向量進行加密的,我們輸入的-pass,會轉換成key和iv
- 為了增強安全性,在把用戶密碼轉換成 key / iv 的時候需要使用鹽值,默認鹽值隨機生成。使用-S參數,則鹽值由用戶指定。也可指用-nosalt指定不使用鹽值,但降低了安全性,不推薦使用。
- 因為本質是采用 key / iv 加密,所以我們可以直接用 key / iv 解密或者加密
手動指定Key和IV值,指定key / iv 后,-pass參數不起作用
/*手動指定key和iv值*/
$ openssl enc -aes-128-cbc -in plain.txt -out encrypt.txt -K 1223 -iv f123 -p
salt=0B00000000000000
key=12230000000000000000000000000000
iv =F1230000000000000000000000000000
/*指定pass密碼,不起作用,注意Key和IV值是16進制*/
$ openssl enc -aes-128-cbc -in plain.txt -out encrypt.txt -K 1223 -iv f123 -p -pass pass:123456
salt=F502F4B8DE62E0E5
key=12230000000000000000000000000000
iv =F1230000000000000000000000000000
2.公私鑰對的生成(這里演示RSA算法相關)
首先我們需要用到 openssl genrsa
命令,先看下幫助文檔,這是一個簡易的命令,為了方便我們生成自己的私鑰
$ openssl genrsa -h
/*
usage: genrsa [args] [numbits]
-des 生成的私鑰采用DES算法加密
-des3 生成的私鑰采用DES3算法加密 (168 bit key)
-seed encrypt PEM output with cbc seed
-aes128, -aes192, -aes256
以上幾個都是對稱加密算法的指定,因為我們長期會把私鑰加密,避免明文存放
-out file 私鑰輸出位置
-passout arg 輸出文件的密碼,如果我們指定了對稱加密算法,也可以不帶此參數,會有命令行提示你輸入密碼
*/
我們生成一個私鑰
~ ? openssl genrsa -out my.key -des3
/*
Generating RSA private key, 512 bit long modulus
...++++++++++++
.++++++++++++
e is 65537 (0x10001)
# 因為指定了des3算法,并且沒指定密碼,所以會要求我輸入密碼
Enter pass phrase for my.key:
Verifying - Enter pass phrase for my.key:
------------------------------------------------------------
*/
~ ? cat my.key
/*
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,21A9C0CD76DFBF27
i1h8ZmZxOZxDHigtXs0tAIWNs7THoN4t00F4xmYP7gDEU8vwWXltZisUqMJ2KHgZ
ME70Tm2XvhEAwu3OLhCaV6Url+DJ/G6sMFpnvkebrW51Ndph87ZCRdhaOrXN2WVg
+/KNRv2dMh4c98zgoJqYiN6qqdY9Sztj0DMtjn2f9k7mU8l2oN5bmlO6dy+mX2ZB
Qaupx9PV2DZH7Yd5tcKLudCa44lJ9cJscnvIyzLhDHcrGytCsTeHNeVMx9gefd0p
DzMBruiNhmXSe8a067OT5mWMi7++4WOYYWfIj2bat/pxsBNo0gOxqcuV0G1RFEDA
uX0vk1ma3+hB01p51bPCjc2HF/nvs2s/YeYgJR/E3zuxQGMvi6G0uxVY10i5xhtb
mIXi1J5RSoVcj2gMXD3GasGANNG3hdTWC+g6hfq+DczmGl8uR9lXwg==
-----END RSA PRIVATE KEY-----
*/
我們可以指定私鑰長度,命令最后就是指定私鑰長度,默認512bit
openssl genrsa -out my.key -des3 1024
另外我們需要用到 openssl rsa
命令,我們會用它生成公鑰,先看下幫助文檔
$ openssl rsa -h
/*
-inform arg 輸入文件編碼格式,只有pem和der兩種
-outform arg 輸出文件編碼格式,只有pem和der兩種
-in arg input file 輸入文件
-sgckey Use IIS SGC key format
-passin arg 如果輸入文件被對稱加密過,需要指定輸入文件的密碼
-out arg 輸出文件位置
-passout arg 如果輸出文件也需要被對稱加密,需要指定輸出文件的密碼
-des 對輸出結果采用對稱加密 des算法
-des3 對輸出結果采用對稱加密 des3算法
-seed
-aes128, -aes192, -aes256
以上幾個都是對稱加密算法的指定,生成私鑰的時候一般會用到,我們不讓私鑰明文保存
-text 以明文形式輸出各個參數值
-noout 不輸出密鑰到任何文件
-modulus 輸出模數值
-check 檢查輸入密鑰的正確性和一致性
-pubin 指定輸入文件是公鑰
-pubout 指定輸出文件是公鑰
-engine e 指定三方加密庫或者硬件
*/
我們利用剛才生成的私鑰my.key
,以此生成一個公鑰
~ ? openssl rsa -in my.key -pubout -out my_pub.key
/*
Enter pass phrase for my.key: # 因為私鑰有密碼,我們需要輸入
writing RSA key
------------------------------------------------------------
*/
~ ? cat my_pub.key
/*
-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAN4QWx/qPoOllcE8ZcR5zBzrSVFh7NXY
4SJHB8+IM3Wv2aYi7F3GlZjpt6EP3vdd4x4cJnuPFnZ5mZ5wFPQ8xD0CAwEAAQ==
-----END PUBLIC KEY-----
*/
openssl rsa 命令的功能還有很多
- rsa 添加 和 去除 密鑰的對稱加密
/*生成不加密的RSA密鑰*/
$ openssl genrsa -out RSA.pem
Generating RSA private key, 512 bit long modulus
..............++++++++++++
.....++++++++++++
e is 65537 (0x10001)
/*為RSA密鑰增加口令保護*/
$ openssl rsa -in RSA.pem -des3 -passout pass:123456 -out E_RSA.pem
/*為RSA密鑰去除口令保護*/
$ openssl rsa -in E_RSA.pem -passin pass:123456 -out P_RSA.pem
/*比較原始后的RSA密鑰和去除口令后的RSA密鑰,是一樣*/
$ diff RSA.pem P_RSA.pem
2、修改密鑰的保護口令和算法
/*生成RSA密鑰*/
$ openssl genrsa -des3 -passout pass:123456 -out RSA.pem
Generating RSA private key, 512 bit long modulus
..................++++++++++++
......................++++++++++++
e is 65537 (0x10001)
/*修改加密算法為aes128,口令是123456*/
$ openssl rsa -in RSA.pem -passin pass:123456 -aes128 -passout pass:123456 -out E_RSA.pem
3、查看密鑰對中的各個參數
$ openssl rsa -in RSA.pem -des -passin pass:123456 -text -noout
4、提取密鑰中的公鑰并打印模數值
/*提取公鑰,用pubout參數指定輸出為公鑰*/
$ openssl rsa -in RSA.pem -passin pass:123456 -pubout -out pub.pem
/*打印公鑰中模數值*/
$ openssl rsa -in pub.pem -pubin -modulus -noout
Modulus=C35E0B54041D78466EAE7DE67C1DA4D26575BC1608CE6A199012E11D10ED36E2F7C651D4D8B40D93691D901E2CF4E21687E912B77DCCE069373A7F6585E946EF
5、轉換密鑰的格式
/*把pem格式轉化成der格式,使用outform指定der格式*/
$ openssl rsa -in RSA.pem -passin pass:123456 -des -passout pass:123456 -outform der -out rsa.der
/*把der格式轉化成pem格式,使用inform指定der格式*/
$ openssl rsa -in rsa.der -inform der -passin pass:123456 -out rsa.pem
3.利用已有的公私鑰對 ,進行非對稱加解密
我們這里需要用到 openssl rsautl
命令
注意:無論是使用公鑰加密還是私鑰加密,RSA每次能夠加密的數據長度不能超過RSA密鑰長度,并且根據具體的補齊方式不同輸入的加密數據最大長度也不一樣,而輸出長度則總是跟RSA密鑰長度相等。RSA不同的補齊方法對應的輸入輸入長度如下表
數據補齊方式 | 輸入數據長度 | 輸出數據長度 | 參數字符串 |
---|---|---|---|
PKCS#1 v1.5 | 少于(密鑰長度-11)字節 | 同密鑰長度 | -pkcs |
PKCS#1 OAEP | 少于(密鑰長度-11)字節 | 同密鑰長度 | -oaep |
PKCS#1 for SSLv23 | 少于(密鑰長度-11)字節 | 同密鑰長度 | -ssl |
不使用補齊 | 同密鑰長度 | 同密鑰長度 | -raw |
使用rsautl進行加密和解密操作,我們還是先看一下幫助文檔
$ openssl rsautl -h
Usage: rsautl [options]
-in file input file //輸入文件
-out file output file //輸出文件
-inkey file input key //輸入的密鑰
-keyform arg private key format - default PEM //指定密鑰格式
-pubin input is an RSA public //指定輸入的是RSA公鑰
-certin input is a certificate carrying an RSA public key //指定輸入的是證書文件
-ssl use SSL v2 padding //使用SSLv23的填充方式
-raw use no padding //不進行填充
-pkcs use PKCS#1 v1.5 padding (default) //使用V1.5的填充方式
-oaep use PKCS#1 OAEP //使用OAEP的填充方式
-sign sign with private key //使用私鑰做簽名
-verify verify with public key //使用公鑰認證簽名
-encrypt encrypt with public key //使用公鑰加密
-decrypt decrypt with private key //使用私鑰解密
-hexdump hex dump output //以16進制dump輸出
-engine e use engine e, possibly a hardware device. //指定三方庫或者硬件設備
-passin arg pass phrase source //指定輸入的密碼
openssl rsautl 基本的加解密使用
/*生成RSA密鑰*/
$ openssl genrsa -des3 -passout pass:123456 -out RSA.pem
Generating RSA private key, 512 bit long modulus
............++++++++++++
...++++++++++++
e is 65537 (0x10001)
/*提取公鑰*/
$ openssl rsa -in RSA.pem -passin pass:123456 -pubout -out pub.pem
/*使用RSA作為密鑰進行加密,實際上使用其中的公鑰進行加密*/
$ openssl rsautl -encrypt -in plain.txt -inkey RSA.pem -passin pass:123456 -out enc.txt
/*使用RSA作為密鑰進行解密,實際上使用其中的私鑰進行解密*/
$ openssl rsautl -decrypt -in enc.txt -inkey RSA.pem -passin pass:123456 -out replain.txt
/*比較原始文件和解密后文件*/
$ diff plain.txt replain.txt
/*使用公鑰進行加密*/
$ openssl rsautl -encrypt -in plain.txt -inkey pub.pem -pubin -out enc1.txt
/*私鑰進行解密*/
$ openssl rsautl -decrypt -in enc1.txt -inkey RSA.pem -passin pass:123456 -out replain1.txt
/*比較原始文件和解密后文件*/
$ diff plain.txt replain1.txt
簽名與驗證操作
/*提取PCKS8格式的私鑰*/
$ openssl pkcs8 -topk8 -in RSA.pem -passin pass:123456 -out pri.pem -nocrypt
/*使用RSA密鑰進行簽名,實際上使用私鑰進行加密*/
$ openssl rsautl -sign -in plain.txt -inkey RSA.pem -passin pass:123456 -out sign.txt
/*使用RSA密鑰進行驗證,實際上使用公鑰進行解密*/
$ openssl rsautl -verify -in sign.txt -inkey RSA.pem -passin pass:123456 -out replain.txt
/*對比原始文件和簽名解密后的文件*/
$ diff plain.txt replain.txt
/*使用私鑰進行簽名*/
$ openssl rsautl -sign -in plain.txt -inkey pri.pem -out sign1.txt
/*使用公鑰進行驗證*/
$ openssl rsautl -verify -in sign1.txt -inkey pub.pem -pubin -out replain1.txt
/*對比原始文件和簽名解密后的文件*/
$ cat plain replain1.txt