隨筆 - 303  文章 - 883  trackbacks - 0
          <2007年3月>
          25262728123
          45678910
          11121314151617
          18192021222324
          25262728293031
          1234567

          歡迎光臨! 
          閑聊 QQ:1074961813

          隨筆分類(357)

          我管理的群

          公共blog

          • n維空間
          • Email : java3d@126.com 群 : 12999758

          參與管理的論壇

          好友的blog

          我的其他blog

          朋友的網(wǎng)站

          搜索

          •  

          最新評論

          MD5/SHA1,DSA,DESede/DES,Diffie-Hellman的使用

          王輝 (ddxxkk@21cn.com),

          2001 年 7 月 04 日

          通常,使用的加密算法 比較簡便高效,密鑰簡短,加解密速度快,破譯極其困難。本文介紹了 MD5/SHA1,DSA,DESede/DES,Diffie-Hellman的使用。

          第1章? 基礎(chǔ)知識


          1.1. 單鑰密碼體制

          單鑰密碼體制是一種傳統(tǒng)的加密算法,是指信息的發(fā)送方和接收方共同使用同一把密鑰進行加解密。

          通常,使用的加密算法比較簡便高效,密鑰簡短,加解密速度快,破譯極其困難。但是加密的安全性依靠密鑰保管的安全性,在公開的計算機網(wǎng)絡(luò)上安全地傳送和保管密鑰是一個嚴峻的問題,并且如果在多用戶的情況下密鑰的保管安全性也是一個問題。

          單鑰密碼體制的代表是美國的DES

          1.2. 消息摘要

          一個消息摘要就是一個數(shù)據(jù)塊的數(shù)字指紋。即對一個任意長度的一個數(shù)據(jù)塊進行計算,產(chǎn)生一個唯一指印(對于SHA1是產(chǎn)生一個20字節(jié)的二進制數(shù)組)。

          消息摘要有兩個基本屬性:

          • 兩個不同的報文難以生成相同的摘要
          • 難以對指定的摘要生成一個報文,而由該報文反推算出該指定的摘要

          代表:美國國家標(biāo)準(zhǔn)技術(shù)研究所的SHA1和麻省理工學(xué)院Ronald Rivest提出的MD5

          1.3. Diffie-Hellman密鑰一致協(xié)議

          密鑰一致協(xié)議是由公開密鑰密碼體制的奠基人Diffie和Hellman所提出的一種思想。

          先決條件,允許兩名用戶在公開媒體上交換信息以生成"一致"的,可以共享的密鑰

          代表:指數(shù)密鑰一致協(xié)議(Exponential Key Agreement Protocol)

          1.4. 非對稱算法與公鑰體系

          1976年,Dittie和Hellman為解決密鑰管理問題,在他們的奠基性的工作"密碼學(xué)的新方向"一文中,提出一種密鑰交換協(xié)議,允許在不安全的媒體上通過通訊雙方交換信息,安全地傳送秘密密鑰。在此新思想的基礎(chǔ)上,很快出現(xiàn)了非對稱密鑰密碼體制,即公鑰密碼體制。在公鑰體制中,加密密鑰不同于解密密鑰,加密密鑰公之于眾,誰都可以使用;解密密鑰只有解密人自己知道。它們分別稱為公開密鑰(Public key)和秘密密鑰(Private key)。

          迄今為止的所有公鑰密碼體系中,RSA系統(tǒng)是最著名、最多使用的一種。RSA公開密鑰密碼系統(tǒng)是由R.Rivest、A.Shamir和L.Adleman俊教授于1977年提出的。RSA的取名就是來自于這三位發(fā)明者的姓的第一個字母

          1.5. 數(shù)字簽名

          所謂數(shù)字簽名就是信息發(fā)送者用其私鑰對從所傳報文中提取出的特征數(shù)據(jù)(或稱數(shù)字指紋)進行RSA算法操作,以保證發(fā)信人無法抵賴曾發(fā)過該信息(即不可抵賴性),同時也確保信息報文在經(jīng)簽名后末被篡改(即完整性)。當(dāng)信息接收者收到報文后,就可以用發(fā)送者的公鑰對數(shù)字簽名進行驗證。 

          在數(shù)字簽名中有重要作用的數(shù)字指紋是通過一類特殊的散列函數(shù)(HASH函數(shù))生成的,對這些HASH函數(shù)的特殊要求是:

          1. 接受的輸入報文數(shù)據(jù)沒有長度限制;
          2. 對任何輸入報文數(shù)據(jù)生成固定長度的摘要(數(shù)字指紋)輸出
          3. 從報文能方便地算出摘要;
          4. 難以對指定的摘要生成一個報文,而由該報文反推算出該指定的摘要;
          5. 兩個不同的報文難以生成相同的摘要

          代表:DSA


          第2章? 在JAVA中的實現(xiàn)


          2.1. 相關(guān)

          Diffie-Hellman密鑰一致協(xié)議和DES程序需要JCE工具庫的支持,可以到 http://java.sun.com/security/index.html 下載JCE,并進行安裝。簡易安裝把 jce1.2.1\lib 下的所有內(nèi)容復(fù)制到 %java_home%\lib\ext下,如果沒有ext目錄自行建立,再把jce1_2_1.jar和sunjce_provider.jar添加到CLASSPATH內(nèi),更詳細說明請看相應(yīng)用戶手冊

          2.2. 消息摘要MD5和SHA的使用

          使用方法:

          首先用生成一個MessageDigest類,確定計算方法

          java.security.MessageDigest alga=java.security.MessageDigest.getInstance("SHA-1");

          添加要進行計算摘要的信息

          alga.update(myinfo.getBytes());

          計算出摘要

          byte[] digesta=alga.digest();

          發(fā)送給其他人你的信息和摘要

          其他人用相同的方法初始化,添加信息,最后進行比較摘要是否相同

          algb.isEqual(digesta,algb.digest())

          相關(guān)AIP

          java.security.MessageDigest 類

          static getInstance(String algorithm)

          返回一個MessageDigest對象,它實現(xiàn)指定的算法

          參數(shù):算法名,如 SHA-1 或MD5

          void update (byte input)

          void update (byte[] input)

          void update(byte[] input, int offset, int len)

          添加要進行計算摘要的信息

          byte[] digest()

          完成計算,返回計算得到的摘要(對于MD5是16位,SHA是20位)

          void reset()

          復(fù)位

          static boolean isEqual(byte[] digesta, byte[] digestb)

          比效兩個摘要是否相同

          代碼:

          import ?java.security. * ;
          public ? class ?myDigest? {
          ??
          public ? static ? void ?main(String[]?args)?? {
          ????myDigest?my
          = new ?myDigest();
          ????my.testDigest();
          ??}

          ??
          public ? void ?testDigest()
          ??
          {
          ???
          try ? {
          ?????String?myinfo
          = " 我的測試信息 " ;
          ????
          // java.security.MessageDigest?alg=java.security.MessageDigest.getInstance("MD5");
          ??????java.security.MessageDigest?alga = java.security.MessageDigest.getInstance( " SHA-1 " );
          ??????alga.update(myinfo.getBytes());
          ??????
          byte []?digesta = alga.digest();
          ??????System.out.println(
          " 本信息摘要是: " + byte2hex(digesta));
          ??????
          // 通過某中方式傳給其他人你的信息(myinfo)和摘要(digesta)?對方可以判斷是否更改或傳輸正常
          ??????java.security.MessageDigest?algb = java.security.MessageDigest.getInstance( " SHA-1 " );
          ??????algb.update(myinfo.getBytes());
          ??????
          if ?(algb.isEqual(digesta,algb.digest()))? {
          ?????????System.out.println(
          " 信息檢查正常 " );
          ???????}

          ???????
          else
          ????????
          {
          ??????????System.out.println(
          " 摘要不相同 " );
          ?????????}

          ???}

          ???
          catch ?(java.security.NoSuchAlgorithmException?ex)? {
          ?????System.out.println(
          " 非法摘要算法 " );
          ???}

          ??}

          ??
          public ?String?byte2hex( byte []?b)? // 二行制轉(zhuǎn)字符串
          ???? {
          ?????String?hs
          = "" ;
          ?????String?stmp
          = "" ;
          ?????
          for ?( int ?n = 0 ;n < b.length;n ++ )
          ??????
          {
          ???????stmp
          = (java.lang.Integer.toHexString(b[n]? & ? 0XFF ));
          ???????
          if ?(stmp.length() == 1 )?hs = hs + " 0 " + stmp;
          ???????
          else ?hs = hs + stmp;
          ???????
          if ?(n < b.length - 1 )??hs = hs + " : " ;
          ??????}

          ?????
          return ?hs.toUpperCase();
          ????}

          }

          2.3. 數(shù)字簽名DSA

          1. 對于一個用戶來講首先要生成他的密鑰對,并且分別保存

            生成一個KeyPairGenerator實例

          java.security.KeyPairGenerator??keygen = java.security.KeyPairGenerator.getInstance( " DSA " );
          ????如果設(shè)定隨機產(chǎn)生器就用如相代碼初始化
          ?????SecureRandom?secrand
          = new ?SecureRandom();
          ?????secrand.setSeed(
          " tttt " .getBytes());? // 初始化隨機產(chǎn)生器
          ?????keygen.initialize( 512 ,secrand);????? // 初始化密鑰生成器
          ????否則
          ?????keygen.initialize(
          512 );
          ????生成密鑰公鑰pubkey和私鑰prikey
          ??????KeyPair?keys
          = keygen.generateKeyPair();? // 生成密鑰組
          ??????PublicKey?pubkey = keys.getPublic();
          ??????PrivateKey?prikey
          = keys.getPrivate();
          ????分別保存在myprikey.dat和mypubkey.dat中,以便下次不在生成
          ????(生成密鑰對的時間比較長
          ?????java.io.ObjectOutputStream?out
          = new ?java.io.ObjectOutputStream( new ?java.io.FileOutputStream( " myprikey.dat " ));
          ?????out.writeObject(prikey);
          ?????out.close();
          ?????out
          = new ?java.io.ObjectOutputStream( new ?java.io.FileOutputStream( " mypubkey.dat " ));
          ?????out.writeObject(pubkey);
          ?????out.close();

          2.用他私人密鑰(prikey)對他所確認的信息(info)進行數(shù)字簽名產(chǎn)生一個簽名數(shù)組

          從文件中讀入私人密鑰(prikey)

          java.io.ObjectInputStream?in = new ?java.io.ObjectInputStream( new ?java.io.FileInputStream( " myprikey.dat " ));
          ????PrivateKey?myprikey
          = (PrivateKey)in.readObject();
          ????in.close();
          ????初始一個Signature對象,并用私鑰對信息簽名
          ?????java.security.Signature?signet
          = java.security.Signature.getInstance( " DSA " );
          ?????signet.initSign(myprikey);
          ?????signet.update(myinfo.getBytes());
          ?????
          byte []?signed = signet.sign();
          ????把信息和簽名保存在一個文件中(myinfo.dat)
          ??????java.io.ObjectOutputStream?out
          = new ?java.io.ObjectOutputStream( new ?java.io.FileOutputStream( " myinfo.dat " ));
          ??????out.writeObject(myinfo);
          ??????out.writeObject(signed);
          ??????out.close();
          ????
          // 把他的公鑰的信息及簽名發(fā)給其它用戶

          3. 其他用戶用他的公共密鑰(pubkey)和簽名(signed)和信息(info)進行驗證是否由他簽名的信息

          讀入公鑰
          java.io.ObjectInputStream in=new java.io.ObjectInputStream(new java.io.FileInputStream("mypubkey.dat"));
          PublicKey pubkey=(PublicKey)in.readObject();
          in.close();

          讀入簽名和信息
          in=new java.io.ObjectInputStream(new java.io.FileInputStream("myinfo.dat"));
          String info=(String)in.readObject();
          byte[] signed=(byte[])in.readObject();
          in.close();

          初始一個Signature對象,并用公鑰和簽名進行驗證
          java.security.Signature signetcheck=java.security.Signature.getInstance("DSA");
          signetcheck.initVerify(pubkey);
          signetcheck.update(info.getBytes());
          if (signetcheck.verify(signed)) { System.out.println("簽名正常");}

          對于密鑰的保存本文是用對象流的方式保存和傳送的,也可可以用編碼的方式保存.注意要
          import java.security.spec.*
          import java.security.*

          具休說明如下

          ? ·public key是用X.509編碼的,例碼如下:

          byte[]?bobEncodedPubKey=mypublic.getEncoded();?//生成編碼
          ???
          //傳送二進制編碼
          ???
          //以下代碼轉(zhuǎn)換編碼為相應(yīng)key對象
          ???X509EncodedKeySpec?bobPubKeySpec?=?new?X509EncodedKeySpec(bobEncodedPubKey);
          ???KeyFactory?keyFactory?
          =?KeyFactory.getInstance("DSA");
          ???PublicKey?bobPubKey?
          =?keyFactory.generatePublic(bobPubKeySpec);
          ??
          ? ·對于Private key是用PKCS#8編碼,例碼如下:
          ?byte[]?bPKCS=myprikey.getEncoded();
          ??
          //傳送二進制編碼
          ??
          //以下代碼轉(zhuǎn)換編碼為相應(yīng)key對象
          ??PKCS8EncodedKeySpec?priPKCS8=new?PKCS8EncodedKeySpec(bPKCS);
          ??KeyFactory?keyf
          =KeyFactory.getInstance("DSA");
          ??PrivateKey?otherprikey
          =keyf.generatePrivate(priPKCS8);
          ?

          4.常用API

          java.security.KeyPairGenerator 密鑰生成器類
          public static KeyPairGenerator getInstance(String algorithm) throws NoSuchAlgorithmException
          以指定的算法返回一個KeyPairGenerator 對象
          參數(shù): algorithm 算法名.如:"DSA","RSA"

          public void initialize(int keysize)

          以指定的長度初始化KeyPairGenerator對象,如果沒有初始化系統(tǒng)以1024長度默認設(shè)置

          參數(shù):keysize 算法位長.其范圍必須在 512 到 1024 之間,且必須為 64 的倍數(shù)

          public void initialize(int keysize, SecureRandom random)
          以指定的長度初始化和隨機發(fā)生器初始化KeyPairGenerator對象
          參數(shù):keysize 算法位長.其范圍必須在 512 到 1024 之間,且必須為 64 的倍數(shù)
          random 一個隨機位的來源(對于initialize(int keysize)使用了默認隨機器

          public abstract KeyPair generateKeyPair()
          產(chǎn)生新密鑰對

          java.security.KeyPair 密鑰對類
          public PrivateKey getPrivate()
          返回私鑰

          public PublicKey getPublic()
          返回公鑰

          java.security.Signature 簽名類
          public static Signature getInstance(String algorithm) throws NoSuchAlgorithmException
          返回一個指定算法的Signature對象
          參數(shù) algorithm 如:"DSA"

          public final void initSign(PrivateKey privateKey)
          throws InvalidKeyException
          用指定的私鑰初始化
          參數(shù):privateKey 所進行簽名時用的私鑰

          public final void update(byte data)
          throws SignatureException
          public final void update(byte[] data)
          throws SignatureException
          public final void update(byte[] data, int off, int len)
          throws SignatureException
          添加要簽名的信息

          public final byte[] sign()
          throws SignatureException
          返回簽名的數(shù)組,前提是initSign和update

          public final void initVerify(PublicKey publicKey)
          throws InvalidKeyException
          用指定的公鑰初始化
          參數(shù):publicKey 驗證時用的公鑰

          public final boolean verify(byte[] signature)
          throws SignatureException
          驗證簽名是否有效,前提是已經(jīng)initVerify初始化
          參數(shù): signature 簽名數(shù)組

          */
          ?
          import?java.security.*;
          ?
          import?java.security.spec.*;
          public?class?testdsa?{
          ??
          public?static?void?main(String[]?args)?throws?java.security.NoSuchAlgorithmException,java.lang.Exception?{
          ????????testdsa?my
          =new?testdsa();
          ????????my.run();
          ??}

          ??
          public?void?run()
          ??
          {
          ??
          //數(shù)字簽名生成密鑰
          ??
          //第一步生成密鑰對,如果已經(jīng)生成過,本過程就可以跳過,對用戶來講myprikey.dat要保存在本地
          ??
          //而mypubkey.dat給發(fā)布給其它用戶
          ???if?((new?java.io.File("myprikey.dat")).exists()==false)?{
          ???????
          if?(generatekey()==false)?{
          ???????????System.out.println(
          "生成密鑰對敗");
          ???????????
          return;
          ??????????}
          ;
          ????????}

          //第二步,此用戶
          //從文件中讀入私鑰,對一個字符串進行簽名后保存在一個文件(myinfo.dat)中
          //并且再把myinfo.dat發(fā)送出去
          //為了方便數(shù)字簽名也放進了myifno.dat文件中,當(dāng)然也可分別發(fā)送
          ??try?{
          ??java.io.ObjectInputStream?in
          =new?java.io.ObjectInputStream(new?java.io.FileInputStream("myprikey.dat"));
          ??PrivateKey?myprikey
          =(PrivateKey)in.readObject();
          ??in.close();
          ?
          //?java.security.spec.X509EncodedKeySpec?pubX509=new?java.security.spec.X509EncodedKeySpec(bX509);
          ?
          //java.security.spec.X509EncodedKeySpec?pubkeyEncode=java.security.spec.X509EncodedKeySpec
          ??String?myinfo="這是我的信息";????//要簽名的信息
          ??
          //用私鑰對信息生成數(shù)字簽名
          ??java.security.Signature?signet=java.security.Signature.getInstance("DSA");
          ??signet.initSign(myprikey);
          ??signet.update(myinfo.getBytes());
          ??
          byte[]?signed=signet.sign();??//對信息的數(shù)字簽名
          ??System.out.println("signed(簽名內(nèi)容)="+byte2hex(signed));
          ?
          //把信息和數(shù)字簽名保存在一個文件中
          ??java.io.ObjectOutputStream?out=new?java.io.ObjectOutputStream(new?java.io.FileOutputStream("myinfo.dat"));
          ??out.writeObject(myinfo);
          ??out.writeObject(signed);
          ??out.close();
          ??System.out.println(
          "簽名并生成文件成功");
          ??}

          ??
          catch?(java.lang.Exception?e)?{
          ????e.printStackTrace();
          ????System.out.println(
          "簽名并生成文件失敗");
          ??}
          ;
          ??
          //第三步
          ??
          //其他人通過公共方式得到此戶的公鑰和文件
          ??
          //其他人用此戶的公鑰,對文件進行檢查,如果成功說明是此用戶發(fā)布的信息.
          ??
          //
          ??try?{
          ???java.io.ObjectInputStream?in
          =new?java.io.ObjectInputStream(new?java.io.FileInputStream("mypubkey.dat"));
          ???PublicKey?pubkey
          =(PublicKey)in.readObject();
          ???in.close();
          ???System.out.println(pubkey.getFormat());
          ???in
          =new?java.io.ObjectInputStream(new?java.io.FileInputStream("myinfo.dat"));
          ???String?info
          =(String)in.readObject();
          ???
          byte[]?signed=(byte[])in.readObject();
          ???in.close();
          ??java.security.Signature?signetcheck
          =java.security.Signature.getInstance("DSA");
          ??signetcheck.initVerify(pubkey);
          ??signetcheck.update(info.getBytes());
          ??
          if?(signetcheck.verify(signed))?{
          ??System.out.println(
          "info="+info);
          ???System.out.println(
          "簽名正常");
          ??}

          ??
          else??System.out.println("非簽名正常");
          ??}

          ??
          catch?(java.lang.Exception?e)?{e.printStackTrace();};
          ??}

          ??
          //生成一對文件myprikey.dat和mypubkey.dat---私鑰和公鑰,
          ??
          //公鑰要用戶發(fā)送(文件,網(wǎng)絡(luò)等方法)給其它用戶,私鑰保存在本地
          ??public?boolean?generatekey()
          ??
          {
          ????
          try?{
          ??java.security.KeyPairGenerator??keygen
          =java.security.KeyPairGenerator.getInstance("DSA");
          ?
          //?SecureRandom?secrand=new?SecureRandom();
          ?
          //?secrand.setSeed("tttt".getBytes());?//初始化隨機產(chǎn)生器
          ?
          //?keygen.initialize(576,secrand);?????//初始化密鑰生成器
          ??keygen.initialize(512);
          ??KeyPair?keys
          =keygen.genKeyPair();
          //??KeyPair?keys=keygen.generateKeyPair();?//生成密鑰組
          ??PublicKey?pubkey=keys.getPublic();
          ??PrivateKey?prikey
          =keys.getPrivate();
          ??java.io.ObjectOutputStream?out
          =new?java.io.ObjectOutputStream(new?java.io.FileOutputStream("myprikey.dat"));
          ??out.writeObject(prikey);
          ??out.close();
          ??System.out.println(
          "寫入對象?prikeys?ok");
          ??out
          =new?java.io.ObjectOutputStream(new?java.io.FileOutputStream("mypubkey.dat"));
          ???out.writeObject(pubkey);
          ???out.close();
          ???System.out.println(
          "寫入對象?pubkeys?ok");
          ???System.out.println(
          "生成密鑰對成功");
          ???
          return?true;
          ??}

          ??
          catch?(java.lang.Exception?e)?{
          ???e.printStackTrace();
          ???System.out.println(
          "生成密鑰對失敗");
          ???
          return?false;
          ???}
          ;
          ??}

          ??
          public?String?byte2hex(byte[]?b)
          ????
          {
          ?????String?hs
          ="";
          ?????String?stmp
          ="";
          ?????
          for?(int?n=0;n<b.length;n++)
          ??????
          {
          ???????stmp
          =(java.lang.Integer.toHexString(b[n]?&?0XFF));
          ???????
          if?(stmp.length()==1)?hs=hs+"0"+stmp;
          ???????
          else?hs=hs+stmp;
          ???????
          if?(n<b.length-1)??hs=hs+":";
          ??????}

          ?????
          return?hs.toUpperCase();
          ????}

          }

          2.4. DESede/DES對稱算法

          首先生成密鑰,并保存(這里并沒的保存的代碼,可參考DSA中的方法)

          KeyGenerator keygen = KeyGenerator.getInstance(Algorithm);

          SecretKey deskey = keygen.generateKey();

          用密鑰加密明文(myinfo),生成密文(cipherByte)

          Cipher c1 = Cipher.getInstance(Algorithm);

          c1.init(Cipher.ENCRYPT_MODE,deskey);

          byte[] cipherByte=c1.doFinal(myinfo.getBytes());

          傳送密文和密鑰,本文沒有相應(yīng)代碼可參考DSA

          .............

          用密鑰解密密文

          c1 = Cipher.getInstance(Algorithm);

          c1.init(Cipher.DECRYPT_MODE,deskey);

          byte[] clearByte=c1.doFinal(cipherByte);

          相對來說對稱密鑰的使用是很簡單的,對于JCE來講支技DES,DESede,Blowfish三種加密術(shù)

          對于密鑰的保存各傳送可使用對象流或者用二進制編碼,相關(guān)參考代碼如下

          ???SecretKey?deskey?=?keygen.generateKey();
          ???
          byte[]?desEncode=deskey.getEncoded();
          ???javax.crypto.spec.SecretKeySpec?destmp
          =new?javax.crypto.spec.SecretKeySpec(desEncode,Algorithm);
          ???SecretKey?mydeskey
          =destmp;

          相關(guān)API

          KeyGenerator 在DSA中已經(jīng)說明,在添加JCE后在instance進可以如下參數(shù)

          DES,DESede,Blowfish,HmacMD5,HmacSHA1

          javax.crypto.Cipher 加/解密器


          public?static?final?Cipher?getInstance(java.lang.String?transformation)
          ????????????????????????????????
          throws?java.security.NoSuchAlgorithmException,
          ???????????????????????????????????????NoSuchPaddingException

          返回一個指定方法的Cipher對象

          參數(shù):transformation 方法名(可用 DES,DESede,Blowfish)

          public final void init(int opmode, java.security.Key key)
          throws java.security.InvalidKeyException

          用指定的密鑰和模式初始化Cipher對象

          參數(shù):opmode 方式(ENCRYPT_MODE, DECRYPT_MODE, WRAP_MODE,UNWRAP_MODE)

          key 密鑰

          public?final?byte[]?doFinal(byte[]?input)
          ?????????????????????
          throws?java.lang.IllegalStateException,
          ????????????????????????????IllegalBlockSizeException,
          ????????????????????????????BadPaddingException

          對input內(nèi)的串,進行編碼處理,返回處理后二進制串,是返回解密文還是加解文由init時的opmode決定

          注意:本方法的執(zhí)行前如果有update,是對updat和本次input全部處理,否則是本inout的內(nèi)容

          /*
          安全程序?DESede/DES測試
          */

          import?java.security.*;
          import?javax.crypto.*;
          public?class?testdes?{
          public?static?void?main(String[]?args){
          ????testdes?my
          =new?testdes();
          ????my.run();
          ??}

          public??void?run()?{
          //添加新安全算法,如果用JCE就要把它添加進去
          ?Security.addProvider(new?com.sun.crypto.provider.SunJCE());
          String?Algorithm
          ="DES";?//定義?加密算法,可用?DES,DESede,Blowfish
          String?myinfo="要加密的信息";
          ???
          try?{
          ???
          //生成密鑰
          ???KeyGenerator?keygen?=?KeyGenerator.getInstance(Algorithm);
          ???SecretKey?deskey?
          =?keygen.generateKey();
          ???
          //加密
          ???System.out.println("加密前的二進串:"+byte2hex(myinfo.getBytes()));
          ???System.out.println(
          "加密前的信息:"+myinfo);
          ???Cipher?c1?
          =?Cipher.getInstance(Algorithm);
          ???c1.init(Cipher.ENCRYPT_MODE,deskey);
          ???
          byte[]?cipherByte=c1.doFinal(myinfo.getBytes());
          ????System.out.println(
          "加密后的二進串:"+byte2hex(cipherByte));
          ???
          //解密
          ???c1?=?Cipher.getInstance(Algorithm);
          ???c1.init(Cipher.DECRYPT_MODE,deskey);
          ???
          byte[]?clearByte=c1.doFinal(cipherByte);
          ???System.out.println(
          "解密后的二進串:"+byte2hex(clearByte));
          ???System.out.println(
          "解密后的信息:"+(new?String(clearByte)));
          ??}

          ???
          catch?(java.security.NoSuchAlgorithmException?e1)?{e1.printStackTrace();}
          ???
          catch?(javax.crypto.NoSuchPaddingException?e2)?{e2.printStackTrace();}
          ???
          catch?(java.lang.Exception?e3)?{e3.printStackTrace();}
          ??}

          ?
          public?String?byte2hex(byte[]?b)?//二行制轉(zhuǎn)字符串
          ????{
          ?????String?hs
          ="";
          ?????String?stmp
          ="";
          ?????
          for?(int?n=0;n<b.length;n++)
          ??????
          {
          ???????stmp
          =(java.lang.Integer.toHexString(b[n]?&?0XFF));
          ???????
          if?(stmp.length()==1)?hs=hs+"0"+stmp;
          ???????
          else?hs=hs+stmp;
          ???????
          if?(n<b.length-1)??hs=hs+":";
          ??????}

          ?????
          return?hs.toUpperCase();
          ????}

          }

          2.5. Diffie-Hellman密鑰一致協(xié)議

          公開密鑰密碼體制的奠基人Diffie和Hellman所提出的 "指數(shù)密鑰一致協(xié)議"(Exponential Key Agreement Protocol),該協(xié)議不要求別的安全性先決條件,允許兩名用戶在公開媒體上交換信息以生成"一致"的,可以共享的密鑰。在JCE的中實現(xiàn)用戶alice生成DH類型的密鑰對,如果長度用1024生成的時間請,推薦第一次生成后保存DHParameterSpec,以便下次使用直接初始化.使其速度加快

          System.out.println("ALICE:?產(chǎn)生?DH?對?");
          KeyPairGenerator?aliceKpairGen?
          =?KeyPairGenerator.getInstance("DH");
          ?aliceKpairGen.initialize(
          512);
          KeyPair?aliceKpair?
          =?aliceKpairGen.generateKeyPair();

          alice生成公鑰發(fā)送組bob

          byte[]?alicePubKeyEnc?=?aliceKpair.getPublic().getEncoded();

          bob從alice發(fā)送來的公鑰中讀出DH密鑰對的初始參數(shù)生成bob的DH密鑰對

          注意這一步一定要做,要保證每個用戶用相同的初始參數(shù)生成的

          ???DHParameterSpec?dhParamSpec?=?((DHPublicKey)alicePubKey).getParams();
          ????KeyPairGenerator?bobKpairGen?
          =?KeyPairGenerator.getInstance("DH");
          ????bobKpairGen.initialize(dhParamSpec);
          ????KeyPair?bobKpair?
          =?bobKpairGen.generateKeyPair();

          bob根據(jù)alice的公鑰生成本地的DES密鑰

          ???KeyAgreement?bobKeyAgree?=?KeyAgreement.getInstance("DH");
          ????bobKeyAgree.init(bobKpair.getPrivate());
          ????bobKeyAgree.doPhase(alicePubKey,?
          true);
          ????SecretKey?bobDesKey?
          =?bobKeyAgree.generateSecret("DES");

          bob已經(jīng)生成了他的DES密鑰,他現(xiàn)把他的公鑰發(fā)給alice,

          ??????byte[]?bobPubKeyEnc?=?bobKpair.getPublic().getEncoded();

          alice根據(jù)bob的公鑰生成本地的DES密鑰

          ??????//,,,,,,解碼
          ????KeyAgreement?aliceKeyAgree?=?KeyAgreement.getInstance("DH");
          ????aliceKeyAgree.init(aliceKpair.getPrivate());
          ????aliceKeyAgree.doPhase(bobPubKey,?
          true);
          ????SecretKey?aliceDesKey?
          =?aliceKeyAgree.generateSecret("DES");

          bob和alice能過這個過程就生成了相同的DES密鑰,在這種基礎(chǔ)就可進行安全能信

          常用API

          java.security.KeyPairGenerator 密鑰生成器類
          public static KeyPairGenerator getInstance(String algorithm)
          throws NoSuchAlgorithmException
          以指定的算法返回一個KeyPairGenerator 對象
          參數(shù): algorithm 算法名.如:原來是DSA,現(xiàn)在添加了 DiffieHellman(DH)

          public void initialize(int keysize)
          以指定的長度初始化KeyPairGenerator對象,如果沒有初始化系統(tǒng)以1024長度默認設(shè)置
          參數(shù):keysize 算法位長.其范圍必須在 512 到 1024 之間,且必須為 64 的倍數(shù)
          注意:如果用1024生長的時間很長,最好生成一次后就保存,下次就不用生成了

          public void initialize(AlgorithmParameterSpec params)
          throws InvalidAlgorithmParameterException
          以指定參數(shù)初始化

          javax.crypto.interfaces.DHPublicKey
          public DHParameterSpec getParams()
          返回
          java.security.KeyFactory

          public static KeyFactory getInstance(String algorithm)
          throws NoSuchAlgorithmException
          以指定的算法返回一個KeyFactory
          參數(shù): algorithm 算法名:DSH,DH

          public final PublicKey generatePublic(KeySpec keySpec)
          throws InvalidKeySpecException
          根據(jù)指定的key說明,返回一個PublicKey對象

          java.security.spec.X509EncodedKeySpec
          public X509EncodedKeySpec(byte[] encodedKey)
          根據(jù)指定的二進制編碼的字串生成一個key的說明
          參數(shù):encodedKey 二進制編碼的字串(一般能過PublicKey.getEncoded()生成)
          javax.crypto.KeyAgreement 密碼一至類

          public static final KeyAgreement getInstance(java.lang.String algorithm)
          throws java.security.NoSuchAlgorithmException
          返回一個指定算法的KeyAgreement對象
          參數(shù):algorithm 算法名,現(xiàn)在只能是DiffieHellman(DH)

          public final void init(java.security.Key key)
          throws java.security.InvalidKeyException
          用指定的私鑰初始化
          參數(shù):key 一個私鑰

          public final java.security.Key doPhase(java.security.Key key,
          boolean lastPhase)
          throws java.security.InvalidKeyException,
          java.lang.IllegalStateException
          用指定的公鑰進行定位,lastPhase確定這是否是最后一個公鑰,對于兩個用戶的
          情況下就可以多次定次,最后確定
          參數(shù):key 公鑰
          lastPhase 是否最后公鑰

          public final SecretKey generateSecret(java.lang.String algorithm)
          throws java.lang.IllegalStateException,
          java.security.NoSuchAlgorithmException,
          java.security.InvalidKeyException
          根據(jù)指定的算法生成密鑰
          參數(shù):algorithm 加密算法(可用 DES,DESede,Blowfish)

          */
          import?java.io.*;
          import?java.math.BigInteger;
          import?java.security.*;
          import?java.security.spec.*;
          import?java.security.interfaces.*;
          import?javax.crypto.*;
          import?javax.crypto.spec.*;
          import?javax.crypto.interfaces.*;
          import?com.sun.crypto.provider.SunJCE;
          public?class?testDHKey?{
          ????
          public?static?void?main(String?argv[])?{
          ????
          try?{
          ????????testDHKey?my
          =?new?testDHKey();
          ????????my.run();
          ????}
          ?catch?(Exception?e)?{
          ????????System.err.println(e);
          ????}

          ????}

          ????
          private?void?run()?throws?Exception?{
          ????????Security.addProvider(
          new?com.sun.crypto.provider.SunJCE());
          ????System.out.println(
          "ALICE:?產(chǎn)生?DH?對?");
          ????KeyPairGenerator?aliceKpairGen?
          =?KeyPairGenerator.getInstance("DH");
          ????????aliceKpairGen.initialize(
          512);
          ????KeyPair?aliceKpair?
          =?aliceKpairGen.generateKeyPair();?//生成時間長
          ????????
          //?張三(Alice)生成公共密鑰?alicePubKeyEnc?并發(fā)送給李四(Bob)?,
          ????????
          //比如用文件方式,socket..
          ????byte[]?alicePubKeyEnc?=?aliceKpair.getPublic().getEncoded();
          ???????
          //bob接收到alice的編碼后的公鑰,將其解碼
          ????KeyFactory?bobKeyFac?=?KeyFactory.getInstance("DH");
          ????X509EncodedKeySpec?x509KeySpec?
          =?new?X509EncodedKeySpec??(alicePubKeyEnc);
          ????PublicKey?alicePubKey?
          =?bobKeyFac.generatePublic(x509KeySpec);
          ????????System.out.println(
          "alice公鑰bob解碼成功");
          ?????
          //?bob必須用相同的參數(shù)初始化的他的DH?KEY對,所以要從Alice發(fā)給他的公開密鑰,
          ?????????
          //中讀出參數(shù),再用這個參數(shù)初始化他的?DH?key對
          ?????????
          //從alicePubKye中取alice初始化時用的參數(shù)
          ????DHParameterSpec?dhParamSpec?=?((DHPublicKey)alicePubKey).getParams();
          ????KeyPairGenerator?bobKpairGen?
          =?KeyPairGenerator.getInstance("DH");
          ????bobKpairGen.initialize(dhParamSpec);
          ????KeyPair?bobKpair?
          =?bobKpairGen.generateKeyPair();
          ????????System.out.println(
          "BOB:?生成?DH?key?對成功");
          ????KeyAgreement?bobKeyAgree?
          =?KeyAgreement.getInstance("DH");
          ????bobKeyAgree.init(bobKpair.getPrivate());
          ????????System.out.println(
          "BOB:?初始化本地key成功");
          ????????
          //李四(bob)?生成本地的密鑰?bobDesKey
          ????bobKeyAgree.doPhase(alicePubKey,?true);
          ????SecretKey?bobDesKey?
          =?bobKeyAgree.generateSecret("DES");
          ????System.out.println(
          "BOB:?用alice的公鑰定位本地key,生成本地DES密鑰成功");
          ????????
          //?Bob生成公共密鑰?bobPubKeyEnc?并發(fā)送給Alice,
          ????????
          //比如用文件方式,socket..,使其生成本地密鑰
          ????byte[]?bobPubKeyEnc?=?bobKpair.getPublic().getEncoded();
          ????????System.out.println(
          "BOB向ALICE發(fā)送公鑰");
          ?????????
          //?alice接收到?bobPubKeyEnc后生成bobPubKey
          ?????????
          //?再進行定位,使aliceKeyAgree定位在bobPubKey
          ????KeyFactory?aliceKeyFac?=?KeyFactory.getInstance("DH");
          ????x509KeySpec?
          =?new?X509EncodedKeySpec(bobPubKeyEnc);
          ????PublicKey?bobPubKey?
          =?aliceKeyFac.generatePublic(x509KeySpec);
          ???????System.out.println(
          "ALICE接收BOB公鑰并解碼成功");
          ;
          ????KeyAgreement?aliceKeyAgree?
          =?KeyAgreement.getInstance("DH");
          ????aliceKeyAgree.init(aliceKpair.getPrivate());
          ????????System.out.println(
          "ALICE:?初始化本地key成功");
          ????aliceKeyAgree.doPhase(bobPubKey,?
          true);
          ????????
          //?張三(alice)?生成本地的密鑰?aliceDesKey
          ????SecretKey?aliceDesKey?=?aliceKeyAgree.generateSecret("DES");
          ????????System.out.println(
          "ALICE:?用bob的公鑰定位本地key,并生成本地DES密鑰");
          ????????
          if?(aliceDesKey.equals(bobDesKey))?System.out.println("張三和李四的密鑰相同");
          ???????
          //現(xiàn)在張三和李四的本地的deskey是相同的所以,完全可以進行發(fā)送加密,接收后解密,達到
          ???????
          //安全通道的的目的
          ????????/*
          ?????????*?bob用bobDesKey密鑰加密信息
          ?????????
          */

          ????Cipher?bobCipher?
          =?Cipher.getInstance("DES");
          ????bobCipher.init(Cipher.ENCRYPT_MODE,?bobDesKey);
          ????????String?bobinfo
          =?"這是李四的機密信息";
          ????????System.out.println(
          "李四加密前原文:"+bobinfo);
          ????
          byte[]?cleartext?=bobinfo.getBytes();
          ????
          byte[]?ciphertext?=?bobCipher.doFinal(cleartext);
          ????????
          /*
          ?????????*?alice用aliceDesKey密鑰解密
          ?????????
          */

          ????Cipher?aliceCipher?
          =?Cipher.getInstance("DES");
          ????aliceCipher.init(Cipher.DECRYPT_MODE,?aliceDesKey);
          ????
          byte[]?recovered?=?aliceCipher.doFinal(ciphertext);
          ????????System.out.println(
          "alice解密bob的信息:"+(new?String(recovered)));
          ????
          if?(!java.util.Arrays.equals(cleartext,?recovered))
          ????????
          throw?new?Exception("解密后與原文信息不同");
          ????System.out.println(
          "解密后相同");
          ????}

          }


          第3章?? 小結(jié)

          在加密術(shù)中生成密鑰對時,密鑰對的當(dāng)然是越長越好,但費時也越多,請從中從實際出發(fā)選取合適的長度,大部分例碼中的密鑰是每次運行就從新生成,在實際的情況中是生成后在一段時間保存在文件中,再次運行直接從文件中讀入,從而加快速度。當(dāng)然定時更新和加強密鑰保管的安全性也是必須的。

          關(guān)于作者

          王輝,具有八年的編程及系統(tǒng)管理經(jīng)驗,所使用的語言為C和Java 編程語言。目前在深圳一家公司做程序員,使用C和JAVA為DB2數(shù)據(jù)庫編程.



          地震讓大伙知道:居安思危,才是生存之道。
          posted on 2007-03-28 09:01 小尋 閱讀(577) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 新昌县| 醴陵市| 论坛| 商河县| 富蕴县| 宁强县| 西乌珠穆沁旗| 拉孜县| 邢台市| 潞西市| 蕉岭县| 龙海市| 宝坻区| 常德市| 长兴县| 腾冲县| 桓台县| 富源县| 黑龙江省| 措美县| 油尖旺区| 荆门市| 香格里拉县| 涡阳县| 蕲春县| 红原县| 萨迦县| 彭山县| 岫岩| 尚志市| 连云港市| 屏南县| 安义县| 昔阳县| 龙游县| 屯留县| 牙克石市| 沙河市| 沙雅县| 古丈县| 石狮市|