David.Turing's blog

           

          RSA使用簡述

          RSA協議我不再描述,大家可以看http://www.di-mgt.com.au/rsa_alg.html
          RSA的密鑰對生成時間依賴于兩個因素,
          第一,密鑰的長度
          第二,素數的篩選質量

          在整個密鑰對生成過程中,RSA會隨機選擇兩個大素數,事實上,計算機的聰明
          程度還不足以判斷某個隨機選擇的大素數是否真的不可分解,因此,你只能夠通過
          計算機程序來盡量將這個大隨機數不是素數的幾率降到某個界限值(如0.0001)以下。

          RSA KeyPair分為公鑰和私鑰,你應該這樣使用KeyPair:
          1,你使用私鑰來簽名,別人用你的公鑰來驗證簽名
          2,別人用你的公鑰加密信息M->M',你用私鑰來解密信息M'->M

          雖然RSA經受過多年深入的密碼分析,但大家在使用RSA的時候還是要注意以下事項,
          否則RSA的安全性會大打折扣:

          1,合理的密鑰長度(setKeyLength)
          RSA1024至今是安全的,按照目前密碼分析和計算機硬件條件的發展,估計在未來5-10年,
          仍以難以破解。

          2,素數確定性選擇(setCertaintyOfPrime)
          實際應用中,選擇100就行了。

          3,選擇合理的padding(setRSAMode)
          RSA有三種模式,RAW, PKCS和OAEP,日常應用中,我本人只使用PKCS(PKCS#1 v1.5)
          和OAEP(PKCS#1 v2.0)這兩種padding模式。
          padding跟安全性其實是緊密掛鉤的,有興趣的朋友可以看看PKCS#1標準討論。


          我編寫了一個RSAUtils的工具類,下面的該類的測試代碼的一部分。

          程序如下:
            RSAUtils utils =new RSAUtils();
            utils.setKeyLength(1024);
            utils.setCertaintyOfPrime(100);
            utils.setRSAMode(PKCS_RSA_MODE);   //RAW =1  PKCS=2  OAEP=3
            utils.initRSAKeyPair();
            
            //查看公鑰
            RSAKeyParameters mypubkey=utils.getPublicKey();
            BigInteger mypubkey_modulus=mypubkey.getModulus();  
            BigInteger mypubkey_exponent=mypubkey.getExponent();
            System.out.println("##mypubkey的modulus長度="+mypubkey_modulus.bitLength());
            System.out.println("##mypubkey_modulus值="+mypubkey_modulus.toString());
            System.out.println("##mypubkey的exponent長度="+mypubkey.getExponent().bitLength());
            System.out.println("##mypubkey_exponent值="+mypubkey_exponent.toString());

            //查看私鑰
            RSAKeyParameters myprivkey=utils.getPrivateKey();
            BigInteger myprivkey_modulus=myprivkey.getModulus();
            System.out.println("##myprivkey的modulus長度="+myprivkey_modulus.bitLength());
            System.out.println("##myprivkey的modulus值="+myprivkey_modulus.toString());
            System.out.println("##myprivkey.getExponent()長度="+myprivkey.getExponent().bitLength());
            System.out.println("##myprivkey.getExponent()值="+myprivkey.getExponent());

          以下是輸出:
          ##mypubkey的modulus長度=1024
          ##mypubkey_modulus值=93806062666699782638132820491933031482836826566660997927543724649365705443512121003172409185855121369631538039111403612211728268332662414248776212969019881724066055080327735965218365399595323200109436472147258110417469825748181131149217613806780318374365617984326523029965066348377550281908277056378455106547
          ##mypubkey的exponent長度=2
          ##mypubkey_exponent值=3

          ##myprivkey的modulus長度=1024
          ##myprivkey的modulus值=93806062666699782638132820491933031482836826566660997927543724649365705443512121003172409185855121369631538039111403612211728268332662414248776212969019881724066055080327735965218365399595323200109436472147258110417469825748181131149217613806780318374365617984326523029965066348377550281908277056378455106547
          ##myprivkey.getExponent()長度=1023
          ##myprivkey.getExponent()值=62537375111133188425421880327955354321891217711107331951695816432910470295674747335448272790570080913087692026074269074807818845555108276165850808646013241363962278455328383552959397735977285649455021534046301135296075808377308404258909132811288204167107604525033796313576612747649866739561523887875979483707

          其中,要記住,公鑰的exponent即RSA算法中的e, e通常是3,17和65537
          X.509建議使用65537,PEM建議使用3,PKCS#1建議使用3或65537,一般來說,都是選擇3。

          私鑰的Exponent就是私鑰中最重要的部分,它就是私鑰區別于公鑰的地方!

          接著,我們看看RSA的加密,解密過程。

          通常,不要隨便對某一個別人發過來的東西進行簽名(有潛在危險),即使有這樣的必要,請先將它的文件進行Digest或者HMAC
          處理后,再做簽名。
          為了說明RSA是如何加密信息的,我先讓大家脫離MD5/SHA1等輔助算法(沒有人會單獨使用RSA,RSAwithMD5,RSAwithSHA1才是常用的使用方法),來單獨看看RSA本身:

          大家習慣了DES/IDEA,再看RSA的加密,可能會有一些不習慣,因為RSA雖然也可以看成是基于Block的加密,但是,RSA的輸入和輸出的Block的大小是不一樣的,Block的大小依賴于你所使用的RSA Key的長度和RSA的padding模式。
          在RSAUtils測試用例中,分別對RSA設置三種長度的Key(768,1024,2048)和2種padding模式(PKCS 1.5和OAEP),結果如下:

          RSA                InBlock大小   OutBlock大小  (單位,字節)
          768bit/PKCS        85                96
          1024bit/PKCS     117               128
          2048bit/PKCS     245               256
          768bit/OAEP        54                96
          1024bit/OAEP     86               128
          2048bit/OAEP     214               256

          大家可以看到,相同密鑰長度, 加密出來的密文長度要比明文要長,且OAEP的InBlock/OutBlock要比PKCS的InBlock/OutBlock要小,單從熵的角度,意味著OAEP padding模式引入更多的熵,OAEP要比PKCS更安全(事實上,為何提出OAEP代替PKCS,大家可以到RSA網站看看OAEP文檔 http://www.rsasecurity.com/rsalabs/node.asp?id=2125)。


          下面,RSAUtils是我寫的針對BouncyCastle的一個工具類,它封裝了BouncyCastle的crypto中的RSAEngine,基本上,我很少單獨使用RSAUtils,我更多的是結合DiegestUtils來使用。

          posted on 2006-01-11 11:24 david.turing 閱讀(10486) 評論(4)  編輯  收藏 所屬分類: Security領域

          評論

          # re: RSA使用簡述 2006-09-28 13:22 aa

          hello  回復  更多評論   

          # re: RSA使用簡述 2007-11-02 18:33 robie

          大哥,能不能詳細解釋下PKCS#1 v1.5的簽名算法padding過程,我現在做了SHA1,得出結果為:ADABC0DC670987EF47B557FB1554A32DDD5B545E,然后還要padding別的東西在前面嗎?還是直接如下填充:
          0001ffff......ffff00ADABC0DC670987EF47B557FB1554A32DDD5B545E????
          先謝謝大哥了?。?!  回復  更多評論   

          # re: RSA使用簡述 2007-11-02 18:37 robie

          我的郵箱:robie◎126.com  回復  更多評論   

          # re: RSA使用簡述 2007-11-04 09:46 david.turing

          如果你使用了SHA1并對散列值進行RSA簽名、加密,則Padding的過程無需你本人去干預。
          或者你可以看看下面的代碼(RSAUtils.java):

          package org.dev2dev.security.crypto.Asymmetric;

          import java.io.BufferedInputStream;
          import java.io.BufferedOutputStream;
          import java.io.BufferedReader;
          import java.io.ByteArrayInputStream;
          import java.io.ByteArrayOutputStream;
          import java.io.FileInputStream;
          import java.io.FileNotFoundException;
          import java.io.FileOutputStream;
          import java.io.IOException;
          import java.io.InputStream;
          import java.io.InputStreamReader;
          import java.io.OutputStream;
          import java.math.BigInteger;
          import java.security.SecureRandom;

          import org.bouncycastle.crypto.AsymmetricBlockCipher;
          import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
          import org.bouncycastle.crypto.DataLengthException;
          import org.bouncycastle.crypto.encodings.OAEPEncoding;
          import org.bouncycastle.crypto.encodings.PKCS1Encoding;
          import org.bouncycastle.crypto.engines.DESEngine;
          import org.bouncycastle.crypto.engines.RSAEngine;
          import org.bouncycastle.crypto.generators.RSAKeyPairGenerator;
          import org.bouncycastle.crypto.params.RSAKeyGenerationParameters;
          import org.bouncycastle.crypto.params.RSAKeyParameters;
          import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
          import org.bouncycastle.util.encoders.Hex;
          import org.dev2dev.security.crypto.blockcipher.BlockCipherTool;


          /**
          * RSA工具類
          * @author david.turing
          * @copyright GuangZhou BEA Usergroup
          * @version 0.7
          * @modifyTime 22:30:34
          */
          public class RSAUtils {

          int keylength=1024;
          int certainty=20;
          RSAKeyGenerationParameters keyparam;
          AsymmetricBlockCipher eng = null;
          RSAKeyPairGenerator pGen = null;
          AsymmetricCipherKeyPair pair = null;

          public RSAUtils()
          {

          }

          public String getName()
          {
          return "RSA";
          }

          /**
          * 設置RSA的密鑰長度
          * @param rsakeylength
          */
          public void setKeyLength(int rsakeylength)
          {
          if(rsakeylength==512||rsakeylength==768||rsakeylength==1024||rsakeylength==2048)
          keylength=rsakeylength;
          }

          /**
          * 設置RSA Key Pair的素數產生經度,該數值越大,理論產生的RSA Key安全性越高
          * @param certaintyofprime
          */
          public void setCertaintyOfPrime(int certaintyofprime)
          {
          certainty=certaintyofprime;
          }

          /**
          * 生成RSA Keypair,如果你不是通過ImportPublicKey和ImportPrivateKey
          * 來導入密鑰對,則可通過此方法隨機生成。
          *
          * @return RSAKeyGenerationParameters
          */
          public void initRSAKeyPair()
          {
          /**
          * 注意, 第一個參數被寫死了,它是publicExponent, 即e
          * e通常選3,17,65537
          * X.509建議使用65537
          * PEM建議使用3
          * PKCS#1建議使用3或65537
          * 在本算法中,它使用了3,即0x3
          */
          RSAKeyGenerationParameters rsaparam=
          new RSAKeyGenerationParameters(BigInteger.valueOf(0x3),
          new SecureRandom(), this.keylength, this.certainty);
          this.keyparam = rsaparam;
          //RSA Keypair的生成依賴于rsaparam
          RSAKeyPairGenerator pGen = new RSAKeyPairGenerator();
          pGen.init(keyparam);
          pair = pGen.generateKeyPair();
          pair.getPublic();
          }

          /**
          * 設置RSA密鑰對,此方法用于從外部文件導入RSA密鑰對
          * @see ImportPublicKey(String)
          * @see ImportPrivateKey(String)
          * @param pubparam 公鑰
          * @param privparam 私鑰
          */
          public void setRSAKeyPair(RSAKeyParameters pubparam, RSAPrivateCrtKeyParameters privparam)
          {
          AsymmetricCipherKeyPair newpair=new AsymmetricCipherKeyPair(pubparam,privparam);
          pair=newpair;

          }

          /**
          * 該函數返回公鑰
          * @return
          */
          public RSAKeyParameters getPublicKey()
          {
          return (RSAKeyParameters)pair.getPublic();
          }

          /**
          * 該函數返回私鑰
          * 注意,RSAPrivateCrtKeyParameters其實繼承了RSAKeyParameters
          * @see getPublicKey()
          * @return
          */
          public RSAPrivateCrtKeyParameters getPrivateKey()
          {
          return (RSAPrivateCrtKeyParameters)pair.getPrivate();
          }

          /**
          * RSA的padding模式,安全性依次遞增
          * mode=1 RAW RSA 安全性最差
          * mode=2 PKCS1
          * mode=3 OAEP
          * @param mode
          */
          public void setRSAMode(int mode)
          {
          eng = new RSAEngine(); //默認就是RAW模式, 安全性問題,已不再使用
          if (mode==2)
          eng = new PKCS1Encoding(eng);
          else
          eng = new OAEPEncoding(eng); //mode==3
          }

          /**
          * 該RSAEngine的每次處理輸入數據,以Block為單位,是32Bytes
          * 因此,本函數的輸入要嚴格控制在32Byte,即256bit數據
          * 超出該長度會拋出異常。
          * 本函數要求輸入必須為16進制字符0-F。
          *
          * @see Decrypt(String input)
          * @param input
          * @return
          */
          public String encrypt(String input)
          {

          byte[] inputdata=Hex.decode(input);

          //用公鑰加密
          eng.init(true, pair.getPublic());

          System.out.println(">>>加密參數");
          System.out.println(">>>明文字節數:"+inputdata.length);
          System.out.println(">>>RSA Engine Input Block Size="+this.eng.getInputBlockSize());
          System.out.println(">>>RSA Engine Output Block Size="+this.eng.getOutputBlockSize());

          try
          {
          inputdata = eng.processBlock(inputdata, 0, inputdata.length);
          }
          catch (Exception e)
          {
          e.printStackTrace();
          }

          return new String(Hex.encode(inputdata));
          }

          /**
          * 該函數輸入為字節,并規定其長度為32字節
          * 超出該長度會拋出異常
          * @see Decrypt(byte[] inputdata)
          * @param inputdata
          * @return
          */
          public byte[] encrypt(byte[] inputdata)
          {
          byte[] outputdata=null;

          //用公鑰加密
          eng.init(true, pair.getPublic());

          try
          {
          inputdata = eng.processBlock(inputdata, 0, inputdata.length);
          outputdata=new byte[eng.getOutputBlockSize()];
          outputdata=inputdata;
          }
          catch (Exception e)
          {
          e.printStackTrace();
          }

          return outputdata;
          }


          /**
          * 加密ByteArrayInputStream流,在該方法中,會對input做分段處理,每段都將會
          * 以inBlockSize來劃分明文,密文同樣會設置換行,因此,將來在加密過程中,密文
          * 需要分行讀入,在明文、密文,唯一對應的是inBlock和outBlock,它們是換行對應的。
          *
          * 本函數已經處理結尾Block問題
          * @param input
          * @param Key
          * @return
          */
          public byte[] encryptPro(byte[] inputload)
          {
          ByteArrayInputStream inputstream=new ByteArrayInputStream(inputload);
          ByteArrayOutputStream outputstream=new ByteArrayOutputStream();


          //用公鑰加密
          eng.init(true, pair.getPublic());

          int inBlockSize =this.eng.getInputBlockSize() ;
          int outBlockSize = this.eng.getOutputBlockSize();

          try {
          System.out.println("加密的 InBlockSize="+inBlockSize);
          System.out.println("加密的outBlockSize="+outBlockSize);

          encryptPro(inputstream, outputstream);

          } catch (DataLengthException e) {
          e.printStackTrace();
          } catch (IllegalStateException e) {
          e.printStackTrace();
          } catch(Exception e){
          e.printStackTrace();
          }

          byte[] outputload=outputstream.toByteArray();


          System.out.println("###[1]明文大?。?quot;+inputload.length);
          System.out.println("###[1]密文大小:"+outputload.length);

          return outputload;
          }

          /**
          * 加密BufferedInputStream流,在該方法中,會對input做分段處理,每段都將會
          * 以inBlockSize來劃分明文,密文同樣會設置換行,因此,將來在加密過程中,密文
          * 需要分行讀入,在明文、密文,唯一對應的是inBlock和outBlock,它們是換行對應的。
          *
          *此函數未處理padding,如果你不想自己調整padding,請用encryptPro
          *@see encryptPro(BufferedInputStream inputstream,BufferedOutputStream outputstream)
          *
          * @param input
          * @param Key
          * @return
          */
          public void encrypt(BufferedInputStream inputstream,BufferedOutputStream outputstream)
          {
          //用公鑰加密
          eng.init(true, pair.getPublic());

          int inBlockSize =this.eng.getInputBlockSize() ;
          int outBlockSize = this.eng.getOutputBlockSize();

          byte[] inblock = new byte[inBlockSize];
          byte[] outblock = new byte[outBlockSize];

          byte[] rv = null;
          try {
          while (inputstream.read(inblock, 0, inBlockSize) > 0)
          {
          outblock = eng.processBlock(inblock, 0, inBlockSize);
          rv = Hex.encode(outblock, 0, outBlockSize);
          outputstream.write(rv, 0, rv.length);
          outputstream.write('\n');

          }

          } catch (DataLengthException e) {
          e.printStackTrace();
          } catch (IllegalStateException e) {
          e.printStackTrace();
          } catch(Exception e){
          e.printStackTrace();
          }

          }


          /**
          * 加密BufferedInputStream流,在該方法中,會對input做分段處理,每段都將會
          * 以inBlockSize來劃分明文,密文同樣會設置換行,因此,將來在加密過程中,密文
          * 需要分行讀入,在明文、密文,唯一對應的是inBlock和outBlock,它們是換行對應的。
          *
          * 該函數會在加密文件的頭部注明padding_size
          * padding_size即padding_size即明文流按照inBlockSize劃分后
          * 最后一個block的未占滿的大小(字節數)
          *
          * @param input
          * @param Key
          * @return
          */
          public void encryptPro(InputStream inputstream,OutputStream outputstream)
          {
          //用公鑰加密
          eng.init(true, pair.getPublic());

          int inBlockSize =this.eng.getInputBlockSize() ;
          int outBlockSize = this.eng.getOutputBlockSize();

          byte[] inblock = new byte[inBlockSize];
          byte[] outblock = new byte[outBlockSize];


          byte[] rv = null;

          try {

          //System.out.println("stream length="+inputstream.available());
          int padding_size=inBlockSize-(inputstream.available() % inBlockSize);
          //System.out.println("padding_size="+padding_size);

          /*寫入padding_size,處理最后一個Block不夠inBlockSize的情況
          * 記住不要自己修改inBlockSize,因為RSA共有三種模式,每種模式
          * 對Padding的處理方式都不一樣,所以,不要修改對processBlock
          * 的加密解密方式??傊?,不要修改RSA的inBlock!
          */
          outputstream.write((padding_size+"").getBytes());
          outputstream.write('\n');

          while (inputstream.read(inblock, 0, inBlockSize) > 0)
          {
          outblock = eng.processBlock(inblock, 0, inBlockSize);
          rv = Hex.encode(outblock, 0, outBlockSize);

          //System.out.println("Hex len="+rv.length);
          outputstream.write(rv, 0, rv.length);

          outputstream.write('\n');
          }

          } catch (DataLengthException e) {
          e.printStackTrace();
          } catch (IllegalStateException e) {
          e.printStackTrace();
          } catch(Exception e){
          e.printStackTrace();
          }

          }

          /**
          * 解密字符串
          * @param input
          * @return
          */
          public String decrypt(String input)
          {

          byte[] inputdata=Hex.decode(input);

          eng.init(false,pair.getPrivate());
          System.out.println(">>>加密參數");
          System.out.println(">>>RSA Engine Input Block Size="+this.eng.getInputBlockSize());
          System.out.println(">>>RSA Engine Output Block Size="+this.eng.getOutputBlockSize());

          try
          {
          inputdata=eng.processBlock(inputdata,0,inputdata.length);
          }
          catch(Exception e)
          {
          e.printStackTrace();
          }

          return new String(Hex.encode(inputdata));

          }

          /**
          * 解密字節數組
          * @param inputdata
          * @return
          */
          public byte[] decrypt(byte[] inputdata)
          {
          byte[] outputdata=null;

          //用公鑰加密
          eng.init(false, pair.getPrivate());

          try
          {
          inputdata = eng.processBlock(inputdata, 0, inputdata.length);
          outputdata=new byte[eng.getOutputBlockSize()];
          outputdata=inputdata;
          }
          catch (Exception e)
          {
          e.printStackTrace();
          }

          return outputdata;
          }

          /**
          * 解密流
          *
          * 本函數已經處理結尾Block問題
          * @see encryptPro(byte[] inputload)
          *
          * @param inputstream 被加密過的流
          * @param outputstream 解密輸出的流
          */
          public byte[] decryptPro(byte[] inputload)
          {

          ByteArrayInputStream inputstream=new ByteArrayInputStream(inputload);
          ByteArrayOutputStream outputstream=new ByteArrayOutputStream();

          //設置引擎
          eng.init(false, pair.getPrivate());

          int inBlockSize =this.eng.getInputBlockSize() ;
          int outBlockSize = this.eng.getOutputBlockSize();

          try {
          System.out.println("解密的In BlockSize="+inBlockSize);
          System.out.println("解密的out BlockSize="+outBlockSize);

          this.decryptPro(inputstream, outputstream);
          } catch (DataLengthException e) {
          e.printStackTrace();
          } catch (IllegalStateException e) {
          e.printStackTrace();
          }
          catch(Exception e)
          {
          e.printStackTrace();
          }

          //System.out.println("解密。。。outputload="+new String(outputload));

          //byte[] outputload=new byte[outputstream.size()];
          byte[] outputload=outputstream.toByteArray();

          System.out.println("###[2]密文大?。?quot;+inputload.length);
          System.out.println("###[2]明文大小:"+outputload.length);

          return outputload;
          }



          /**
          * 解密RSA流,首先先讀取RSA的流的padding_size(第一行)
          *
          * @param inputstream 被加密過的流
          * @param outputstream 解密輸出的流
          */
          public void decryptPro(InputStream inputstream, OutputStream outputstream)
          {
          //設置引擎
          eng.init(false, pair.getPrivate());

          BufferedReader br = new BufferedReader(new InputStreamReader(inputstream));

          int inBlockSize =this.eng.getInputBlockSize() ;
          int outBlockSize = this.eng.getOutputBlockSize();

          int lines;

          byte[] outblock = new byte[outBlockSize];

          String rv = null;
          int inL=0;
          byte[] last=null;

          try {
          int amout=inputstream.available();
          lines=amout/(inBlockSize*2);
          //System.out.println("lines="+lines);
          rv=br.readLine();

          //System.out.println("#########padding size="+rv);
          int padding_size=Integer.parseInt(rv);

          while ((rv = br.readLine()) != null)
          {
          lines--;
          /* 要注意,Hex處理密文是將每個byte用2個16進制表示
          * 一個Hex碼其實只需4bit來表示,一個byte有8bit,因此
          * 需要2個Hex碼表示,所以,一個字符經Hex Encode會
          * 變成兩個Hex字符。
          */
          inL=rv.length()/2;
          last=new byte[inL];
          last = Hex.decode(rv);

          outblock = eng.processBlock(last, 0, inBlockSize);

          if(lines>0)
          {
          outputstream.write(outblock, 0, outBlockSize);
          }
          else
          outputstream.write(outblock, 0, outBlockSize-padding_size);

          }

          } catch (DataLengthException e) {
          e.printStackTrace();
          } catch (IllegalStateException e) {
          e.printStackTrace();
          }
          catch(Exception e)
          {
          e.printStackTrace();
          }

          }

          /**
          * 輸出公鑰到文件
          * @param Filename
          */
          public void ExportPublicKey(String Filename)
          {
          String outfile = Filename;
          BufferedOutputStream outstream = null;

          try
          {
          outstream = new BufferedOutputStream(new FileOutputStream(outfile));
          }
          catch (IOException fnf)
          {
          System.err.println("無法創建公鑰文件 ["+outfile+"]");
          System.exit(1);
          }


          RSAKeyParameters mypubkey=this.getPublicKey();
          BigInteger mypubkey_modulus=mypubkey.getModulus();
          BigInteger mypubkey_exponent=mypubkey.getExponent();
          System.out.println("[ExportPublicKey]mypubkey_modulus="+mypubkey_modulus.toString());
          System.out.println("[ExportPublicKey]mypubkey_exponent="+mypubkey_exponent);

          try
          {
          outstream.write(mypubkey_modulus.toString().getBytes());
          outstream.write('\n');
          outstream.write(mypubkey_exponent.toString().getBytes());
          outstream.flush();
          outstream.close();
          }
          catch (IOException closing)
          {
          closing.printStackTrace();
          }
          System.out.println("公鑰輸出到文件:"+Filename);

          }

          /**
          * 從文件中導入公鑰到內存
          * @param Filename
          * @return
          */
          public RSAKeyParameters ImportPublicKey(String Filename)
          {
          String infile = Filename;
          BufferedInputStream instream = null;
          RSAKeyParameters RSAParam=null;
          try
          {
          instream = new BufferedInputStream(new FileInputStream(infile));
          }
          catch (FileNotFoundException fnf)
          {
          System.err.println("公鑰文件沒有找到 ["+infile+"]");
          System.exit(1);
          }

          BufferedReader br = new BufferedReader(new InputStreamReader(instream));
          BigInteger mypubkey_modulus=null;
          BigInteger mypubkey_exponent=null;
          String readstr=null;

          try {

          readstr = br.readLine();

          mypubkey_modulus= new BigInteger(readstr);
          System.out.println("[ImportPublicKey]mypubkey_modulus="+mypubkey_modulus.toString());

          readstr = br.readLine();
          mypubkey_exponent=new BigInteger(readstr);
          System.out.println("[ImportPublicKey]mypubkey_exponent="+mypubkey_exponent);

          RSAParam=new RSAKeyParameters(false,mypubkey_modulus,mypubkey_exponent);

          } catch (DataLengthException e) {
          e.printStackTrace();
          } catch (IllegalStateException e) {
          e.printStackTrace();
          }
          catch(Exception e)
          {
          e.printStackTrace();
          }
          return RSAParam;

          }

          /**
          * 輸出私鑰到指定的文件
          * @param Filename
          */
          public void ExportPrivateKey(String Filename)
          {

          String outfile = Filename;
          BufferedOutputStream outstream = null;

          try
          {
          outstream = new BufferedOutputStream(new FileOutputStream(outfile));
          }
          catch (IOException fnf)
          {
          System.err.println("輸出文件無法創建 ["+outfile+"]");
          System.exit(1);
          }


          RSAPrivateCrtKeyParameters myprivkey=this.getPrivateKey();

          BigInteger myprivkey_modulus=myprivkey.getModulus();
          BigInteger myprivkey_exponent=myprivkey.getExponent();
          BigInteger e=myprivkey.getPublicExponent(); //e is public
          BigInteger dP=myprivkey.getDP();
          BigInteger dQ=myprivkey.getDQ();
          BigInteger p=myprivkey.getP();
          BigInteger q=myprivkey.getQ();
          BigInteger qInv=myprivkey.getQInv();


          try
          {
          outstream.write(myprivkey_modulus.toString().getBytes());
          outstream.write('\n');
          outstream.write(e.toString().getBytes());
          outstream.write('\n');
          outstream.write(myprivkey_exponent.toString().getBytes());
          outstream.write('\n');
          outstream.write(p.toString().getBytes());
          outstream.write('\n');
          outstream.write(q.toString().getBytes());
          outstream.write('\n');
          outstream.write(dP.toString().getBytes());
          outstream.write('\n');
          outstream.write(dQ.toString().getBytes());
          outstream.write('\n');
          outstream.write(qInv.toString().getBytes());
          outstream.write('\n');

          outstream.flush();
          outstream.close();
          }
          catch (IOException closing)
          {
          closing.printStackTrace();
          }
          System.out.println("私鑰輸出到文件:"+Filename);

          }

          /**
          * 輸出私鑰到指定的文件,私鑰經過密碼加密
          * 強烈建議在生產環境中使用此方法而不要使用
          * ExportPrivateKey(String Filename)
          *
          * @param Filename 私鑰文件
          * @param Password 私鑰的保護密碼
          */
          public void ExportPrivateKeyWithPass(String Filename, String Password)
          {

          String outfile = Filename;

          ByteArrayOutputStream outstream=null;
          BufferedOutputStream keyoutstream=null;
          //借助BlockCipherTool來加密私鑰
          BlockCipherTool cipherTool=new BlockCipherTool();

          //暫時使用DES加密私鑰
          //cipherTool.setEngine(new AESEngine());
          //cipherTool.setEngine(new IDEAEngine());
          cipherTool.setEngine(new DESEngine());
          //cipherTool.setEngine(new BlowfishEngine());

          //cipherTool.setKeyLength(64); //AES 32(Hex)*4=128bit
          //String keyStr="123456789012345678901234567890FF"; //16進制 128bit AES Key
          //String keyStr="123456789012345678901234567890FF123456789012345678901234567890FF"; //16進制 256bit AES Key
          //String keyStr="123456789012345678901234567890FF"; //16進制 128bit IDEA Key
          //String keyStr="0123456789abcdef"; //16進制 64bit(56) DES Key
          //String keyStr="0123456789ABCDEF"; //16進制 64bit(56) Blowfish Key


          outstream = new ByteArrayOutputStream();
          try
          {
          keyoutstream = new BufferedOutputStream(new FileOutputStream(outfile));

          }
          catch (Exception fnf)
          {
          System.err.println("輸出文件無法創建 ["+outfile+"]");
          System.exit(1);
          }


          RSAPrivateCrtKeyParameters myprivkey=this.getPrivateKey();

          BigInteger myprivkey_modulus=myprivkey.getModulus();
          BigInteger myprivkey_exponent=myprivkey.getExponent();
          BigInteger e=myprivkey.getPublicExponent(); //e is public
          BigInteger dP=myprivkey.getDP();
          BigInteger dQ=myprivkey.getDQ();
          BigInteger p=myprivkey.getP();
          BigInteger q=myprivkey.getQ();
          BigInteger qInv=myprivkey.getQInv();


          try
          {
          // 產生正確的私鑰流
          outstream.write(myprivkey_modulus.toString().getBytes());
          outstream.write('\n');
          outstream.write(e.toString().getBytes());
          outstream.write('\n');
          outstream.write(myprivkey_exponent.toString().getBytes());
          outstream.write('\n');
          outstream.write(p.toString().getBytes());
          outstream.write('\n');
          outstream.write(q.toString().getBytes());
          outstream.write('\n');
          outstream.write(dP.toString().getBytes());
          outstream.write('\n');
          outstream.write(dQ.toString().getBytes());
          outstream.write('\n');
          outstream.write(qInv.toString().getBytes());
          outstream.write('\n');


          byte[] privatekey_withtoutpass=outstream.toByteArray();

          ByteArrayInputStream keyinstream=new ByteArrayInputStream(privatekey_withtoutpass);

          //加密私鑰
          cipherTool.init(true,Password);
          //將outstream轉型成keyinstream,將keyinstream執行DES加密
          cipherTool.Encrypt(keyinstream,keyoutstream);

          keyinstream.close();
          keyoutstream.flush();
          keyoutstream.close();


          }
          catch (IOException closing)
          {
          closing.printStackTrace();
          }

          System.out.println("私鑰經過加密并輸出到文件:"+Filename);

          }

          /**
          * 從某個文件中導入私鑰,假定私鑰未被加密
          * @see ExportPrivateKey(String Filename)
          * @param Filename
          * @return
          */
          public RSAPrivateCrtKeyParameters ImportPrivateKey(String Filename)
          {
          String infile = Filename;
          BufferedInputStream instream = null;
          RSAPrivateCrtKeyParameters RSAPrivParam=null;

          try
          {
          instream = new BufferedInputStream(new FileInputStream(infile));
          }
          catch (FileNotFoundException fnf)
          {
          System.err.println("私鑰文件沒有找到 ["+infile+"]");
          System.exit(1);
          }

          BufferedReader br = new BufferedReader(new InputStreamReader(instream));


          BigInteger myprivkey_modulus=null;
          BigInteger myprivkey_exponent=null;
          BigInteger e=null;
          BigInteger p=null;
          BigInteger q=null;
          BigInteger dP=null;
          BigInteger dQ=null;
          BigInteger qInv=null;

          String readstr=null;
          try {

          readstr = br.readLine();
          myprivkey_modulus= new BigInteger(readstr);
          readstr = br.readLine();
          e= new BigInteger(readstr);
          readstr = br.readLine();
          myprivkey_exponent= new BigInteger(readstr);
          readstr = br.readLine();
          p= new BigInteger(readstr);
          readstr = br.readLine();
          q= new BigInteger(readstr);
          readstr = br.readLine();
          dP= new BigInteger(readstr);
          readstr = br.readLine();
          dQ= new BigInteger(readstr);
          readstr = br.readLine();
          qInv= new BigInteger(readstr);


          RSAPrivParam=new RSAPrivateCrtKeyParameters(myprivkey_modulus, myprivkey_exponent,
          e,p,q,dP,dQ,qInv);

          } catch (DataLengthException ex) {
          ex.printStackTrace();
          } catch (IllegalStateException ex) {
          ex.printStackTrace();
          }
          catch(Exception ex)
          {
          ex.printStackTrace();
          }
          return RSAPrivParam;

          }

          /**
          * 從私鑰文件中導入私鑰,并用保護密碼通過DES解密該私鑰
          * 放入內存,該方法跟ExportPrivateKeyWithPass 對應
          *
          * @see ExportPrivateKeyWithPass(String Filename, String Password)
          * @param Filename
          * @param Password
          * @return
          */
          public RSAPrivateCrtKeyParameters ImportPrivateKeyWithPass(String Filename,String Password)
          {
          String infile = Filename;
          InputStream instream = null;

          ByteArrayInputStream keyinstream =null;
          ByteArrayOutputStream keyoutstream = new ByteArrayOutputStream();

          //借助BlockCipherTool來加密私鑰
          BlockCipherTool cipherTool=new BlockCipherTool();

          //暫時使用DES加密私鑰
          //cipherTool.setEngine(new AESEngine());
          //cipherTool.setEngine(new IDEAEngine());
          cipherTool.setEngine(new DESEngine());
          //cipherTool.setEngine(new BlowfishEngine());

          //cipherTool.setKeyLength(64); //AES 32(Hex)*4=128bit
          //String keyStr="123456789012345678901234567890FF"; //16進制 128bit AES Key
          //String keyStr="123456789012345678901234567890FF123456789012345678901234567890FF"; //16進制 256bit AES Key
          //String keyStr="123456789012345678901234567890FF"; //16進制 128bit IDEA Key
          //String keyStr="0123456789abcdef"; //16進制 64bit(56) DES Key
          //String keyStr="0123456789ABCDEF"; //16進制 64bit(56) Blowfish Key


          RSAPrivateCrtKeyParameters RSAPrivParam=null;
          try
          {
          instream = new BufferedInputStream(new FileInputStream(infile));
          }
          catch (FileNotFoundException fnf)
          {
          System.err.println("私鑰文件沒有找到 ["+infile+"]");
          System.exit(1);
          }

          cipherTool.init(false,Password);

          //keyinstream-->ByteArrayOutputStream,將keyinstream執行DES加密
          cipherTool.Decrypt(instream,keyoutstream);

          byte[] privatekey_withtoutpass=keyoutstream.toByteArray();

          keyinstream=new ByteArrayInputStream(privatekey_withtoutpass);



          BigInteger myprivkey_modulus=null;
          BigInteger myprivkey_exponent=null;
          BigInteger e=null;
          BigInteger p=null;
          BigInteger q=null;
          BigInteger dP=null;
          BigInteger dQ=null;
          BigInteger qInv=null;

          String readstr=null;
          try {

          BufferedReader br = new BufferedReader(new InputStreamReader(keyinstream));

          readstr = br.readLine();
          myprivkey_modulus= new BigInteger(readstr);
          readstr = br.readLine();
          e= new BigInteger(readstr);
          readstr = br.readLine();
          myprivkey_exponent= new BigInteger(readstr);
          readstr = br.readLine();
          p= new BigInteger(readstr);
          readstr = br.readLine();
          q= new BigInteger(readstr);
          readstr = br.readLine();
          dP= new BigInteger(readstr);
          readstr = br.readLine();
          dQ= new BigInteger(readstr);
          readstr = br.readLine();
          qInv= new BigInteger(readstr);


          RSAPrivParam=new RSAPrivateCrtKeyParameters(myprivkey_modulus, myprivkey_exponent,
          e,p,q,dP,dQ,qInv);


          keyinstream.close();
          keyoutstream.flush();
          keyoutstream.close();

          } catch (DataLengthException ex) {
          ex.printStackTrace();
          } catch (IllegalStateException ex) {
          ex.printStackTrace();
          }
          catch(Exception ex)
          {
          ex.printStackTrace();
          }

          return RSAPrivParam;

          }

          /**
          * 為一個Block清0
          * @param block
          */
          public void reset(byte[] block)
          {
          for(int i=0;i<block.length;i++)
          block[i]=(byte)0;
          }

          /**
          * 將某個Block自off后的字節清0
          * @param block
          * @param off
          */
          public void padding(byte[] block, int off)
          {
          for(int i=off;i<block.length;i++)
          block[i]=(byte)0;
          }


          }
            回復  更多評論   

          導航

          統計

          常用鏈接

          留言簿(110)

          我參與的團隊

          隨筆分類(126)

          隨筆檔案(155)

          文章分類(9)

          文章檔案(19)

          相冊

          搜索

          積分與排名

          最新隨筆

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 汶上县| 朝阳县| 颍上县| 综艺| 佛坪县| 民丰县| 临澧县| 读书| 广昌县| 禄丰县| 太原市| 临邑县| 柯坪县| 久治县| 镶黄旗| 尚义县| 依安县| 伊春市| 临海市| 公主岭市| 仪征市| 卢龙县| 汽车| 富源县| 贡嘎县| 浮梁县| 闵行区| 东丽区| 大埔区| 信阳市| 南皮县| 田东县| 石家庄市| 水城县| 永新县| 西充县| 山阴县| 宿松县| 东明县| 仁布县| 元朗区|