<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    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]明文大小:"+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]密文大小:"+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)

    相冊

    搜索

    積分與排名

    最新隨筆

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 丰满妇女做a级毛片免费观看| 亚洲av无码专区青青草原| a级片免费在线观看| 亚洲国产精品一区二区三区久久| 亚洲区日韩精品中文字幕| 99久久免费国产精品特黄| 亚洲免费观看网站| 在线v片免费观看视频| 久久久国产亚洲精品| 午夜一区二区免费视频| 国产成人人综合亚洲欧美丁香花| 成人av免费电影| 亚洲精品欧美综合四区| 成年人免费观看视频网站| 九九久久国产精品免费热6| 国产精品另类激情久久久免费| 亚洲手机中文字幕| 18禁成人网站免费观看| 亚洲AV电影院在线观看| 99在线免费视频| 亚洲av中文无码乱人伦在线r▽| 成人免费一区二区三区| 国产aⅴ无码专区亚洲av麻豆| 日韩在线视频免费| 区三区激情福利综合中文字幕在线一区亚洲视频1 | 亚洲精品V欧洲精品V日韩精品| 成人午夜免费视频| 国产国拍亚洲精品福利 | 久久精品亚洲男人的天堂| 久久影视国产亚洲| 一区二区三区视频免费| 亚洲欧洲中文日韩av乱码| 国产性生大片免费观看性| 亚洲无线码在线一区观看| a毛片免费全部在线播放**| 亚洲精品美女久久777777| 久久精品视频免费播放| 亚洲黄网在线观看| 永久黄网站色视频免费| 美女裸体无遮挡免费视频网站| a级亚洲片精品久久久久久久|