目錄
- ASN.1 - 數據結構描述語言
- 文件編碼格式
- DER編碼格式
- PEM編碼格式
- 證書、密碼學Key格式標準
- X.509標準
- PKCS(公鑰加密標準)系列(
PKCS#1
、PKCS#8、PKCS#12)
- 常見的證書標準格式(PEM編碼)
- X.509 Certificate
- X.509 Certificate Subject Public Key Info
- PKCS #1 Private Key
- PKCS #1 Public Key
- PKCS #8 Unencrypted Private Key
- PKCS #8 Encrypted Private Key
- 常見的證書文件后綴(.pem .der .cer .crt .pfx .p12 .jks)
- Private Key操作命令:生成、轉換
- Public Key操作命令:從PKCS #1/#8提取、從X.509證書提取、轉換
# 前言
PKI標準可以分為第一代標準和第二代標準。
第一代PKI標準主要包括美國RSA公司的公鑰加密標準(Public Key Cryptography Standards,PKCS)系列
、國際電信聯盟的ITU-T X.509
、IETF組織的公鑰基礎設施X.509(Public Key Infrastructure X.509,PKIX)標準系列、無線應用協議(Wireless Application Protocol ,WAP)論壇的無線公鑰基礎設施(Wireless Public Key Infrastructure,WPKI)標準等。第一代PKI標準主要是基于抽象語法符號(Abstract Syntax Notation One,ASN.1)編碼的
,實現比較困難,這也在一定程度上影響了標準的推廣。
第二代PKI標準,略。
CA中心普遍采用的規范是X.509系列和PKCS系列。
# ASN.1 - 數據結構描述語言
引用自Wiki:
ASN.1 is a standard interface description language for defining data structures that can be serialized and deserialized in a cross-platform way.
也就是說ASN.1是一種用來定義數據結構的接口描述語言,它不是二進制,也不是文件格式,看下面的例子你就會明白了:
FooQuestion ::= SEQUENCE {
trackingNumber INTEGER,
question IA5String
}
這段代碼定義了FooQuestion的數據結構,下面是FooQuestion這個數據接口的某個具體的數據:
myQuestion FooQuestion ::= SEQUENCE {
trackingNumber 5,
question "Anybody there?"
}
ASN.1用在很多地方比如下面要講的X.509和PKCS group of cryptography standards。
# 文件編碼格式
## DER編碼格式
引用自Wiki:
ASN.1 is closely associated with a set of encoding rules that specify how to represent a data structure as a series of bytes
意思是ASN.1有一套關聯的編碼規則,這些編碼規則用來規定如何用二進制來表示數據結構,DER是其中一種。
把上面的FooQuestion的例子用DER編碼則是(16進制):
30 13 02 01 05 16 0e 41 6e 79 62 6f 64 79 20 74 68 65 72 65 3f
翻譯過來就是:
30 — type tag indicating SEQUENCE
13 — length in octets of value that follows
02 — type tag indicating INTEGER
01 — length in octets of value that follows
05 — value (5)
16 — type tag indicating IA5String
(IA5 means the full 7-bit ISO 646 set, including variants,
but is generally US-ASCII)
0e — length in octets of value that follows
41 6e 79 62 6f 64 79 20 74 68 65 72 65 3f — value ("Anybody there?")
看到這里你應該對DER編碼格式有一個比較好的認識了。
## PEM編碼格式
引用自Wiki:
Privacy-Enhanced Mail (PEM) is a de facto file format for storing and sending cryptographic keys, certificates, and other data, based on a set of 1993 IETF standards defining "privacy-enhanced mail."
PEM是一個用來存儲和發送密碼學key、證書和其他數據的文件格式的事實標準。許多使用ASN.1的密碼學標準(比如X.509和PKCS)都使用DER編碼,而DER編碼的內容是二進制的,不適合與郵件傳輸(早期Email不能發送附件),因此使用PEM把二進制內容轉換成ASCII碼。文件內容的格式像下面這樣:
-----BEGIN label-----
BASE64Encoded
-----END label-----
label用來區分內容到底是什么類型,下面會講。
和PEM相關的RFC有很多,與本文內容相關的則是RFC7468,這里面規定了很多label,不過要注意不是所有label都會有對應的RFC或Specification,這些label只是一種約定俗成。
PEM實際上就是把DER編碼的文件的二進制內容用base64編碼一下,然后加上-----BEGIN label-----
這樣的頭和-----END label-----
這樣的尾,中間則是DER文件的Base64編碼。
我們可以通過下面的方法驗證這個結論,先生成一個RSA Private Key,編碼格式是PEM格式:
openssl genrsa -out key.pem
查看一下文件內容,可以看到label是RSA PRIVATE KEY
:
-----BEGIN RSA PRIVATE KEY-----
BASE64Encoded
-----END RSA PRIVATE KEY-----
然后我們把PEM格式轉換成DER格式:
openssl rsa -in key.pem -outform der -out key.der
如果你這個時候看一下文件內容會發現都是二進制。然后我們把DER文件的內容Base64一下,會看到內容和PEM文件一樣(忽略頭尾和換行):
base64 -i key.der -o key.der.base64
在-----BEGIN-----與-----END-----之間內容的頂部,有時使用一些頭定義對信息進行封裝,這些頭信息格式如下(不一定都需要,可選的):
Proc-Type,4:ENCRYPTED
DEK-Info: cipher-name, ivec
其中,第一個頭信息標注了該文件是否進行了加密,該頭信息可能的值包括ENCRYPTED(信息已經加密和簽名)、MIC-ONLY(信息經過數字簽名但沒有加密)、MIC-CLEAR(信息經過數字簽名但是沒有加密、也沒有進行編碼,可使用非PEM格式閱讀)以及CLEAR(信息沒有簽名和加密并且沒有進行編碼,該項好象是openssl自身的擴展,但是并沒有真正實現);
第二個頭信息標注了加密的算法以及使用的ivec參量,ivec其實在這兒提供的應該是一個隨機產生的數據序列,與塊加密算法中要使用到的初始化變量(IV)不一樣。
# 證書、密碼學Key格式標準
上面講到的PEM是對證書、密碼學Key文件的一種編碼方式,下面舉例這些證書、密碼學Key文件格式:
## X.509標準
引用自Wiki :
In cryptography, X.509 is a standard defining the format of public key certificates. X.509 certificates are used in many Internet protocols, including TLS/SSL, which is the basis for HTTPS, the secure protocol for browsing the web.
X.509是一個Public Key Certificates的格式標準,TLS/SSL使用它,TLS/SSL是HTTPS的基礎所以HTTPS也使用它。而所謂Public Key Certificates又被稱為Digital Certificate 或 Identity Certificate。
An X.509 certificate contains a public key and an identity (a hostname, or an organization, or an individual), and is either signed by a certificate authority or self-signed.
一個X.509 Certificate包含一個Public Key和一個身份信息,它要么是被CA簽發的要么是自簽發的。
下面這種張圖就是一個X.509 Certificate:事實上X.509 Certificate這個名詞通常指代的是IETF的PKIX Certificate和CRL Profile,見RFC5280。所以當你看到PKIX Certificate字樣的時候可以認為就是X.509 Certificate。
## PKCS(公鑰加密標準)系列
引用自Wiki:
In cryptography, PKCS stands for "Public Key Cryptography Standards"
前面提到的X.509是定義Public Key Certificates的格式的標準,看上去和PKCS有點像,但實際上不同,PKCS是Public Key密碼學標準。此外Public-Key Cryptography雖然名字看上去只涉及Public Key,實際上也涉及Priviate Key,因此PKCS也涉及Private Key。
PKCS一共有15個標準編號從1到15,這里只挑講PKCS #1、PKCS #8、PKCS #12。
### PKCS #1
PKCS #1,RSA Cryptography Standard,定義了RSA Public Key和Private Key數學屬性和格式,詳見RFC8017。
詳細的介紹了RSA算法的計算過程,包括:key的產生,key的結構,對數字加密/解密/簽名/驗證簽名的過程、對應算法。
-
key
. 關于key,分別記錄了private和public的詳細結構,以及存儲哪些內容。并且在附錄里面推薦了ASN.1 Syntax中的存儲結構。注:沒有規定實際的物理文件存儲結構,比如pem等。 -
加密/解密
詳細描述了加密/解密的算法。包括,首先針對字符串,怎么轉化成數字,之后,怎么根據數字進行加密。 這里可以看出,標準中沒有對超長字符串處理的說明。而轉化出的字符串的長度,全都是key的模長度k。
在字符串轉化成數字過程中,需要增加填充字符,所以,分成了兩種不同算法:RSAES-OAEP(現有標準) RSAES-PKCS1-v1_5(兼容過去標準)。在實際加密過程中,就只有一種算法了 - 無論在加密還是簽名過程中,都會進行hash操作,hash操作沒有自己定義,而是從附錄中可以選擇需要的hash方式。
-
PKCS1填充方式
:在進行RSA運算時需要將源數據D轉化為Encryption block(EB)。其中pkcs1padding V1.5的填充模式按照以下方式進行:
格式:加密塊EB = 00 + 塊類型BT + 填充字符PS + 00 + 數據D //以下描述均以十六進制字符串來描述
說明
EB:為轉化后Hex進制表示的數據塊,長度為128個字節(密鑰1024位的情況下)
00:為了確保塊轉換為整數的時候 小于模數
BT(Block Type):
用一個字節表示,在目前的版本上,有三個值00 01 02。如果使用公鑰操作,BT永遠為02,如果用私鑰操作則可能為00或01。
塊類型為00,數據開頭必須不能是00,因為填充的也是00,將無法解析。
塊類型為01或02,塊可以被準確解析,因為不會是00來填充。
如果是私鑰操作,且明文數據是以00字節開頭,那么建議把BT的值設置為01,否則,BT為00,PS為00,D開頭為00,數據無法被分隔開
PS(Padding String):
為填充位,PS由k-3-D這么多個字節構成,k表示密鑰的字節長度,如果我們用1024bit的RSA密鑰,這個長度就是1024/8=128,D表示明文數據D的字節長度
對于BT為00的,則這些字節全部為00
對于BT為01的,這些值全部為FF
對于BT為02的,這些字節的值隨機產生但不能是0字節(非00)
填充長度至少為8個字節
00:用于分開 PS 和 D
D:數據原文(HEX十六進制)
PS至少為8個字節,所以D <= k-11
當我們使用128字節密鑰對數據進行加密時,明文數據的長度不能超過過128-11=117字節
當RSA要加密數據大于 k-11字節時怎么辦呢?把明文數據按照D的最大長度分塊然后逐塊加密,最后把密文拼起來就行。
注意:加密塊EB長度 = RSA密鑰key的長度。比如密鑰1024bit,即128字節,加密塊也會被填充為128字節
示例:下面的數據需要填充74個FF才夠128個字節。
簽名的時候:加密塊 = 00 + 01 + FF(74個) + 00 + ">3031300d060960864801650304020105000420b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9(51字節)
此外還有其他標準里定義的填充方式,比如PKCS5Padding、PKCS7Padding,不再贅述
### PKCS #8
PKCS #8,Private-Key Information Syntax Standard,詳細的描述了私鑰的存儲格式。用于加密、非加密地存儲Private Certificate Keypairs(不限于RSA),詳見RFC5858。
### PKCS #12
PKCS #12定義了通常用來存儲Private Keys和Public Key Certificates(例如前面提到的X.509)的文件格式,使用基于密碼的對稱密鑰進行保護。注意上述Private Keys和Public Key Certificates是復數形式,這意味著PKCS #12文件實際上是一個Keystore,PKCS #12文件可以被用做Java Key Store(JKS),詳見RFC7292。
如果你用自己的CA所簽發了一個證書,運行下列命令可以生成PKCS #12 keystore:
openssl pkcs12 -export \
-in <cert> \
-inkey <private-key> \
-name my-cert \
-caname my-ca-root \
-CAfile <ca-cert> \
-chain
-out <pkcs-file>
PKCS #12一般不導出PEM編碼格式。
# 常見的證書標準格式(PEM編碼)
當你不知道你的PEM文件內容是什么格式的可以根據下面查詢。
## X.509 Certificate
RFC7468 - Textual Encoding of Certificates
-----BEGIN CERTIFICATE-----
BASE64Encoded
-----END CERTIFICATE-----
## X.509 Certificate Subject Public Key Info
RFC7468 - Textual Encoding of Subject Public Key Info
-----BEGIN PUBLIC KEY-----
BASE64Encoded
-----END PUBLIC KEY-----
## PKCS #1 Private Key
沒有RFC或權威Specification,該格式有時候被稱為traditional format、SSLeay format(見SO)
-----BEGIN RSA PRIVATE KEY-----
BASE64Encoded
-----END RSA PRIVATE KEY-----
## PKCS #1 Public Key
同上沒有RFC或權威Specification
-----BEGIN RSA PUBLIC KEY-----
BASE64Encoded
-----END RSA PUBLIC KEY-----
## PKCS #8 Unencrypted Private Key
RFC7468 - One Asymmetric Key and the Textual Encoding of PKCS #8 Private Key Info
-----BEGIN PRIVATE KEY-----
BASE64Encoded
-----END PRIVATE KEY-----
## PKCS #8 Encrypted Private Key
RFC7468 - Textual Encoding of PKCS #8 Encrypted Private Key Info
-----BEGIN ENCRYPTED PRIVATE KEY-----
BASE64Encoded
-----END ENCRYPTED PRIVATE KEY-----
# 常見證書后綴
作為文件形式存在的證書一般有這幾種后綴:(證書中包含公鑰,以及公鑰頒發機構、版本號、算法等信息,可以以X.509為例看一下證書內容)
1.帶有私鑰的證書:(一般都有密碼保護,使用的是DER編碼)
-
.pfx
常用于Windows上的 IIS服務器 -
.p12
常用于MAC OS、iOS中(PKCS#12由PFX進化而來的用于交換公共的和私有的對象的標準格式) -
.jks
Java Key Storage,這是Java的專利,JAVA的專屬格式,一般用于 Tomcat 服務器。
2.不帶私鑰的證書:
-
.cer/crt
編碼方式不一定,可能是DER也可能是PEM -
.pem
都是PEM編碼格式 -
.der
都是DER編碼格式 -
.p7b
以樹狀展示證書鏈(certificate chain),同時也支持單個證書,不含私鑰
3.補充
- .der文件一般只放證書,
不含私鑰
- .pem文件中可以放證書或者私鑰,或者兩者都有,pem如果只含私鑰的話,一般用
.key
擴展名,而且可以有密碼保護 - .csr - Certificate Signing Request,即證書簽名請求,這個并不是證書,而是向權威證書頒發機構獲得簽名證書的申請,其核心內容是一個公鑰(當然還附帶了一些別的信息),在生成這個申請的時候,同時也會生成一個私鑰key,私鑰要自己保管好。做過iOS APP的朋友都應該知道是怎么向蘋果申請開發者證書的吧.
可以使用命令行工具、代碼、在線網站等實現不同后綴格式、不同證書標準之間的轉換,比如這個網站http://www.metools.info/
# Private Key操作命令
## 生成
生成PKCS #1格式的RSA Private Key
openssl genrsa -out private-key.p1.pem 2048
## 轉換
PKCS #1 -> Unencrypted PKCS #8
openssl pkcs8 -topk8 -in private-key.p1.pem -out private-key.p8.pem -nocrypt
PKCS #1 -> Encrypted PKCS #8
openssl pkcs8 -topk8 -in private-key.p1.pem -out private-key.p8.pem
過程中會讓你輸入密碼,你至少得輸入4位,所以PKCS #8相比PKCS #1更安全。
PKCS #8 -> PKCS #1
openssl rsa -in private-key.p8.pem -out private-key.p1.pem
如果這個PKCS #8是加密的,那么你得輸入密碼。
# Public Key操作命令
## 從PKCS #1/#8提取
提取指的是從Private Key中提取Public Key,openssl rsa
同時支持PKCS #1和PKCS #8的RSA Private Key,唯一的區別是如果PKCS #8是加密的,會要求你輸入密碼。
提取X.509格式RSA Public Key
openssl rsa -in private-key.pem -pubout -out public-key.x509.pem
提取PKCS #1格式RSA Public Key
openssl rsa -in private-key.pem -out public-key.p1.pem -RSAPublicKey_out
## 從X.509證書提取
openssl x509 -in cert.pem -pubkey -noout > public-key.x509.pem
## 轉換
X.509 RSA Public Key -> PKCS #1 RSA Public Key
openssl rsa -pubin -in public-key.x509.pem -RSAPublicKey_out -out public-key.p1.pem
PKCS #1 RSA Public Key -> X.509 RSA Public Key
openssl rsa -RSAPublicKey_in -in public-key.p1.pem -pubout -out public-key.x509.pem
# 參考鏈接
- 很多的內容都來自這篇博客,增加了一些內容,并按照個人習慣整理了一下