日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java中使用OpenSSL生成的RSA公私钥进行数据加解密

發布時間:2025/3/17 java 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java中使用OpenSSL生成的RSA公私钥进行数据加解密 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本文出處:http://blog.csdn.net/chaijunkun/article/details/7275632,轉載請注明。由于本人不定期會整理相關博文,會對相應內容作出完善。因此強烈建議在原始出處查看此文。

?

RSA是什么:RSA公鑰加密算法是 1977年由Ron Rivest、Adi Shamirh和LenAdleman在(美國麻省理工學院)開發的。RSA取名來自開發他們三者的名字。RSA是目前最有影響力的公鑰加密算法,它能夠 抵抗到目前為止已知的所有密碼攻擊,已被ISO推薦為公鑰數據加密標準。目前該加密方式廣泛用于網上銀行、數字簽名等場合。RSA算法基于一個十分簡單的 數論事實:將兩個大素數相乘十分容易,但那時想要對其乘積進行因式分解卻極其困難,因此可以將乘積公開作為加密密鑰。

OpenSSL是什 么:眾多的密碼算法、公鑰基礎設施標準以及SSL協議,或許這些有趣的功能會讓你產生實現所有這些算法和標準的想法。果真如此,在對你表示敬佩的同時,還 是忍不住提醒你:這是一個令人望而生畏的過程。這個工作不再是簡單的讀懂幾本密碼學專著和協議文檔那么簡單,而是要理解所有這些算法、標準和協議文檔的每 一個細節,并用你可能很熟悉的C語言字符一個一個去實現這些定義和過程。我們不知道你將需要多少時間來完成這項有趣而可怕的工作,但肯定不是一年兩年的問 題。OpenSSL就是由Eric A. Young和Tim J. Hudson兩位絕世大好人自1995年就開始編寫的集合眾多安全算法的算法集合。通過命令或者開發庫,我們可以輕松實現標準的公開算法應用。

?

我的一個假設應用背景:

隨 著移動互聯網的普及,為移動設備開發的應用也層出不窮。這些應用往往伴隨著用戶注冊與密碼驗證的功能。”網絡傳輸“、”應用程序日志訪問“中的安全性都存 在著隱患。密碼作為用戶的敏感數據,特別需要開發者在應用上線之前做好安全防范。處理不當,可能會造成諸如商業競爭對手的惡意攻擊、第三方合作商的訴訟等 問題。

?

RSA算法雖然有這么多好處,但是在網上找不到一個完整的例子來說明如何操作。下面我就來介紹一下:

一、使用OpenSSL來生成私鑰和公鑰

我使用的是Linux系統,已經安裝了OpenSSL軟件包,此時請驗證你的機器上已經安裝了OpenSSL,運行命令應當出現如下信息:

[plain] view plaincopy
  • [root@chaijunkun?~]#?openssl?version?-a??
  • OpenSSL?1.0.0-fips?29?Mar?2010??
  • built?on:?Wed?Jan?25?02:17:15?GMT?2012??
  • platform:?linux-x86_64??
  • options:??bn(64,64)?md2(int)?rc4(16x,int)?des(idx,cisc,16,int)?blowfish(idx)???
  • compiler:?gcc?-fPIC?-DOPENSSL_PIC?-DZLIB?-DOPENSSL_THREADS?-D_REENTRANT?-DDSO_DLFCN?-DHAVE_DLFCN_H?-DKRB5_MIT?-m64?-DL_ENDIAN?-DTERMIO?-Wall?-O2?-g?-pipe?-Wall?-Wp,-D_FORTIFY_SOURCE=2?-fexceptions?-fstack-protector?--param=ssp-buffer-size=4?-m64?-mtune=generic?-Wa,--noexecstack?-DMD32_REG_T=int?-DOPENSSL_IA32_SSE2?-DOPENSSL_BN_ASM_MONT?-DSHA1_ASM?-DSHA256_ASM?-DSHA512_ASM?-DMD5_ASM?-DAES_ASM?-DWHIRLPOOL_ASM??
  • OPENSSLDIR:?"/etc/pki/tls"??
  • engines:??aesni?dynamic???
  • 先來生成私鑰:

    [plain] view plaincopy
  • [root@chaijunkun?~]#?openssl?genrsa?-out?rsa_private_key.pem?1024??
  • Generating?RSA?private?key,?1024?bit?long?modulus??
  • .......................++++++??
  • ..++++++??
  • e?is?65537?(0x10001)??
  • 這條命令讓openssl隨機生成了一份私鑰,加密長度是1024位。加密長度是指理論上最大允許”被加密的信息“長度的限制,也就是明文的長度限制。隨著這個參數的增大(比方說2048),允許的明文長度也會增加,但同時也會造成計算復雜度的極速增長。一般推薦的長度就是1024位(128字節)。

    我們來看一下私鑰的內容:

    [plain] view plaincopy
  • [root@chaijunkun?~]#?cat?rsa_private_key.pem???
  • -----BEGIN?RSA?PRIVATE?KEY-----??
  • MIICWwIBAAKBgQChDzcjw/rWgFwnxunbKp7/4e8w/UmXx2jk6qEEn69t6N2R1i/L??
  • mcyDT1xr/T2AHGOiXNQ5V8W4iCaaeNawi7aJaRhtVx1uOH/2U378fscEESEG8XDq??
  • ll0GCfB1/TjKI2aitVSzXOtRs8kYgGU78f7VmDNgXIlk3gdhnzh+uoEQywIDAQAB??
  • AoGAaeKk76CSsp7k90mwyWP18GhLZru+vEhfT9BpV67cGLg1owFbntFYQSPVsTFm??
  • U2lWn5HD/IcV+EGaj4fOLXdM43Kt4wyznoABSZCKKxs6uRciu8nQaFNUy4xVeOfX??
  • PHU2TE7vi4LDkw9df1fya+DScSLnaDAUN3OHB5jqGL+Ls5ECQQDUfuxXN3uqGYKk??
  • znrKj0j6pY27HRfROMeHgxbjnnApCQ71SzjqAM77R3wIlKfh935OIV0aQC4jQRB4??
  • iHYSLl9lAkEAwgh4jxxXeIAufMsgjOi3qpJqGvumKX0W96McpCwV3Fsew7W1/msi??
  • suTkJp5BBvjFvFwfMAHYlJdP7W+nEBWkbwJAYbz/eB5NAzA4pxVR5VmCd8cuKaJ4??
  • EgPLwsjI/mkhrb484xZ2VyuICIwYwNmfXpA3yDgQWsKqdgy3Rrl9lV8/AQJAcjLi??
  • IfigUr++nJxA8C4Xy0CZSoBJ76k710wdE1MPGr5WgQF1t+P+bCPjVAdYZm4Mkyv0??
  • /yBXBD16QVixjvnt6QJABli6Zx9GYRWnu6AKpDAHd8QjWOnnNfNLQHue4WepEvkm??
  • CysG+IBs2GgsXNtrzLWJLFx7VHmpqNTTC8yNmX1KFw==??
  • -----END?RSA?PRIVATE?KEY-----??
  • 內容都是標準的ASCII字符,開頭一行和結尾一行有明顯的標記,真正的私鑰數據是中間的不規則字符。

    2015 年3月24日補充:密鑰文件最終將數據通過Base64編碼進行存儲。可以看到上述密鑰文件內容每一行的長度都很規律。這是由于RFC2045中規 定:The encoded output stream must be represented in lines of no more than 76 characters each。也就是說Base64編碼的數據每行最多不超過76字符,對于超長數據需要按行分割。

    接下來根據私鑰生成公鑰:

    [plain] view plaincopy
  • [root@chaijunkun?~]#?openssl?rsa?-in?rsa_private_key.pem?-out?rsa_public_key.pem?-pubout??
  • writing?RSA?key??
  • 再來看一下公鑰的內容: [plain] view plaincopy
  • [root@chaijunkun?~]#?cat?rsa_public_ley.pem???
  • -----BEGIN?PUBLIC?KEY-----??
  • MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQChDzcjw/rWgFwnxunbKp7/4e8w??
  • /UmXx2jk6qEEn69t6N2R1i/LmcyDT1xr/T2AHGOiXNQ5V8W4iCaaeNawi7aJaRht??
  • Vx1uOH/2U378fscEESEG8XDqll0GCfB1/TjKI2aitVSzXOtRs8kYgGU78f7VmDNg??
  • XIlk3gdhnzh+uoEQywIDAQAB??
  • -----END?PUBLIC?KEY-----??
  • 這時候的私鑰還不能直接被使用,需要進行PKCS#8編碼: [plain] view plaincopy
  • [root@chaijunkun?~]#?openssl?pkcs8?-topk8?-in?rsa_private_key.pem?-out?pkcs8_rsa_private_key.pem?-nocrypt??
  • 命令中指明了輸入私鑰文件為rsa_private_key.pem,輸出私鑰文件為pkcs8_rsa_private_key.pem,不采用任何二次加密(-nocrypt)

    再來看一下,編碼后的私鑰文件是不是和之前的私鑰文件不同了:

    [plain] view plaincopy
  • [root@chaijunkun?~]#?cat?pkcs8_rsa_private_key.pem???
  • -----BEGIN?PRIVATE?KEY-----??
  • MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAKEPNyPD+taAXCfG??
  • 6dsqnv/h7zD9SZfHaOTqoQSfr23o3ZHWL8uZzINPXGv9PYAcY6Jc1DlXxbiIJpp4??
  • 1rCLtolpGG1XHW44f/ZTfvx+xwQRIQbxcOqWXQYJ8HX9OMojZqK1VLNc61GzyRiA??
  • ZTvx/tWYM2BciWTeB2GfOH66gRDLAgMBAAECgYBp4qTvoJKynuT3SbDJY/XwaEtm??
  • u768SF9P0GlXrtwYuDWjAVue0VhBI9WxMWZTaVafkcP8hxX4QZqPh84td0zjcq3j??
  • DLOegAFJkIorGzq5FyK7ydBoU1TLjFV459c8dTZMTu+LgsOTD11/V/Jr4NJxIudo??
  • MBQ3c4cHmOoYv4uzkQJBANR+7Fc3e6oZgqTOesqPSPqljbsdF9E4x4eDFuOecCkJ??
  • DvVLOOoAzvtHfAiUp+H3fk4hXRpALiNBEHiIdhIuX2UCQQDCCHiPHFd4gC58yyCM??
  • 6Leqkmoa+6YpfRb3oxykLBXcWx7DtbX+ayKy5OQmnkEG+MW8XB8wAdiUl0/tb6cQ??
  • FaRvAkBhvP94Hk0DMDinFVHlWYJ3xy4pongSA8vCyMj+aSGtvjzjFnZXK4gIjBjA??
  • 2Z9ekDfIOBBawqp2DLdGuX2VXz8BAkByMuIh+KBSv76cnEDwLhfLQJlKgEnvqTvX??
  • TB0TUw8avlaBAXW34/5sI+NUB1hmbgyTK/T/IFcEPXpBWLGO+e3pAkAGWLpnH0Zh??
  • Fae7oAqkMAd3xCNY6ec180tAe57hZ6kS+SYLKwb4gGzYaCxc22vMtYksXHtUeamo??
  • 1NMLzI2ZfUoX??
  • -----END?PRIVATE?KEY-----??
  • 至此,可用的密鑰對已經生成好了,私鑰使用pkcs8_rsa_private_key.pem,公鑰采用rsa_public_key.pem。

    2014年5月20日補充:最近又遇到RSA加密的需求了,而且對方要求只能使用第一步生成的未經過PKCS#8編碼的私鑰文件。后來查看相關文獻得知第一步生成的私鑰文件編碼是PKCS#1格式,這種格式Java其實是支持的,只不過多寫兩行代碼而已:

    [java] view plaincopy
  • RSAPrivateKeyStructure?asn1PrivKey?=?new?RSAPrivateKeyStructure((ASN1Sequence)?ASN1Sequence.fromByteArray(priKeyData));??
  • RSAPrivateKeySpec?rsaPrivKeySpec?=?new?RSAPrivateKeySpec(asn1PrivKey.getModulus(),?asn1PrivKey.getPrivateExponent());??
  • KeyFactory?keyFactory=?KeyFactory.getInstance("RSA");??
  • PrivateKey?priKey=?keyFactory.generatePrivate(rsaPrivKeySpec);??
  • 首先將PKCS#1的私鑰文件讀取出來(注意去掉減號開頭的注釋內容),然后使用Base64解碼讀出的字符串,便得到priKeyData,也就是第一行代碼中的參數。最后一行得到了私鑰。接下來的用法就沒什么區別了。

    參考文獻:https://community.oracle.com/thread/1529240?start=0&tstart=0

    ?

    二、編寫Java代碼實際測試

    2012 年2月23日補充:在標準JDK中只是規定了JCE(JCE (Java Cryptography Extension)?是一組包,它們提供用于加密、密鑰生成和協商以及 Message Authentication Code(MAC)算法的框架和實現。它提供對對稱、不對稱、塊和流密碼的加密支持,它還支持安全流和密封的對象。)接口,但是內部實現需要自己或者第三 方提供。因此我們這里使用bouncycastle的開源的JCE實現包,下載地址:http://bouncycastle.org /latest_releases.html,我使用的是bcprov-jdk16-146.jar,這是在JDK1.6環境下使用的。如果需要其他 JDK版本下的實現,可以在之前的下載頁面中找到對應版本。

    下面來看一下我實現的代碼:

    [java] view plaincopy
  • package?net.csdn.blog.chaijunkun;??
  • ??
  • import?java.io.BufferedReader;??
  • import?java.io.IOException;??
  • import?java.io.InputStream;??
  • import?java.io.InputStreamReader;??
  • import?java.security.InvalidKeyException;??
  • import?java.security.KeyFactory;??
  • import?java.security.KeyPair;??
  • import?java.security.KeyPairGenerator;??
  • import?java.security.NoSuchAlgorithmException;??
  • import?java.security.SecureRandom;??
  • import?java.security.interfaces.RSAPrivateKey;??
  • import?java.security.interfaces.RSAPublicKey;??
  • import?java.security.spec.InvalidKeySpecException;??
  • import?java.security.spec.PKCS8EncodedKeySpec;??
  • import?java.security.spec.X509EncodedKeySpec;??
  • ??
  • import?javax.crypto.BadPaddingException;??
  • import?javax.crypto.Cipher;??
  • import?javax.crypto.IllegalBlockSizeException;??
  • import?javax.crypto.NoSuchPaddingException;??
  • ??
  • import?org.bouncycastle.jce.provider.BouncyCastleProvider;??
  • ??
  • import?sun.misc.BASE64Decoder;??
  • ??
  • public?class?RSAEncrypt?{??
  • ??????
  • ????private?static?final?String?DEFAULT_PUBLIC_KEY=???
  • ????????"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQChDzcjw/rWgFwnxunbKp7/4e8w"?+?"\r"?+??
  • ????????"/UmXx2jk6qEEn69t6N2R1i/LmcyDT1xr/T2AHGOiXNQ5V8W4iCaaeNawi7aJaRht"?+?"\r"?+??
  • ????????"Vx1uOH/2U378fscEESEG8XDqll0GCfB1/TjKI2aitVSzXOtRs8kYgGU78f7VmDNg"?+?"\r"?+??
  • ????????"XIlk3gdhnzh+uoEQywIDAQAB"?+?"\r";??
  • ??????
  • ????private?static?final?String?DEFAULT_PRIVATE_KEY=??
  • ????????"MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAKEPNyPD+taAXCfG"?+?"\r"?+??
  • ????????"6dsqnv/h7zD9SZfHaOTqoQSfr23o3ZHWL8uZzINPXGv9PYAcY6Jc1DlXxbiIJpp4"?+?"\r"?+??
  • ????????"1rCLtolpGG1XHW44f/ZTfvx+xwQRIQbxcOqWXQYJ8HX9OMojZqK1VLNc61GzyRiA"?+?"\r"?+??
  • ????????"ZTvx/tWYM2BciWTeB2GfOH66gRDLAgMBAAECgYBp4qTvoJKynuT3SbDJY/XwaEtm"?+?"\r"?+??
  • ????????"u768SF9P0GlXrtwYuDWjAVue0VhBI9WxMWZTaVafkcP8hxX4QZqPh84td0zjcq3j"?+?"\r"?+??
  • ????????"DLOegAFJkIorGzq5FyK7ydBoU1TLjFV459c8dTZMTu+LgsOTD11/V/Jr4NJxIudo"?+?"\r"?+??
  • ????????"MBQ3c4cHmOoYv4uzkQJBANR+7Fc3e6oZgqTOesqPSPqljbsdF9E4x4eDFuOecCkJ"?+?"\r"?+??
  • ????????"DvVLOOoAzvtHfAiUp+H3fk4hXRpALiNBEHiIdhIuX2UCQQDCCHiPHFd4gC58yyCM"?+?"\r"?+??
  • ????????"6Leqkmoa+6YpfRb3oxykLBXcWx7DtbX+ayKy5OQmnkEG+MW8XB8wAdiUl0/tb6cQ"?+?"\r"?+??
  • ????????"FaRvAkBhvP94Hk0DMDinFVHlWYJ3xy4pongSA8vCyMj+aSGtvjzjFnZXK4gIjBjA"?+?"\r"?+??
  • ????????"2Z9ekDfIOBBawqp2DLdGuX2VXz8BAkByMuIh+KBSv76cnEDwLhfLQJlKgEnvqTvX"?+?"\r"?+??
  • ????????"TB0TUw8avlaBAXW34/5sI+NUB1hmbgyTK/T/IFcEPXpBWLGO+e3pAkAGWLpnH0Zh"?+?"\r"?+??
  • ????????"Fae7oAqkMAd3xCNY6ec180tAe57hZ6kS+SYLKwb4gGzYaCxc22vMtYksXHtUeamo"?+?"\r"?+??
  • ????????"1NMLzI2ZfUoX"?+?"\r";??
  • ??
  • ????/**?
  • ?????*?私鑰?
  • ?????*/??
  • ????private?RSAPrivateKey?privateKey;??
  • ??
  • ????/**?
  • ?????*?公鑰?
  • ?????*/??
  • ????private?RSAPublicKey?publicKey;??
  • ??????
  • ????/**?
  • ?????*?字節數據轉字符串專用集合?
  • ?????*/??
  • ????private?static?final?char[]?HEX_CHAR=?{'0',?'1',?'2',?'3',?'4',?'5',?'6',?'7',?'8',?'9',?'a',?'b',?'c',?'d',?'e',?'f'};??
  • ??????
  • ??
  • ????/**?
  • ?????*?獲取私鑰?
  • ?????*?@return?當前的私鑰對象?
  • ?????*/??
  • ????public?RSAPrivateKey?getPrivateKey()?{??
  • ????????return?privateKey;??
  • ????}??
  • ??
  • ????/**?
  • ?????*?獲取公鑰?
  • ?????*?@return?當前的公鑰對象?
  • ?????*/??
  • ????public?RSAPublicKey?getPublicKey()?{??
  • ????????return?publicKey;??
  • ????}??
  • ??
  • ????/**?
  • ?????*?隨機生成密鑰對?
  • ?????*/??
  • ????public?void?genKeyPair(){??
  • ????????KeyPairGenerator?keyPairGen=?null;??
  • ????????try?{??
  • ????????????keyPairGen=?KeyPairGenerator.getInstance("RSA");??
  • ????????}?catch?(NoSuchAlgorithmException?e)?{??
  • ????????????e.printStackTrace();??
  • ????????}??
  • ????????keyPairGen.initialize(1024,?new?SecureRandom());??
  • ????????KeyPair?keyPair=?keyPairGen.generateKeyPair();??
  • ????????this.privateKey=?(RSAPrivateKey)?keyPair.getPrivate();??
  • ????????this.publicKey=?(RSAPublicKey)?keyPair.getPublic();??
  • ????}??
  • ??
  • ????/**?
  • ?????*?從文件中輸入流中加載公鑰?
  • ?????*?@param?in?公鑰輸入流?
  • ?????*?@throws?Exception?加載公鑰時產生的異常?
  • ?????*/??
  • ????public?void?loadPublicKey(InputStream?in)?throws?Exception{??
  • ????????try?{??
  • ????????????BufferedReader?br=?new?BufferedReader(new?InputStreamReader(in));??
  • ????????????String?readLine=?null;??
  • ????????????StringBuilder?sb=?new?StringBuilder();??
  • ????????????while((readLine=?br.readLine())!=null){??
  • ????????????????if(readLine.charAt(0)=='-'){??
  • ????????????????????continue;??
  • ????????????????}else{??
  • ????????????????????sb.append(readLine);??
  • ????????????????????sb.append('\r');??
  • ????????????????}??
  • ????????????}??
  • ????????????loadPublicKey(sb.toString());??
  • ????????}?catch?(IOException?e)?{??
  • ????????????throw?new?Exception("公鑰數據流讀取錯誤");??
  • ????????}?catch?(NullPointerException?e)?{??
  • ????????????throw?new?Exception("公鑰輸入流為空");??
  • ????????}??
  • ????}??
  • ??
  • ??
  • ????/**?
  • ?????*?從字符串中加載公鑰?
  • ?????*?@param?publicKeyStr?公鑰數據字符串?
  • ?????*?@throws?Exception?加載公鑰時產生的異常?
  • ?????*/??
  • ????public?void?loadPublicKey(String?publicKeyStr)?throws?Exception{??
  • ????????try?{??
  • ????????????BASE64Decoder?base64Decoder=?new?BASE64Decoder();??
  • ????????????byte[]?buffer=?base64Decoder.decodeBuffer(publicKeyStr);??
  • ????????????KeyFactory?keyFactory=?KeyFactory.getInstance("RSA");??
  • ????????????X509EncodedKeySpec?keySpec=?new?X509EncodedKeySpec(buffer);??
  • ????????????this.publicKey=?(RSAPublicKey)?keyFactory.generatePublic(keySpec);??
  • ????????}?catch?(NoSuchAlgorithmException?e)?{??
  • ????????????throw?new?Exception("無此算法");??
  • ????????}?catch?(InvalidKeySpecException?e)?{??
  • ????????????throw?new?Exception("公鑰非法");??
  • ????????}?catch?(IOException?e)?{??
  • ????????????throw?new?Exception("公鑰數據內容讀取錯誤");??
  • ????????}?catch?(NullPointerException?e)?{??
  • ????????????throw?new?Exception("公鑰數據為空");??
  • ????????}??
  • ????}??
  • ??
  • ????/**?
  • ?????*?從文件中加載私鑰?
  • ?????*?@param?keyFileName?私鑰文件名?
  • ?????*?@return?是否成功?
  • ?????*?@throws?Exception??
  • ?????*/??
  • ????public?void?loadPrivateKey(InputStream?in)?throws?Exception{??
  • ????????try?{??
  • ????????????BufferedReader?br=?new?BufferedReader(new?InputStreamReader(in));??
  • ????????????String?readLine=?null;??
  • ????????????StringBuilder?sb=?new?StringBuilder();??
  • ????????????while((readLine=?br.readLine())!=null){??
  • ????????????????if(readLine.charAt(0)=='-'){??
  • ????????????????????continue;??
  • ????????????????}else{??
  • ????????????????????sb.append(readLine);??
  • ????????????????????sb.append('\r');??
  • ????????????????}??
  • ????????????}??
  • ????????????loadPrivateKey(sb.toString());??
  • ????????}?catch?(IOException?e)?{??
  • ????????????throw?new?Exception("私鑰數據讀取錯誤");??
  • ????????}?catch?(NullPointerException?e)?{??
  • ????????????throw?new?Exception("私鑰輸入流為空");??
  • ????????}??
  • ????}??
  • ??
  • ????public?void?loadPrivateKey(String?privateKeyStr)?throws?Exception{??
  • ????????try?{??
  • ????????????BASE64Decoder?base64Decoder=?new?BASE64Decoder();??
  • ????????????byte[]?buffer=?base64Decoder.decodeBuffer(privateKeyStr);??
  • ????????????PKCS8EncodedKeySpec?keySpec=?new?PKCS8EncodedKeySpec(buffer);??
  • ????????????KeyFactory?keyFactory=?KeyFactory.getInstance("RSA");??
  • ????????????this.privateKey=?(RSAPrivateKey)?keyFactory.generatePrivate(keySpec);??
  • ????????}?catch?(NoSuchAlgorithmException?e)?{??
  • ????????????throw?new?Exception("無此算法");??
  • ????????}?catch?(InvalidKeySpecException?e)?{??
  • ????????????throw?new?Exception("私鑰非法");??
  • ????????}?catch?(IOException?e)?{??
  • ????????????throw?new?Exception("私鑰數據內容讀取錯誤");??
  • ????????}?catch?(NullPointerException?e)?{??
  • ????????????throw?new?Exception("私鑰數據為空");??
  • ????????}??
  • ????}??
  • ??
  • ????/**?
  • ?????*?加密過程?
  • ?????*?@param?publicKey?公鑰?
  • ?????*?@param?plainTextData?明文數據?
  • ?????*?@return?
  • ?????*?@throws?Exception?加密過程中的異常信息?
  • ?????*/??
  • ????public?byte[]?encrypt(RSAPublicKey?publicKey,?byte[]?plainTextData)?throws?Exception{??
  • ????????if(publicKey==?null){??
  • ????????????throw?new?Exception("加密公鑰為空,?請設置");??
  • ????????}??
  • ????????Cipher?cipher=?null;??
  • ????????try?{??
  • ????????????cipher=?Cipher.getInstance("RSA",?new?BouncyCastleProvider());??
  • ????????????cipher.init(Cipher.ENCRYPT_MODE,?publicKey);??
  • ????????????byte[]?output=?cipher.doFinal(plainTextData);??
  • ????????????return?output;??
  • ????????}?catch?(NoSuchAlgorithmException?e)?{??
  • ????????????throw?new?Exception("無此加密算法");??
  • ????????}?catch?(NoSuchPaddingException?e)?{??
  • ????????????e.printStackTrace();??
  • ????????????return?null;??
  • ????????}catch?(InvalidKeyException?e)?{??
  • ????????????throw?new?Exception("加密公鑰非法,請檢查");??
  • ????????}?catch?(IllegalBlockSizeException?e)?{??
  • ????????????throw?new?Exception("明文長度非法");??
  • ????????}?catch?(BadPaddingException?e)?{??
  • ????????????throw?new?Exception("明文數據已損壞");??
  • ????????}??
  • ????}??
  • ??
  • ????/**?
  • ?????*?解密過程?
  • ?????*?@param?privateKey?私鑰?
  • ?????*?@param?cipherData?密文數據?
  • ?????*?@return?明文?
  • ?????*?@throws?Exception?解密過程中的異常信息?
  • ?????*/??
  • ????public?byte[]?decrypt(RSAPrivateKey?privateKey,?byte[]?cipherData)?throws?Exception{??
  • ????????if?(privateKey==?null){??
  • ????????????throw?new?Exception("解密私鑰為空,?請設置");??
  • ????????}??
  • ????????Cipher?cipher=?null;??
  • ????????try?{??
  • ????????????cipher=?Cipher.getInstance("RSA",?new?BouncyCastleProvider());??
  • ????????????cipher.init(Cipher.DECRYPT_MODE,?privateKey);??
  • ????????????byte[]?output=?cipher.doFinal(cipherData);??
  • ????????????return?output;??
  • ????????}?catch?(NoSuchAlgorithmException?e)?{??
  • ????????????throw?new?Exception("無此解密算法");??
  • ????????}?catch?(NoSuchPaddingException?e)?{??
  • ????????????e.printStackTrace();??
  • ????????????return?null;??
  • ????????}catch?(InvalidKeyException?e)?{??
  • ????????????throw?new?Exception("解密私鑰非法,請檢查");??
  • ????????}?catch?(IllegalBlockSizeException?e)?{??
  • ????????????throw?new?Exception("密文長度非法");??
  • ????????}?catch?(BadPaddingException?e)?{??
  • ????????????throw?new?Exception("密文數據已損壞");??
  • ????????}?????????
  • ????}??
  • ??
  • ??????
  • ????/**?
  • ?????*?字節數據轉十六進制字符串?
  • ?????*?@param?data?輸入數據?
  • ?????*?@return?十六進制內容?
  • ?????*/??
  • ????public?static?String?byteArrayToString(byte[]?data){??
  • ????????StringBuilder?stringBuilder=?new?StringBuilder();??
  • ????????for?(int?i=0;?i<data.length;?i++){??
  • ????????????//取出字節的高四位?作為索引得到相應的十六進制標識符?注意無符號右移??
  • ????????????stringBuilder.append(HEX_CHAR[(data[i]?&?0xf0)>>>?4]);??
  • ????????????//取出字節的低四位?作為索引得到相應的十六進制標識符??
  • ????????????stringBuilder.append(HEX_CHAR[(data[i]?&?0x0f)]);??
  • ????????????if?(i<data.length-1){??
  • ????????????????stringBuilder.append('?');??
  • ????????????}??
  • ????????}??
  • ????????return?stringBuilder.toString();??
  • ????}??
  • ??
  • ??
  • ????public?static?void?main(String[]?args){??
  • ????????RSAEncrypt?rsaEncrypt=?new?RSAEncrypt();??
  • ????????//rsaEncrypt.genKeyPair();??
  • ??
  • ????????//加載公鑰??
  • ????????try?{??
  • ????????????rsaEncrypt.loadPublicKey(RSAEncrypt.DEFAULT_PUBLIC_KEY);??
  • ????????????System.out.println("加載公鑰成功");??
  • ????????}?catch?(Exception?e)?{??
  • ????????????System.err.println(e.getMessage());??
  • ????????????System.err.println("加載公鑰失敗");??
  • ????????}??
  • ??
  • ????????//加載私鑰??
  • ????????try?{??
  • ????????????rsaEncrypt.loadPrivateKey(RSAEncrypt.DEFAULT_PRIVATE_KEY);??
  • ????????????System.out.println("加載私鑰成功");??
  • ????????}?catch?(Exception?e)?{??
  • ????????????System.err.println(e.getMessage());??
  • ????????????System.err.println("加載私鑰失敗");??
  • ????????}??
  • ??
  • ????????//測試字符串??
  • ????????String?encryptStr=?"Test?String?chaijunkun";??
  • ??
  • ????????try?{??
  • ????????????//加密??
  • ????????????byte[]?cipher?=?rsaEncrypt.encrypt(rsaEncrypt.getPublicKey(),?encryptStr.getBytes());??
  • ????????????//解密??
  • ????????????byte[]?plainText?=?rsaEncrypt.decrypt(rsaEncrypt.getPrivateKey(),?cipher);??
  • ????????????System.out.println("密文長度:"+?cipher.length);??
  • ????????????System.out.println(RSAEncrypt.byteArrayToString(cipher));??
  • ????????????System.out.println("明文長度:"+?plainText.length);??
  • ????????????System.out.println(RSAEncrypt.byteArrayToString(plainText));??
  • ????????????System.out.println(new?String(plainText));??
  • ????????}?catch?(Exception?e)?{??
  • ????????????System.err.println(e.getMessage());??
  • ????????}??
  • ????}??
  • }??

  • 代碼中我提供了兩種加載公鑰和私鑰的方式。

    按流來讀取:適合在Android應用中按ID索引資源得到InputStream的方式;

    按字符串來讀取:就像代碼中展示的那樣,將密鑰內容按行存儲到靜態常量中,按String類型導入密鑰。

    ?

    運行上面的代碼,會顯示如下信息: [plain] view plaincopy
  • 加載公鑰成功??
  • 加載私鑰成功??
  • 密文長度:128??
  • 35?b4?6f?49?69?ae?a3?85?a2?a5?0d?45?75?00?23?23?e6?70?69?b4?59?ae?72?6f?6d?d3?43?e1?d3?44?85?eb?04?57?2c?46?3e?70?09?4d?e6?4c?83?50?c7?56?75?80?c7?e1?31?64?57?c8?e3?46?a7?ce?57?31?ac?cd?21?89?89?8f?c1?24?c1?22?0c?cb?70?6a?0d?fa?c9?38?80?ba?2e?e1?29?02?ed?45?9e?88?e9?23?09?87?af?ad?ab?ac?cb?61?03?3c?a1?81?56?a5?de?c4?79?aa?3e?48?ee?30?3d?bc?5b?47?50?75?9f?fd?22?87?9e?de?b1?f4?e8?b2??
  • 明文長度:22??
  • 54?65?73?74?20?53?74?72?69?6e?67?20?63?68?61?69?6a?75?6e?6b?75?6e??
  • Test?String?chaijunkun??

  • 在main函數中我注釋掉了”rsaEncrypt.genKeyPair()“,這個方法是用來隨機生成密鑰對的(只生成、使用,不存儲)。當不使用文件密鑰時,可以將載入密鑰的代碼注釋,啟用本方法,也可以跑通代碼。

    加載公鑰與加載私鑰的不同點在于公鑰加載時使用的是X509EncodedKeySpec(X509編碼的Key指令),私鑰加載時使用的是PKCS8EncodedKeySpec(PKCS#8編碼的Key指令)。

    ?

    2012 年2月22日補充:在android軟件開發的過程中,發現上述代碼不能正常工作,主要原因在于sun.misc.BASE64Decoder類在 android開發包中不存在。因此需要特別在網上尋找rt.jar的源代碼,至于JDK的src.zip中的源代碼,這個只是JDK中的部分源代碼,上 述的幾個類的代碼都沒有。經過尋找并添加,上述代碼在android應用中能夠很好地工作。其中就包含這個類的對應代碼。另外此類還依賴于 CEFormatException、CEStreamExhausted、CharacterDecoder和CharacterEncoder類和異 常定義。

    ?

    2012 年2月23日補充:起初,我寫這篇文章是想不依賴于任何第三方包來實現RSA的加密與解密,然而后續遇到了問題。由于在加密方法encrypt和解密方法 decrypt中都要建立一個Cipher對象,這個對象只能通過getInstance來獲取實例。它有兩種:第一個是只指定算法,不指定提供者 Provider的;第二個是兩個都要指定的。起初沒有指定,代碼依然能夠跑通,但是你會發現,每次加密的結果都不一樣。后來分析才知道Cipher對象 使用的公私鑰是內部自己隨機生成的,不是代碼中指定的公私鑰。奇怪的是,這種不指定Provider的代碼能夠在android應用中跑通,而且每次加密 的結果都相同。我想,android的SDK中除了系統的一些開發函數外,自己也實現了JDK的功能,可能在它自己的JDK中已經提供了相應的 Provider,才使得每次加密結果相同。當我像網上的示例代碼那樣加入了bouncycastle的Provider后,果然每次加密的結果都相同了。

    ?

    參考文獻:

    RSA介紹:http://baike.baidu.com/view/7520.htm

    OpenSSL介紹:http://baike.baidu.com/view/300712.htm

    密鑰對生成:http://www.howforge.com/how-to-generate-key-pair-using-openssl

    私鑰編碼格式轉換:http://shuany.iteye.com/blog/730910

    JCE介紹:http://baike.baidu.com/view/1855103.htm

    總結

    以上是生活随笔為你收集整理的Java中使用OpenSSL生成的RSA公私钥进行数据加解密的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。