最近豹储,在寫java讀取key的時候遇到了一個version的問題。不解淘这,就各種找資料剥扣,這里總結(jié)一下.
ANS.1編碼規(guī)則
openssl的數(shù)據(jù)編碼規(guī)則是基于ans.1:
ASN.1(=Abstract Syntax Notation One),是一種結(jié)構(gòu)化的描述語言铝穷,包括兩部分,數(shù)據(jù)描述語言和數(shù)據(jù)編碼規(guī)則钠怯。
- 數(shù)據(jù)描述語言標(biāo)準(zhǔn):語言標(biāo)準(zhǔn)允許用戶自定義的基本數(shù)據(jù)類型,并可以通過簡單的數(shù)據(jù)類型組成更復(fù)雜的數(shù)據(jù)類型曙聂。
- 數(shù)據(jù)編碼規(guī)則:這些編碼方法規(guī)定了將數(shù)字對象轉(zhuǎn)換成應(yīng)用程序能夠處理晦炊、保存、傳輸?shù)亩M(jìn)制形式的一組規(guī)則宁脊。
標(biāo)準(zhǔn)ASN.1編碼規(guī)則有規(guī)范編碼規(guī)則(CER断国,Canonical Encoding Rules)、唯一編碼規(guī)則(DER榆苞,Distinguished Encoding Rules)稳衬、壓縮編碼規(guī)則(PER,Packed Encoding Rules)和XML編碼規(guī)則(XER坐漏,XML Encoding Rules)薄疚。
所謂的規(guī)則碧信,就是數(shù)據(jù)流編解碼的方式。編碼:將數(shù)據(jù)結(jié)構(gòu)(可能是不同的输涕,異構(gòu)的)變成數(shù)據(jù)流音婶;解碼:其他應(yīng)用讀取解析,獲得相應(yīng)數(shù)據(jù)莱坎。
Step 1:數(shù)據(jù)格式定義
對于普通數(shù)據(jù)類型衣式,我們將數(shù)據(jù)直接轉(zhuǎn)化成數(shù)據(jù)流進(jìn)行傳輸即可;對于復(fù)雜數(shù)據(jù)格式檐什,需要引入一個數(shù)字對象的概念碴卧,通過將復(fù)雜數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)化成數(shù)據(jù)對象。
ASN.1的第一部分---數(shù)據(jù)描述語言標(biāo)準(zhǔn)乃正,這個標(biāo)準(zhǔn)定義了一些基本的數(shù)據(jù)類型住册,如果我們使用到復(fù)雜的數(shù)據(jù)結(jié)構(gòu),asn.1還允許通過簡單數(shù)據(jù)類型組成復(fù)雜的數(shù)據(jù)類型(x.509)瓮具。
Step 2:數(shù)據(jù)流轉(zhuǎn)化
數(shù)據(jù)傳輸需要將數(shù)據(jù)(結(jié)構(gòu)或者對象)轉(zhuǎn)化成數(shù)據(jù)流(二進(jìn)制流)進(jìn)行傳輸荧飞。
ASN.1的第二部分--編碼規(guī)則,編碼方法規(guī)定了將數(shù)字對象轉(zhuǎn)換成應(yīng)用程序能夠處理名党、保存叹阔、傳輸?shù)亩M(jìn)制形式的一組規(guī)則。
所以传睹,ASN.1標(biāo)準(zhǔn)就是規(guī)定了把數(shù)據(jù)轉(zhuǎn)化成數(shù)據(jù)對象耳幢,又規(guī)定數(shù)據(jù)對象編碼為二進(jìn)制流的方法。
openssl使用的是asn.1的der編碼規(guī)則欧啤,保證每個asn.1對象使用der編碼獲得的二進(jìn)制編碼是唯一的睛藻。
openssl使用pem作為基本的文件編碼格式,pem和der的關(guān)系如下圖所示邢隧,其中幾種加密環(huán)節(jié)是可選的:
從本質(zhì)上來說店印,openssl是pem編碼就是在der編碼的技術(shù)上進(jìn)行Base64編碼,然后添加一些頭尾信息組成府框,可以通過openssl指令對der和pem進(jìn)行格式轉(zhuǎn)換吱窝。
證書編碼格式
常見的證書編碼格式有三種X.509證書,PKCS#12證書和PKCS#7證書迫靖。
X.509證書
最常用的證書格式,它僅包含了公鑰信息而沒有私鑰信息兴使,一個openssl簽發(fā)經(jīng)過PEM編碼的X.509證書格式如下:
-----BEGIN CERTIFICATE-----
XXX
-----END CERTIFICATE-----
中間部分就是經(jīng)過PEM編碼的X509證書系宜。除了上述形式的頭尾格式,還可能出現(xiàn)以下兩種不同的標(biāo)識符发魄。
-----BEGIN X.509 CERTIFICATE----
XXX
-----END X.509 CERTIFICATE-----
或者
-----BEGIN TRUSTED CERTIFICATE-----
XXX
-----END TRUSTED CERTIFICATE-----
X.509證書文件的后綴名經(jīng)常是der盹牧,cer或者crt俩垃。openssl的指令x509提供了對X.509證書進(jìn)行格式轉(zhuǎn)換的方法。
PKCS#12證書
PKCS12證書可以包含一個或者多個證書汰寓,并且還可以包含證書對應(yīng)的私鑰口柳。openssl的pkcs12指令可以將X.509格式的證書和私鑰封裝成PKCS#12格式的證書,也可以將PKCS#12證書轉(zhuǎn)換成X.509證書有滑。
PKCS#12證書的后綴名通常是p12或者pdx跃闹。
PKCS#7證書:
PKCS#7可以封裝一個或者多個X.509證書或者PKCS#6證書,并且可以包含CRL信息毛好。PKCS#7證書中也不包含私鑰信息望艺。openssl提供了crl2pkcs7和pkcs7兩個指令來生成和處理PKCS#7文件,可以使用他們在X.509證書和PKCS#7證書之間進(jìn)行轉(zhuǎn)換和處理
PKCS#7證書的后綴名是p7b
密鑰編碼
openssl有多種形式的密鑰肌访,openssl提供PEM和DER兩種編碼方式對這些密鑰進(jìn)行編碼找默,并提供相關(guān)指令可以使用戶在這兩種格式之間進(jìn)行轉(zhuǎn)換。
openssl密鑰大致可以分為兩種吼驶,一種是可以公開的惩激,例如公鑰,一種是不能公開的蟹演,比對私鑰风钻。反映在編碼上,有的密鑰需要加密轨帜,有的密鑰就不需要加密魄咕。一個經(jīng)過加密的PEM編碼密鑰文件會在PEM文件中增加一些頭信息,表明密鑰的加密狀態(tài)蚌父,加密算法及初始化向量等信息
openssl指令提供了對密鑰加密的功能哮兰,并提供了多種可選的對稱加密算法,比如DES和DES3苟弛。當(dāng)對密鑰進(jìn)行加密的時候通常需要用戶輸入口令喝滞,這里的口令并非直接用來作為加密的密鑰,而是根據(jù)這個口令使用一系列HASH操作來生成一個用戶加密密鑰數(shù)據(jù)的密鑰膏秫。當(dāng)讀取這類密鑰的時候右遭,同樣需要輸入同樣的口令。
這里再詳細(xì)的說下DER和PEM缤削。
DER
DER就是密鑰的二進(jìn)制表述格式窘哈。
Distinguished Encoding Rules (DER)
is a binary serialization of ASN.1 format. It is often used for cryptographic data such as certificates, but has other uses.
PEM
PEM格式就是對DER編碼轉(zhuǎn)碼為base64字符格式。通過base64解碼可以還原DER格式亭敢。
A PEM file is plain text. It contain one or more objects, such as certificates or keys, which may not all be the same type. Each object is delimited by lines similar to “—–BEGIN …—–” and “—–END …—–”. Data that is not between such lines is ignored, and is sometimes used for comments, or for a human-readable dump of the encoded data.
Following the “BEGIN” and “END” keywords is a name (such as “CERTIFICATE”) that can be used as an identifier for the type of object.
The data between the delimiter lines starts with an optional email-like header section, followed by base64-encoded payload data. After decoding, the payload data is in DER format.
PEM 是明文格式滚婉,可以包含證書或者是密鑰;其內(nèi)容通常是以類似 “—–BEGIN …—–” 開頭 “—–END …—–” 為結(jié)尾的這樣的格式進(jìn)行描述的帅刀。
因為DER是純二進(jìn)制格式让腹,對人不友好远剩,所以一般都用PEM進(jìn)行存儲。這里主要介紹PEM格式的公私鑰骇窍。
公鑰PEM
PKCS #1
PKCS #1 標(biāo)準(zhǔn)是專門為 RSA 密鑰
進(jìn)行定義的瓜晤,其對應(yīng)的 PEM 文件格式如下,
-----BEGIN RSA PUBLIC KEY-----
BASE64 ENCODED DATA
-----END RSA PUBLIC KEY-----
上面的內(nèi)容 BASE64 ENCODED DATA 指的就是 ANS.1 的 DER 的 Base64 編碼腹纳。其ASN.1的格式為:
RSAPublicKey ::= SEQUENCE {
modulus INTEGER, -- n
publicExponent INTEGER -- e
}
各個filed的含義:
- modulus 是RSA的合數(shù)模n痢掠。
- publicExponent 是RSA公開冪e。
PKCS #8
PKCS#8 標(biāo)準(zhǔn)定義了一個密鑰格式的通用方案只估,它不僅僅為 RSA 所使用志群,同樣也可以被其它密鑰所使用。其對應(yīng)的PEM文件格式如下:
-----BEGIN PUBLIC KEY-----
BASE64 ENCODED DATA
-----END PUBLIC KEY-----
注意蛔钙,這里就沒有 RSA 字樣了锌云,因為 PKCS#8 是一個通用型的秘鑰格式方案;其中的 BASE64 ENCODED DATA 所標(biāo)注的內(nèi)容為 PEM 格式中對 DER 原始二進(jìn)制進(jìn)行的 BASE64 編碼:
PublicKeyInfo ::= SEQUENCE {
algorithm AlgorithmIdentifier,
PublicKey BIT STRING
}
AlgorithmIdentifier ::= SEQUENCE {
algorithm OBJECT IDENTIFIER,
parameters ANY DEFINED BY algorithm OPTIONAL
}
PKCS#8 雖然名字叫做 Private-Key Information Syntax Specification吁脱,但是實際上桑涎,可以看到,它同樣可以用作 Public Key 的格式定義兼贡;而 PKCS#8 是站在 PKCS#7 CMS 的基礎(chǔ)之上進(jìn)行編碼格式定義的攻冷。
私鑰PEM
PKCS #1
PKCS#1 是專門為 RSA 所涉及的,其對應(yīng)的 PEM 格式如下:
-----BEGIN RSA PRIVATE KEY-----
BASE64 ENCODED DATA
-----END RSA PRIVATE KEY-----
原始的 DER 格式結(jié)構(gòu)遍希,既是 ASN.1 的數(shù)據(jù)結(jié)構(gòu):
RSAPrivateKey ::= SEQUENCE {
version Version,
modulus INTEGER, -- n
publicExponent INTEGER, -- e
privateExponent INTEGER, -- d
prime1 INTEGER, -- p
prime2 INTEGER, -- q
exponent1 INTEGER, -- d mod (p-1)
exponent2 INTEGER, -- d mod (q-1)
coefficient INTEGER, -- (inverse of q) mod p
otherPrimeInfos OtherPrimeInfos OPTIONAL
}
其中各個字段的含義為:
- version 是版本號等曼,兩個素數(shù)為0,如果使用了多素數(shù)凿蒜,則版本號應(yīng)該是1禁谦。
Version ::= INTEGER { two-prime(0), multi(1) }
(CONSTRAINED BY {-- version must be multi if otherPrimeInfos present --}) - modulus 是RSA合數(shù)模n。
- publicExponent 是RSA的公開冪e废封。
- privateExponent 是RSA的私有冪d州泊。
- prime1 是n的素數(shù)因子p。
- prime2 是n的素數(shù)因子q漂洋。
- exponent1 等于d mod (p ? 1)遥皂。
- exponent2 等于d mod (q ? 1)。
- coefficient 是CRT系數(shù) q–1 mod p刽漂。
- otherPrimeInfos 按順序包含了其它素數(shù)r3, …, ru的信息演训。如果version是0 ,它應(yīng)該被忽略贝咙;而如果version是1,它應(yīng)該至少包含OtherPrimeInfo的一個實例眯娱。
PKCS #8
未加密
PEM格式:
-----BEGIN PRIVATE KEY-----
BASE64 ENCODED DATA
-----END PRIVATE KEY-----
對應(yīng)的DER:
PrivateKeyInfo ::= SEQUENCE {
version Version,
algorithm AlgorithmIdentifier,
PrivateKey BIT STRING
}
AlgorithmIdentifier ::= SEQUENCE {
algorithm OBJECT IDENTIFIER,
parameters ANY DEFINED BY algorithm OPTIONAL
}
加密
針對私鑰的內(nèi)容進(jìn)行加密。
PEM格式:
-----BEGIN ENCRYPTED PRIVATE KEY-----
BASE64 ENCODED DATA
-----END ENCRYPTED PRIVATE KEY-----
DER格式:
EncryptedPrivateKeyInfo ::= SEQUENCE {
encryptionAlgorithm EncryptionAlgorithmIdentifier,
encryptedData EncryptedData
}
EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
EncryptedData ::= OCTET STRING
openssl操作
生成私鑰
openssl有多種方法生成私鑰:
- genrsa生成RSA密鑰穿剖。
- req在生成req證書請求時同時產(chǎn)生密鑰。
- genpkey除了可以生成RSA密鑰外,還可以生成DSA救巷、DH密鑰谜酒。
使用genpkey命令生成RSA私鑰文件,選擇DES-EDE3-CBC算法進(jìn)行加密唆貌,口令是1234:
openssl genpkey -algorithm RSA -out privatekey.pem -pass pass:1234 -des-ede3-cbc
生成私鑰文件,其密鑰長度為1024诱担。
這里還可以直接生成Openssl ASN格式的key:
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info:DES-EDE3-CBC,4D5D1AF13367D726
BASE64私鑰內(nèi)容
-----END RSA PRIVATE KEY-----
還有很多格式施籍,比如微軟的PVK等诈茧。Openssl ASN格式在加密私鑰數(shù)據(jù)時只能用MD5算法生成key,而且只迭代計算了1次曾沈。所以從1.0.0開始Openssl把PKCS#8格式作為默認(rèn)格式障涯,可以為私鑰文件提供更好的安全性和擴(kuò)展性匙姜。
genrsa
生成ASN格式的key畅厢;
rsa
生成或者轉(zhuǎn)化為PVK格式:openssl rsa -in privatekey.pem -out privatekey.pvk -outform PVK
。
解析私鑰
使用asn1parse
命令讀取私鑰SAN.1結(jié)構(gòu)郭计,其中-i表示使用縮進(jìn)格式霸琴。
openssl asn1parse -i -in privatekey.pem
其ASN.1輸出格式為:
0:d=0 hl=3 l= 135 cons: SEQUENCE
3:d=1 hl=2 l= 1 prim: INTEGER :01
6:d=1 hl=2 l= 19 cons: SEQUENCE
8:d=2 hl=2 l= 7 prim: OBJECT :id-ecPublicKey
17:d=2 hl=2 l= 8 prim: OBJECT :prime256v1
27:d=1 hl=2 l= 109 prim: OCTET STRING [HEX DUMP]:306B02010104204B42FE59E4C16B8BDD516E23AE880BBBC2662D28DD6B461C0364D639F691FBCCA144034200040EE3526C590136A6DD9467F0C17487296BF8A70D9E14E783F955C21D5E0212B04A9D45C18B073F9CBEFAE94CD79D69EC8D4529DD9392CC209FE7A70D90B9AFE9
每一行的意義大概為:
- 0 表示節(jié)點在整個文件中的偏移長度
- d=0 表示節(jié)點深度
- hl=3 表示節(jié)點頭字節(jié)長度
- l=135 表示節(jié)點數(shù)據(jù)字節(jié)長度
- cons 表示該節(jié)點為結(jié)構(gòu)節(jié)點,表示包含子節(jié)點或者子結(jié)構(gòu)數(shù)據(jù)
- prim 表示該節(jié)點為原始節(jié)點昭伸,包含數(shù)據(jù)
- SEQUENCE梧乘、OCTET STRING等都是ASN.1中定義的數(shù)據(jù)類型,具體可以參考ASN.1格式說明。
最后一個節(jié)點OCTET STRING [HEX DUMP]选调,就是加密后的私鑰數(shù)據(jù)夹供。