前言:
PEM是OpenSSL和許多其他SSL工具的標准格式,OpenSSL 使用PEM 文件格式存儲證書和密鑰。這種格式被設計用來安全的包含在ascii甚至富文本文檔中,如電子郵件。這意味着您可以簡單的復制和粘貼pem文件的內容到另一個文檔中。
PEM文件是Base64編碼的證書。PEM證書通常用於web服務器,因為他們可以通過一個簡單的文本編輯器,很容易地轉換成可讀的數據。通常當一個PEM編碼在文本編輯器中打開文件,它會包含不同的頁眉和頁腳。
-----BEGIN CERTIFICATE REQUEST----- and -----END CERTIFICATEREQUEST-----
CSR(證書簽名請求)
-----BEGIN RSA PRIVATE KEY----- and -----END RSA PRIVATEKEY-----
私鑰
-----BEGIN CERTIFICATE----- and -----END CERTIFICATE-----
證書文件
PKCS #8: Private-Key Information Syntax(語法) Standard(標准)
OpenSSL:是一個強大的安全套接字層密碼庫,囊括主要的密碼算法、常用的密鑰和證書封裝管理功能及SSL協議,並提供豐富的應用程序供測試或其它目的使用。
OpenSSL整個軟件包大概可以分成三個主要的功能部分:密碼算法庫、SSL協議庫以及應用程序。OpenSSL的目錄結構自然也是圍繞這三個功能部分進行規划的。
一、OpenSSL生成pem格式公私鑰
1、生成RSA私鑰
openssl genrsa -out rsa_private_key.pem 1024
該命令會生成1024位的私鑰,運行,如下圖:
生成私鑰文件rsa_private_key.pem,內容如下:
用記事本方式打開它,可以看到-----BEGIN RSA PRIVATE KEY-----開頭,-----END RSA PRIVATE KEY-----結尾的字符串,這個就是原始的私鑰。
備注:若運行openssl.exe,會進入OpenSSL命令行界面,此時輸入命令時,則無需再寫openssl。
2、RSA私鑰轉換成PKCS8格式
openssl pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -out rsa_private_key_01.pem -nocrypt
打開生成的文件后可以看到,控制台打印出的內容,-----BEGIN PRIVATE KEY-----開頭,-----END PRIVATE KEY-----結尾的字符串,這個就是PKCS#8格式的私鑰。
3、生成RSA公鑰
openssl rsa -in rsa_private_key.pem-pubout -out rsa_public_key.pem
運行,如下圖:
生成公鑰文件rsa_public_key.pem, 打開它,可以看到-----BEGIN PUBLIC KEY-----開頭,-----END PUBLIC KEY-----結尾的字符串,這個就是公鑰。
4、Java使用pem文件內容,示例代碼
1)私鑰簽名
a)獲取私鑰
//獲取KeyFactory,指定RSA算法
KeyFactorykeyFactory = KeyFactory.getInstance("RSA");
//將BASE64編碼的私鑰字符串進行解碼
BASE64Decoderdecoder = newBASE64Decoder();
byte[] encodeByte = decoder.decodeBuffer(priKey);
//將BASE64解碼后的字節數組,構造成PKCS8EncodedKeySpec對象,生成私鑰對象
PrivateKeyprivatekey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encodeByte));
b)使用私鑰,對數據進行簽名
//獲取Signature實例,指定簽名算法(本例使用SHA1WithRSA)
Signaturesignature = Signature.getInstance("SHA1WithRSA");
//加載私鑰
signature.initSign(privatekey);
//更新待簽名的數據
signature.update(plain.getBytes("UTF-8"));
//進行簽名
byte[] signed = signature.sign();
//將加密后的字節數組,轉換成BASE64編碼的字符串,作為最終的簽名數據
BASE64Encoderencoder = newBASE64Encoder();
return encoder.encode(signed);
2)公鑰驗簽
a)獲取公鑰
//獲取KeyFactory,指定RSA算法
KeyFactorykeyFactory = KeyFactory.getInstance("RSA");
//將BASE64編碼的公鑰字符串進行解碼
BASE64Decoderdecoder = newBASE64Decoder();
byte[] encodeByte = decoder.decodeBuffer(pubKey);
//將BASE64解碼后的字節數組,構造成X509EncodedKeySpec對象,生成公鑰對象
PublicKeypublicKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodeByte));
b)使用公鑰,進行驗簽
//獲取Signature實例,指定簽名算法(與之前一致)
Signaturesignature = Signature.getInstance("SHA1WithRSA");
//加載公鑰
signature.initVerify(publicKey);
//更新原數據
signature.update(plain.getBytes("UTF-8"));
//公鑰驗簽(true-驗簽通過;false-驗簽失敗)
BASE64Decoderdecoder = newBASE64Decoder();
returnsignature.verify(decoder.decodeBuffer(sign));
備注:
驗簽時,簽名數據需要先BASE64解碼
附:遇到的問題:在RSA加解密驗證時,使用私鑰無法生成簽名,報algid parse error, not a sequence錯誤
原因:私鑰在使用前為pkcs1格式,而java在不引用第三方包的情況下無法直接使用pkcs1格式的秘鑰,需要將其轉化為pkcs8編碼
解決方案:使用openssl(官網:https://www.openssl.org/source/)將私鑰進行pkcs8編碼,將秘鑰文件拷貝到openssl安裝目錄中,打開cmd命令進入該目錄,執行命令:
openssl pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -out rsa_private_key_01.pem -nocrypt
其中rsa_private_key.pem表示原私鑰文件,rsa_private_key_01.pem表示pkcs8編碼后的私鑰文件。
注:目前網上還沒找到java在不使用第三方jar包的情況下處理pkcs1格式私鑰的解決方案。絕大多數都是使用openssl工具將秘鑰文件處理為pkcs8編碼后再進行操作。