風人園

          弱水三千,只取一瓢,便能解渴;佛法無邊,奉行一法,便能得益。
          隨筆 - 99, 文章 - 181, 評論 - 56, 引用 - 0
          數據加載中……

          Java加密和數字簽名

          本文主要談一下密碼學中的加密和數字簽名,以及其在java中如何進行使用。對密碼學有興趣的伙伴,推薦看 Bruce Schneier的著作:Applied Crypotography。在jdk1.5的發行版本中安全性方面有了很大的改進,也提供了對RSA算法的直接支持,現在我們從實例入手解決問題(本文僅是作為簡單介紹):

            一、密碼學上常用的概念 

            1)消息摘要:

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

          /**
          *MessageDigestExample.java
          *Copyright?2005-2-16
          */
          import?java.security.MessageDigest;
          /**
          *單一的消息摘要算法,不使用密碼.可以用來對明文消息(如:密碼)隱藏保存
          */
          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:");
            
          //輸出算法運算結果
            System.out.println(new?String(messageDigest.digest(),"UTF8"));
           }
          }

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

          這里補充另一個運用消息摘要的方式加密的例子:
          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)私鑰加密:

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

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

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

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

          /**
          *私鈅加密,保證消息機密性
          */
          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形成一個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");

            
          //獲得一個私鈅加密類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)公鑰加密:

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

          /**
          *PublicExample.java
          *Copyright?2005-2-16
          */
          import?java.security.Key;
          import?javax.crypto.Cipher;
          import?java.security.KeyPairGenerator;
          import?java.security.KeyPair;
          /**
          *一個簡單的公鈅加密例子,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");
            
          //構成一個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");

            
          //獲得一個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-11-01 14:07 風人園 閱讀(335) 評論(0)  編輯  收藏 所屬分類: 算法

          主站蜘蛛池模板: 普定县| 兴海县| 南投市| 阿尔山市| 新安县| 广宁县| 阳山县| 宁都县| 泸溪县| 通州区| 宁津县| 丽水市| 泰宁县| 河源市| 津市市| 岚皋县| 石棉县| 玛曲县| 崇左市| 恩平市| 松滋市| 东阳市| 盐池县| 玛曲县| 南靖县| 玉屏| 临泽县| 信丰县| 白银市| 隆子县| 大石桥市| 喀什市| 全椒县| 神木县| 汪清县| 兰溪市| 高唐县| 樟树市| 巴南区| 宣威市| 六盘水市|