每日一得

          不求多得,只求一得 about java,hibernate,spring,design,database,Ror,ruby,快速開發(fā)
          最近關(guān)心的內(nèi)容:SSH,seam,flex,敏捷,TDD
          本站的官方站點(diǎn)是:顛覆軟件

            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            220 隨筆 :: 9 文章 :: 421 評(píng)論 :: 0 Trackbacks
          本文主要談一下密碼學(xué)中的加密和數(shù)字簽名,以及其在java中如何進(jìn)行使用。對(duì)密碼學(xué)有興趣的伙伴,推薦看 Bruce Schneier的著作:Applied Crypotography。在jdk1.5的發(fā)行版本中安全性方面有了很大的改進(jìn),也提供了對(duì)RSA算法的直接支持,現(xiàn)在我們從實(shí)例入手解決問題(本文 僅是作為簡單介紹):

            一、密碼學(xué)上常用的概念 

            1)消息摘要:

             這是一種與消息認(rèn)證碼結(jié)合使用以確保消息完整性的技術(shù)。主要使用單向散列函數(shù)算法,可用于檢驗(yàn)消息的完整性,和通過散列密碼直接以文本形式保存等,目前 廣泛使用的算法有MD4、MD5、SHA-1,jdk1.5對(duì)上面都提供了支持,在java中進(jìn)行消息摘要很簡單, java.security.MessageDigest提供了一個(gè)簡易的操作方法:

          /**
          *MessageDigestExample.java
          *Copyright?2005-2-16
          */
          import?java.security.MessageDigest;
          /**
          *單一的消息摘要算法,不使用密碼.可以用來對(duì)明文消息(如:密碼)隱藏保存
          */
          public?class?MessageDigestExample{
           
          public?static?void?main(String[]?args)?throws?Exception{
            
          if(args.length!=1){
             System.err.println(
          "Usage:java?MessageDigestExample?text");
             System.exit(
          1);
            }

            
          byte[]?plainText=args[0].getBytes("UTF8");

            
          //使用getInstance("算法")來獲得消息摘要,這里使用SHA-1的160位算法
            MessageDigest?messageDigest=MessageDigest.getInstance("SHA-1");

            System.out.println(
          "\n"+messageDigest.getProvider().getInfo());
            
          //開始使用算法
            messageDigest.update(plainText);
            System.out.println(
          "\nDigest:");
            
          //輸出算法運(yùn)算結(jié)果
            System.out.println(new?String(messageDigest.digest(),"UTF8"));
           }
          }

            還可以通過消息認(rèn)證碼來進(jìn)行加密實(shí)現(xiàn),javax.crypto.Mac提供了一個(gè)解決方案,有興趣者可以參考相關(guān)API文檔,本文只是簡單介紹什么是摘要算法。

          這里補(bǔ)充另一個(gè)運(yùn)用消息摘要的方式加密的例子:
          public?class?TestEncrypt?{

          ????
          public?TestEncrypt()?{
          ????}

          ????
          /**
          ?????*?
          @param?strSrc??:strSrc?is?a?string?will?be?encrypted,
          ?????*?
          @param?encName?:?encName?is?the?algorithm?name?will?be?used.
          ?????*????????????????encName?dafault?to?"MD5"
          ?????*?
          @return?String
          ?????
          */
          ????
          public?String?Encrypt(String?strSrc,?String?encName)?{

          ????????MessageDigest?md?
          =?null;
          ????????String?strDes?
          =?null;

          ????????
          byte[]?bt?=?strSrc.getBytes();
          ????????
          try?{
          ????????????
          if?(encName?==?null?||?encName.equals(""))?{
          ????????????????encName?
          =?"MD5";
          ????????????}
          ????????????md?
          =?MessageDigest.getInstance(encName);
          ????????????md.update(bt);
          ????????????strDes?
          =?bytes2Hex(md.digest());?//to?HexString
          ????????}
          ????????
          catch?(NoSuchAlgorithmException?e)?{
          ????????????System.out.println(
          "Invalid?algorithm.");
          ????????????
          return?null;
          ????????}
          ????????
          return?strDes;
          ????}

          ????
          public?String?bytes2Hex(byte[]?bts)?{
          ????????String?des?
          =?"";
          ????????String?tmp?
          =?null;
          ????????
          for?(int?i?=?0;?i?<?bts.length;?i++)?{
          ????????????tmp?
          =?(Integer.toHexString(bts[i]?&?0xFF));
          ????????????
          if?(tmp.length()?==?1)?{
          ????????????????des?
          +=?"0";
          ????????????}
          ????????????des?
          +=?tmp;
          ????????}
          ????????
          return?des;
          ????}

          ????
          public?static?void?main(String[]args)?{
          ????????TestEncrypt?te?
          =?new?TestEncrypt();
          ????????String?strSrc?
          =?"可以加密漢字.Oh,and?english";
          ????????System.out.println(
          "Source?String:"?+?strSrc);
          ????????System.out.println(
          "Encrypted?String:");
          ????????System.out.println(
          "Use?Def:"?+?te.Encrypt(strSrc,?null));
          ????????System.out.println(
          "Use?MD5:"?+?te.Encrypt(strSrc,?"MD5"));
          ????????System.out.println(
          "Use?SHA:"?+?te.Encrypt(strSrc,?"SHA-1"));
          ????????System.out.println(
          "Use?SHA-256:"?+?te.Encrypt(strSrc,?"SHA-256"));
          ????}
          }

          另外,在javawebparts中的 RequestHelpers里的generateGUID方法也涉及到了MD5的方法,代碼如下:
          public?static?String?generateGUID(HttpServletRequest?request)?{

          ????String?out?
          =?"";
          ????
          try?{
          ??????
          //?Construct?a?string?that?is?comprised?of:
          ??????
          //?Remote?IP?Address?+?Host?IP?Address?+?Date?(yyyyMMdd)?+
          ??????
          //?Time?(hhmmssSSa)?+?Requested?Path?+?Session?ID?+
          ??????
          //?HashCode?Of?ParameterMap
          ??????StringBuffer?sb?=?new?StringBuffer(1024);
          ??????sb.append(request.getRemoteAddr());
          ??????InetAddress?ia?
          =?InetAddress.getLocalHost();
          ??????sb.append(ia.getHostAddress());
          ??????sb.append(
          new?SimpleDateFormat("yyyyMMddhhmmssSSa").format(new?Date()));
          ??????String?path?
          =?request.getServletPath();
          ??????String?pathInfo?
          =?request.getPathInfo();
          ??????
          if?(pathInfo?!=?null)?{
          ????????path?
          +=?pathInfo;
          ??????}
          ??????sb.append(path);
          ??????sb.append(request.getSession(
          false));
          ??????sb.append(request.getParameterMap().hashCode());
          ??????String?str?
          =?sb.toString();
          ??????
          //?Now?encode?the?string?using?an?MD5?encryption?algorithm.
          ??????MessageDigest?md?=?MessageDigest.getInstance("md5");
          ??????md.update(str.getBytes());
          ??????
          byte[]?digest?=?md.digest();
          ??????StringBuffer?hexStr?
          =?new?StringBuffer(1024);
          ??????
          for?(int?i?=?0;?i?<?digest.length;?i++)?{
          ????????str?
          =?Integer.toHexString(0xFF?&?digest[i]);
          ????????
          if?(str.length()?<?2)?{
          ??????????str?
          =?"0"?+?str;
          ????????}
          ????????hexStr.append(str);
          ??????}
          ??????out?
          =?hexStr.toString();
          ????}?
          catch?(NoSuchAlgorithmException?nsae)?{
          ??????log.error(nsae);
          ????}?
          catch?(UnknownHostException?uhe)?{
          ??????log.error(uhe);
          ????}
          ????
          //?Return?the?encrypted?string.??It?should?be?unique?based?on?the
          ????
          //?components?that?comprise?the?plain?text?string,?and?should?always?be
          ????
          //?32?characters?thanks?to?the?MD5?algorithm.
          ????return?out;

          ??}?
          //?End?generateGUID().


            2)私鑰加密:

            消息摘要只能檢查消息的完整性,但是單向的,對(duì)明文消息并不能加密,要加密明文的消息的話,就要使用其他的算法,要確保機(jī)密性,我們需要使用私鑰密碼術(shù)來交換私有消息。

            這種最好理解,使用對(duì)稱算法。比如:A用一個(gè)密鑰對(duì)一個(gè)文件加密,而B讀取這個(gè)文件的話,則需要和A一樣的密鑰,雙方共享一個(gè)私鑰(而在web環(huán)境下,私鑰在傳遞時(shí)容易被偵聽):

             使用私鑰加密的話,首先需要一個(gè)密鑰,可用javax.crypto.KeyGenerator產(chǎn)生一個(gè)密鑰(java.security.Key), 然后傳遞給一個(gè)加密工具(javax.crypto.Cipher),該工具再使用相應(yīng)的算法來進(jìn)行加密,主要對(duì)稱算法有:DES(實(shí)際密鑰只用到56 位),AES(支持三種密鑰長度:128、192、256位),通常首先128位,其他的還有DESede等,jdk1.5種也提供了對(duì)對(duì)稱算法的支持, 以下例子使用AES算法來加密:

          /**
          *PrivateExmaple.java
          *Copyright?2005-2-16
          */
          import?javax.crypto.Cipher;
          import?javax.crypto.KeyGenerator;
          import?java.security.Key;

          /**
          *私鈅加密,保證消息機(jī)密性
          */
          public?class?PrivateExample{
           
          public?static?void?main(String[]?args)?throws?Exception{
            
          if(args.length!=1){
             System.err.println(
          "Usage:java?PrivateExample?<text>");
             System.exit(
          1);
            }
            
          byte[]?plainText=args[0].getBytes("UTF8");

            
          //通過KeyGenerator形成一個(gè)key
            System.out.println("\nStart?generate?AES?key");
            KeyGenerator?keyGen
          =KeyGenerator.getInstance("AES");
            keyGen.init(
          128);
            Key?key
          =keyGen.generateKey();
            System.out.println(
          "Finish?generating?DES?key");

            
          //獲得一個(gè)私鈅加密類Cipher,ECB是加密方式,PKCS5Padding是填充方法
            Cipher?cipher=Cipher.getInstance("AES/ECB/PKCS5Padding");
            System.out.println(
          "\n"+cipher.getProvider().getInfo());

            
          //使用私鈅加密
            System.out.println("\nStart?encryption:");
            cipher.init(Cipher.ENCRYPT_MODE,key);
            
          byte[]?cipherText=cipher.doFinal(plainText);
            System.out.println(
          "Finish?encryption:");
            System.out.println(
          new?String(cipherText,"UTF8"));

            System.out.println(
          "\nStart?decryption:");
            cipher.init(Cipher.DECRYPT_MODE,key);
            
          byte[]?newPlainText=cipher.doFinal(cipherText);
            System.out.println(
          "Finish?decryption:");

            System.out.println(
          new?String(newPlainText,"UTF8"));

           }
          }

            3)公鑰加密:

             上面提到,私鑰加密需要一個(gè)共享的密鑰,那么如何傳遞密鑰呢?web環(huán)境下,直接傳遞的話很容易被偵聽到,幸好有了公鑰加密的出現(xiàn)。公鑰加密也叫不對(duì)稱 加密,不對(duì)稱算法使用一對(duì)密鑰對(duì),一個(gè)公鑰,一個(gè)私鑰,使用公鑰加密的數(shù)據(jù),只有私鑰能解開(可用于加密);同時(shí),使用私鑰加密的數(shù)據(jù),只有公鑰能解開 (簽名)。但是速度很慢(比私鑰加密慢100到1000倍),公鑰的主要算法有RSA,還包括Blowfish,Diffie-Helman等, jdk1.5種提供了對(duì)RSA的支持,是一個(gè)改進(jìn)的地方:

          /**
          *PublicExample.java
          *Copyright?2005-2-16
          */
          import?java.security.Key;
          import?javax.crypto.Cipher;
          import?java.security.KeyPairGenerator;
          import?java.security.KeyPair;
          /**
          *一個(gè)簡單的公鈅加密例子,Cipher類使用KeyPairGenerator生成的公鈅和私鈅
          */
          public?class?PublicExample{
           
          public?static?void?main(String[]?args)?throws?Exception{
            
          if(args.length!=1){
             System.err.println(
          "Usage:java?PublicExample?<text>");
             System.exit(
          1);
            }

            
          byte[]?plainText=args[0].getBytes("UTF8");
            
          //構(gòu)成一個(gè)RSA密鑰
            System.out.println("\nStart?generating?RSA?key");
            KeyPairGenerator?keyGen
          =KeyPairGenerator.getInstance("RSA");
            keyGen.initialize(
          1024);
            KeyPair?key
          =keyGen.generateKeyPair();
            System.out.println(
          "Finish?generating?RSA?key");

            
          //獲得一個(gè)RSA的Cipher類,使用公鈅加密
            Cipher?cipher=Cipher.getInstance("RSA/ECB/PKCS1Padding");
            System.out.println(
          "\n"+cipher.getProvider().getInfo());

            System.out.println(
          "\nStart?encryption");
            cipher.init(Cipher.ENCRYPT_MODE,key.getPublic());
            
          byte[]?cipherText=cipher.doFinal(plainText);
            System.out.println(
          "Finish?encryption:");
            System.out.println(
          new?String(cipherText,"UTF8"));

            
          //使用私鈅解密
            System.out.println("\nStart?decryption");
            cipher.init(Cipher.DECRYPT_MODE,key.getPrivate());
            
          byte[]?newPlainText=cipher.doFinal(cipherText);
            System.out.println(
          "Finish?decryption:");
            System.out.println(
          new?String(newPlainText,"UTF8"));
           }
          }

          posted on 2006-09-07 23:59 Alex 閱讀(1165) 評(píng)論(0)  編輯  收藏 所屬分類: 加密解密

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


          網(wǎng)站導(dǎo)航:
          博客園   IT新聞   Chat2DB   C++博客   博問  
           
          主站蜘蛛池模板: 康马县| 邓州市| 乡城县| 双城市| 奉化市| 丹阳市| 丹东市| 五台县| 岳普湖县| 开江县| 上杭县| 麻江县| 林口县| 息烽县| 洪洞县| 江陵县| 张家港市| 渭南市| 海安县| 栖霞市| 龙陵县| 阳新县| 普安县| 措勤县| 车致| 木里| 合水县| 杭锦后旗| 长海县| 河南省| 永顺县| 盱眙县| 永济市| 太原市| 漾濞| 淅川县| 天等县| 湖州市| 岳阳县| 龙胜| 宁海县|