天天看點

linux核心簽名建立私鑰檔案,使用openssl指令剖析RSA私鑰檔案格式

http://blog.csdn.net/zhymax/article/details/7683925

Openssl提供了強大證書功能,生成密鑰對、證書,頒發證書、生成crl、驗證證書、銷毀證書等。本文将j介紹如何利用openssl的指令分析RSA私鑰檔案格式,同時也将簡單介紹幾種常見的私鑰檔案格式。

1 生成私鑰檔案

openssl有多種方法生成私鑰:

genrsa生成RSA密鑰。

req在生成req證書請求時同時産生密鑰。

genpkey除了可以生成RSA密鑰外,還可以生成DSA、DH密鑰。

這裡我使用genpkey指令生成RSA私鑰檔案,選擇DES-EDE3-CBC算法進行加密,密碼是1234:

openssl genpkey -algorithm RSA -out privatekey.pem -pass pass:1234 -des-ede3-cbc

指令執行後輸出私鑰檔案privatekey.pem,預設輸出為PEM格式,密鑰長度為1024,接下來使用文本工具直接打開該檔案,可以看到如下内容:

-----BEGINENCRYPTED PRIVATE KEY-----

MIICxjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIhrQ3ApYYe1ACAggA

MBQGCCqGSIb3DQMHBAgyM5zYLuXOdQSCAoAFqnCRqkpoHJTY0BpLeekzjsuzdTOq

DkgxJMi4WRt1rZNyHqarbhHCZGC9Lug/xbLW5e2ZtjYVJ+ljmFb4lUaAch4nAgoz

m0J5YyrbFKppiqlk6vkS5hKfpKbWrx5hkQzMt6OsVEQFj2U+EvOI8SVgI6LkjNmh

7qokYxv9Inx9joM6agEUY9fXdAu53CyfjpneX95vxUHIn7hHmhxH7MYua619N7x+

JVA65b3Kj45aH3cnY/kMAQ78EN9aLpqYXzn6j9GRdUd2JMuP0IrYlREw3/z8Qn68

CwGXzGtkYnlt0xHdOG/tnmKWqBg1cY9uVx6g6JT1BUabqwxVODaMqaSsFr4o3xJo

3TTh8TswK0V/+3JLkXtasI7V8cRj2dksccGApujmB5eymU3XXTlX3iXs481I4kmz

JOZHbqfGOpyzW6WqhMO+LebIkyIGMlCGRiJ3PNSQI9w6bfZ9FoqC6OfFKY1OEmBN

6ALtPc+cYXeO5Msx9mbakIYRbcjlVmelPsLyvAceW/09OG909turflvYaGnM+SKd

KzWn2gFr3YwF57WZlX2jifYUUnjHVMZW7s/k6hgOxcEnvBOg4Ug/cKdNPUEB7tJx

nvsR+odHypyjgyphLEP8UmEiz3/hnPV8lhLDAPV7fKaK+zDglKqQYF3KBLh55q6h

PPe1HqahifK9EKqWOl7m1HhFPIZTex4clLy98rB3gyXnL0qx4+A7WD6uLJbU285j

IWMNq3f1c80ZPrpbhT6hd6Z9zUwfYT6gTO9gIIe4d5KVmfjNaFwSls5zaI6x7AJp

d/Xl/m1u469+J0rWyeY3D4wtahvZrKMXRrILtJ5OgkWPak2FTyMu/Hs/

-----ENDENCRYPTED PRIVATE KEY-----

私鑰經過PEM編碼後在檔案頭尾都添加了标簽,用以說明目前的檔案格式。從标簽内容也可以看出私鑰是加密的,因為有“ENCRYPTED”。中間的私鑰内容是經過BASE64編碼的,這樣友善私鑰的傳遞,例如在網絡上傳輸,資料複制粘貼。

例子隻是PEM檔案格式的其中一種,以下是平時可能會碰到的PEM私鑰格式:

PKCS#8 私鑰加密格式

-----BEGIN ENCRYPTED PRIVATE KEY-----

BASE64私鑰内容

-----ENDENCRYPTED PRIVATE KEY-----

PKCS#8 私鑰非加密格式

-----BEGIN PRIVATE KEY-----

BASE64私鑰内容

-----END PRIVATEKEY-----

Openssl ASN格式

-----BEGIN RSA PRIVATE KEY-----

Proc-Type: 4,ENCRYPTED

DEK-Info:DES-EDE3-CBC,4D5D1AF13367D726

BASE64私鑰内容

-----END RSA PRIVATE KEY-----

除了以上幾種,還有微軟的PVK格式;以及DER編碼格式,就是在使用PEM編碼前的資料,由于沒有密碼保護,平時很少直接使用。

Openssl ASN格式在加密私鑰資料時隻能用MD5算法生成key,而且隻疊代計算了1次。

是以從1.0.0開始Openssl把PKCS#8格式作為預設格式,可以為私鑰檔案提供更好的安全性和擴充性。

我們這裡就針對PKCS#8格式的私鑰進行讨論。 如果大家想要研究其他格式,可以使用以下指令:

genrsa生成ASN格式

rsa生成或轉換為PVK格式

openssl rsa -in privatekey.pem -out privatekey.pvk -outform PVK

2 分析私鑰檔案

使用asn1parse指令讀取私鑰ASN.1結構,其中–i表示輸出使用縮進格式。

openssl asn1parse -i -in privatekey.pem

0:d=0hl=4l=710cons: SEQUENCE

4:d=1hl=2l=64cons: SEQUENCE

6:d=2hl=2l=9prim:  OBJECT            :PBES2

17:d=2hl=2l=51cons:  SEQUENCE

19:d=3hl=2l=27cons:   SEQUENCE

21:d=4hl=2l=9prim:    OBJECT            :PBKDF2

32:d=4hl=2l=14cons:    SEQUENCE

34:d=5hl=2l=8prim:     OCTET STRING      [HEX DUMP]:7A61B055165A89CA

44:d=5hl=2l=2prim:     INTEGER           :0800

48:d=3hl=2l=20cons:   SEQUENCE

50:d=4hl=2l=8prim:    OBJECT            :des-ede3-cbc

60:d=4hl=2l=8prim:    OCTET STRING      [HEX DUMP]:110E8A184EFEAB9C

70:d=1hl=4l=640prim:  OCTET STRING      [HEX DUMP]:

4F34F0CFF56B3E92D437C49559B1BD632BA2D8B22AF290B0E8EBB7F71C555115CED4DE87E3922A41436A20DA1DB01F1BD88EA3002E8AD4691C0B25F16AF4D196C2A96B99A1D49F704A21D3B81F8CC81C3F09412317B67F453151490D2573E1FD96D13BB55E7FCD4085ED0C4DD75EB1EFFC4ACE5431AFD708E6ECE5077BAB2B03965C6F2873C1DB5F475F861E9C04D61465C72A8A99DCF093190F746DD8959C0B0942E38A013B0FEC2D4A66F600EF75CE0326F3B4904C3128CB389204A1CC4F93EED7C8F2450603A42C6C16FB143FF4C9C01E714A43CC07B1F1B580A6C9DE4DC9B78CA0D5B874C75A0F56F6A55CFE4620F1AC639DCE4A8AF2BCBB69691DAF983BB26F6A6C859C371D1EBA7DA5C27FBDAC86C6529C48B32E3B89317FC7EBF03F9C105EAA1892437E9E789F0E2340979812A53CD1668EC07A45BBEAE088E7E27BB20B16C2D14280970BBF715D57005F194B97A1784E7BC563A0B84909A7EAB6C7E0BC6E2B467AA4009420D190617F93CD32FAEEE50003462DC8B26816040E891523E1375F339A3F05C43C9E90A4533BD4D3F75A2A33E60D91563542355D5ED1F46CF62594460694F459F0EC428BECE015F075895CFEB502EA22ECD9B53BF050B795074BE9A51194789F0B2970C21CCFE16284FB564F720C7899D5840362C48D248A50BAFA2720B0C1F7B417AD6EA183459BBB80679A85D96421C5AE3FA53A2135217F886759187123766914BB0169F6F9C3A36F1C46B6EB9300009A799D0F96C3E1FBE805F17A01FF2F5A9C941399E6130DBEE9825F4EB8937F2B8F0B3DE5F08644F3DC65028F2DE150D03D454AECFF9CAF26A00BB1B6D6D2C5255216E0A6769F14937618E31573811AAA464C3C42246A17DD70B1F77A87948FD5C7526D569BB8

ASN.1結構輸出格式說明:

0:d=0hl=4l=710cons: SEQUENCE

0表示節點在整個檔案中的偏移長度

d=0表示節點深度

hl=4表示節點頭位元組長度

l=710表示節點資料位元組長度

cons表示該節點為結構節點,表示包含子節點或者子結構資料

prim表示該節點為原始節點,包含資料

SEQUENCE、OCTETSTRING等都是ASN.1中定義的資料類型,具體可以參考ASN.1格式說明。

最後一個節點OCTET STRING      [HEX DUMP],就是加密後的私鑰資料。

為了友善了解,下面給出相關的PKCS定義。

PCKS#8檔案格式定義:

PrivateKeyInfo::=SEQUENCE{

version                   Version,

privateKeyAlgorithm       PrivateKeyAlgorithmIdentifier,

privateKey                PrivateKey,

attributes           [0]  IMPLICIT Attributes OPTIONAL }

privateKey,加密後私鑰資料,最後一個OCTET STRING資料塊。

privateKeyAlgorithm,使用的私鑰算法,詳細格式在PKCS#5 2.0中的定義:

PBES2-params::=SEQUENCE{

keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},

encryptionScheme AlgorithmIdentifier {{PBES2-Encs}}

}

keyDerivationFunc

加密密鑰生成函數,現在預設使用的是sha1,還包含了salt,疊代次數iterationCount:

PBKDF2-params::=SEQUENCE{

salt CHOICE {

specified OCTET STRING,

otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}}

},

iterationCount INTEGER (1..MAX),

keyLength INTEGER (1..MAX) OPTIONAL,

prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT

algid-hmacWithSHA1

}

對應資料:

19:d=3hl=2l=27cons:   SEQUENCE

21:d=4hl=2l=9prim:    OBJECT            :PBKDF2

32:d=4hl=2l=14cons:    SEQUENCE

34:d=5hl=2l=8prim:     OCTET STRING      [HEX DUMP]:7A61B055165A89CA

44:d=5hl=2l=2prim:     INTEGER           :0800

encryptionScheme

加密算法,例子中使用的是des-ede3-cbc,該結構中還包含初始化向量iv。

對應資料:

48:d=3hl=2l=20cons:   SEQUENCE

50:d=4hl=2l=8prim:    OBJECT            :des-ede3-cbc

60:d=4hl=2l=8prim:    OCTET STRING      [HEX DUMP]:110E8A184EFEAB9C

解密流程:

1 按PKCS#8和PCKS#5定義從檔案中解析出相關參數:

加密密鑰生成函數(KDF)PBKDF2;

加密時使用的salt:7A61B055165A89CA,以及疊代次數iter:0x0800(2048次);

加密算法des-ede3-cbc,以及加密初始向量iv:110E8A184EFEAB9C

2 解析出加密的私鑰資料data,也就是最後一個OCTET STRING;

3 生成加密密鑰:key = KDF(pass(1234),salt,iter)

4 解密 des-ede3-cbc(key, iv, data)

這一解密過程可以使用openssl的pkey指令完成,執行完成後得到privatekey.der檔案,這個是沒有加密的私鑰檔案,資料是ASN.1格式,并使用DER編碼。

Openssl pkey -in privatekey.pem -outform der-out privatekey.der -passin pass:1234

然後再次分析密鑰資料,由于輸入是der格式,需要使用inform參數說明:

openssl asn1parse -in privatekey.der -inform DER

0:d=0hl=4l=604cons: SEQUENCE

4:d=1hl=2l=1prim: INTEGER           :00

7:d=1hl=3l=129prim:INTEGER           :

A11E66B0F965215AB4AD771581700477F62D9EDF2CFEBDF2E20C02DE4E95881F58CA898B6FC389CC83AE39DE95C0252BCF9FB98A6A21A20B751222DF2A4CBE1E08F8BDC8D443A59D4944723C33CED5601E1CF4A324E88B951626326783014CFF3BB7CF7278BF443AB003D1E1608B97CFC7783C6FD42B9A7C8F84C5633FB72DFB

139:d=1hl=2l=3prim: INTEGER           :010001

144:d=1hl=3l=129prim:INTEGER           :

9B2C9B7CD105AC851EC47E8FB0D541088489D59C5E4A8E88F15ADE1C5B953ABFEE154B39870FCD94B23247BBEF805A8C826FF413B239E8469E9F3404B949A643E1E2CCF9753822FD28345B7898148164DA2D858F672B52C7B3041F0A9F6FFFB97759D3C04AE3ED2E372E4ADD3A44202CE004D189566A81F19239649779F30DE9

276:d=1hl=2l=65prim: INTEGER           :

CE25257FDE50AFDAF926BDBEFE5A236C130F2714C5FC0C36A07B5AA5618E8F5039E313387C933A86EBDC2DEF8640069CB98B1D04C3E74B46C75F292A768083D5

343:d=1hl=2l=65prim: INTEGER           :

C8159573F6C413EAC0BB721B859A4B7920FF9DE151546CA28FDA3F43A0999C835DB9078AF5054CE503C4BC174ECB1F0C4DE033E116A296FD67B4158F869E628F

410:d=1hl=2l=64prim: INTEGER           :

7329855D7DD10DAD02EB85AD216331CEBA87088A2E60B462001D697262A1C5A647F07758631FCCDE7AFD321C519F8B121B05805C9D24A58510F4348728547B51

476:d=1hl=2l=64prim: INTEGER           :

53735D203EBDCD28CE35E003C69771FF155A47B92038BC0E993D07C1E70BEA9187D79263CC89E7666549FAC125E5E60F35B3DB2F78475BFE58F06D45AD7A05D5

542:d=1hl=2l=64prim: INTEGER           :

4F454C491EAE6CD85ED812D8A26AFD5FD0F6D7DD12AD6D20EDA8C2D257943928B2AE66FDE336F40370D9CC30B85EB2F20D3B4FDAB61D168FE7936CB6AB5E8FE2

得到的資料與上次導出的格式是相同的,雖然看起來資料多,但是層次結構起始要簡單,資料就是一個結構體(cons)SEQUENCE,包含9個整型的原始資料(prim)INTERGER,這個就是私鑰結構,該 ASN.1結構在PKCS#1中定義如下:

RSAPrivateKey::=SEQUENCE{

versionVersion,

modulusINTEGER, -- n

publicExponentINTEGER, -- e

privateExponentINTEGER, -- d

prime1INTEGER, -- p

prime2INTEGER, -- q

exponent1INTEGER, -- d mod (p-1)

exponent2INTEGER, -- d mod (q-1)

coefficientINTEGER, -- (inverse of q) mod p

otherPrimeInfosOtherPrimeInfos OPTIONAL

}

最後一個otherPrimeInfos是可選項,例子中沒有該資料。

結構中包含了RSA密鑰算法中用到的所有資訊,每一項的具體定義可以參考PKCS#1。

3 分析公鑰

為了友善擷取公鑰,在私鑰檔案資料中起始包含了公鑰資訊:

modulus INTEGER, -- n

publicExponent INTEGER, -- e

公鑰的ASN.1結構也在PKCS#1中定義:

RSAPublicKey::=SEQUENCE{

modulus INTEGER, -- n

publicExponentINTEGER -- e

}

可以使用openssl指令導出公鑰檔案pubkey.pem,使用文本工具打開公鑰檔案,pem頭尾格式和私鑰類似的标簽:

openssl pkey -in privatekey.der -inform DER -out pubkey.pem-pubout

-----BEGIN PUBLIC KEY-----

MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQChHmaw+WUhWrStdxWBcAR39i2e

3yz+vfLiDALeTpWIH1jKiYtvw4nMg6453pXAJSvPn7mKaiGiC3USIt8qTL4eCPi9

yNRDpZ1JRHI8M87VYB4c9KMk6IuVFiYyZ4MBTP87t89yeL9EOrAD0eFgi5fPx3g8

b9QrmnyPhMVjP7ct+wIDAQAB

-----END PUBLIC KEY-----

繼續分析公鑰檔案的ASN.1格式:

openssl asn1parse -in pubkey.pem -i

0:d=0hl=3l=159cons: SEQUENCE

3:d=1hl=2l=13cons: SEQUENCE

5:d=2hl=2l=9prim:  OBJECT            :rsaEncryption

16:d=2hl=2l=0prim:  NULL

18:d=1hl=3l=141prim:  BIT STRING

但是這裡顯示格式和上邊給出的PKCS#1格式不一緻,其實這是x.509中的定義的格式,在X.509證書檔案中就是使用這個格式封裝公鑰資料,其中BIT STRING的内容就是PKCS#1格式的公鑰資料,并說明了使用的公鑰算法rsaEncryption。

SubjectPublicKeyInfo::=SEQUENCE{

algorithmAlgorithmIdentifier{{SupportedAlgorithms}},

subjectPublicKeyBIT STRING

}

我們可以進一步使用asn1parse工具解析出BIT STRING内容,首先确定該資料塊偏移是18,然後使用參數-strparse指定位置,可以看到輸出的資料和私鑰檔案中的是一樣的。

asn1parse -in pubkey.pem -strparse 18

輸出公鑰ASN.1格式:

0:d=0hl=3l=137cons: SEQUENCE

3:d=1hl=3l=129prim: INTEGER           :

A11E66B0F965215AB4AD771581700477F62D9EDF2CFEBDF2E20C02DE4E95881F58CA898B6FC389CC83AE39DE95C0252BCF9FB98A6A21A20B751222DF2A4CBE1E08F8BDC8D443A59D4944723C33CED5601E1CF4A324E88B951626326783014CFF3BB7CF7278BF443AB003D1E1608B97CFC7783C6FD42B9A7C8F84C5633FB72DFB

135:d=1hl=2l=3prim: INTEGER           :010001

4 公私鑰操作

分析完私鑰和公鑰格式,以及之間的關系。接下來我們将繼續使用openssl的rsautl測試它們之間的加解密、簽名、驗證等操作。

測試檔案test,内容“1234567890”。

4.1加解密

1)公鑰加密

openssl rsautl -encrypt -in test -out test.enc -inkey asn1pub.pem -pubin

2)私鑰解密

openssl rsautl -decrypt -in test.enc -out test.dec -inkey asn1enc.pem

比較test和test.dec兩個檔案結果相同。

4.2簽名驗證

1)私鑰簽名

openssl rsautl -sign -in test -out test.sig-inkey asn1enc.pem

2)公鑰驗證

openssl rsautl -verify -in test.sig -out test.vfy -inkey asn1pub.pem -pubin

比較test和test.vfy連個檔案應該相同。