C#對稱加密算法Java實現(xiàn)

          最近因為業(yè)務(wù)需求,需要把一段C#編寫的加密代碼采用Java進行實現(xiàn),在此記下我的實施過程和過程中碰到的一些問題以備后用。為了便于觀察,只貼上C#源碼中關(guān)鍵的部分:
           1 ///
           2 ///<summary>
           3 /// 加密方法
           4 /// </summary>
           5 /// <param name=\"Source\">待加密的串</param>
           6 /// <returns>經(jīng)過加密的串</returns>
           7 public static string Encrypto(string Source)
           8 {
           9     byte[] bytIn = UTF8Encoding.UTF8.GetBytes(Source);
          10     MemoryStream ms = new MemoryStream();
          11     mobjCryptoService.Key = GetLegalKey();
          12     mobjCryptoService.IV = GetLegalIV();
          13     //創(chuàng)建對稱加密器對象
          14     //下面的控制臺打印是我自己添加方便觀察的
          15     Console.WriteLine("KeySize:" + mobjCryptoService.KeySize);
          16     Console.WriteLine("LegalKeySizes:" + mobjCryptoService.LegalKeySizes.Length);
          17     Console.WriteLine("Mode:"+ mobjCryptoService.Mode);
          18     Console.WriteLine("Padding:"+mobjCryptoService.Padding);
          19     ICryptoTransform encrypto = mobjCryptoService.CreateEncryptor();
          20     //定義將數(shù)據(jù)流鏈接到加密轉(zhuǎn)換的流
          21     CryptoStream cs = new CryptoStream(ms, encrypto, CryptoStreamMode.Write);
          22     cs.Write(bytIn, 0, bytIn.Length);
          23     cs.FlushFinalBlock();
          24     ms.Close();
          25     byte[] bytOut = ms.ToArray();
          26 
          27     return Convert.ToBase64String(bytOut);
          28 }
          29 
          30 ///
          31 ///<summary>
          32 /// 解密方法
          33 /// </summary>
          34 /// <param name=\"Source\">待解密的串</param>
          35 /// <returns>經(jīng)過解密的串</returns>
          36 public static string Decrypto(string Source)
          37 {
          38     try
          39     {
          40         byte[] bytIn = Convert.FromBase64String(Source);
          41         MemoryStream ms = new MemoryStream(bytIn, 0, bytIn.Length);
          42         mobjCryptoService.Key = GetLegalKey();
          43         mobjCryptoService.IV = GetLegalIV();
          44         //創(chuàng)建對稱解密器對象
          45         ICryptoTransform encrypto = mobjCryptoService.CreateDecryptor();
          46         //定義將數(shù)據(jù)流鏈接到加密轉(zhuǎn)換的流
          47         CryptoStream cs = new CryptoStream(ms, encrypto, CryptoStreamMode.Read);
          48         StreamReader sr = new StreamReader(cs);
          49         return sr.ReadToEnd();
          50     }
          51     catch (Exception)
          52     {
          53         return string.Empty;
          54     }
          55 }

          其中有一個問題:
          1 //生成加密器的對象由RijndaelManaged得來,那么這個RijndaelManaged對象是干嘛的?第三方的?原生的?
          2 private static SymmetricAlgorithm mobjCryptoService = new RijndaelManaged();

          調(diào)查之后,好吧,它是一種對稱加密算法(可以理解為在雙方之間可以實現(xiàn)加解密),以下來自百科:
          高級加密標(biāo)準(zhǔn)(英語:Advanced Encryption Standard,縮寫:AES),在密碼學(xué)中又稱Rijndael加密法,是美國聯(lián)邦政府采用的一種區(qū)塊加密標(biāo)準(zhǔn)。這個標(biāo)準(zhǔn)用來替代原先的DES,已經(jīng)被多方分析且廣為全世界所使用。經(jīng)過五年的甄選流程,高級加密標(biāo)準(zhǔn)由美國國家標(biāo)準(zhǔn)與技術(shù)研究院(NIST)于2001年11月26日發(fā)布于FIPS PUB 197,并在2002年5月26日成為有效的標(biāo)準(zhǔn)。2006年,高級加密標(biāo)準(zhǔn)已然成為對稱密鑰加密中最流行的算法之一。
          之前對加密標(biāo)準(zhǔn)認(rèn)識的并不多,但是通過代碼來看,似乎實現(xiàn)對稱加密還需要別的材料,看到下面這兩個方法
           1 /// <summary>
           2 /// 獲得密鑰
           3 /// </summary>
           4 /// <returns>密鑰</returns>
           5 private static byte[] GetLegalKey()
           6 {
           7     string _TempKey = Key;//Key已經(jīng)預(yù)先寫死在代碼里了
           8     mobjCryptoService.GenerateKey();
           9     byte[] bytTemp = mobjCryptoService.Key;
          10     int KeyLength = bytTemp.Length;
          11     if (_TempKey.Length > KeyLength)
          12         _TempKey = _TempKey.Substring(0, KeyLength);
          13     else if (_TempKey.Length < KeyLength)
          14         _TempKey = _TempKey.PadRight(KeyLength, ' ');
          15       return ASCIIEncoding.ASCII.GetBytes(_TempKey);
          16 }
          17 //GetLegalKey方法每次都會返回一個長度為32的byte數(shù)組
          18 //mobjCryptoService.Key = GetLegalKey();
          19 
          20 /// <summary>
          21 /// 獲得初始向量IV
          22 /// </summary>
          23 /// <returns>初試向量IV</returns>
          24 private static byte[] GetLegalIV()
          25 {
          26     string _TempIV = "$%^&*()_osudghwe7%%2kdijskldglk2397^&*wigwuqwelkn";//這是虛構(gòu)的
          27     mobjCryptoService.GenerateIV();
          28     byte[] bytTemp = mobjCryptoService.IV;
          29     int IVLength = bytTemp.Length;
          30     if (_TempIV.Length > IVLength)
          31         _TempIV = _TempIV.Substring(0, IVLength);
          32     else if (_TempIV.Length < IVLength)
          33         _TempIV = _TempIV.PadRight(IVLength, ' ');
          34     return ASCIIEncoding.ASCII.GetBytes(_TempIV);
          35 }
          36 //GetLegalIV方法每次都會返回一個長度為16的byte數(shù)組
          37 //mobjCryptoService.IV = GetLegalIV();

          雖然是通過兩個方法來取得的KEY和IV(二者都是byte數(shù)組),但是KEY和IV都是預(yù)先寫死在代碼里的,只不過是返回了特定長度的byte數(shù)組。
          1 //RijndaelManaged,這是對稱算法合法的key和IV的長度(分別以位來計算)
          2 //        Legal min key size = 128
          3 //        Legal max key size = 256
          4 //        Legal min block size = 128
          5 //        Legal max block size = 256

          經(jīng)過調(diào)查,還需要配置算法的mode和padding,此處并沒有進行設(shè)置,所以默認(rèn)分別為CipherMode.CBC和PaddingMode.PKCS7。詳見modepadding

          目前來看,需要調(diào)查的可以告一段落了,那么接下來,就需要調(diào)查如何Java實現(xiàn)了。在Java中,實現(xiàn)加密需要用到JCE提供的Cipher對象,類比C#的實現(xiàn),借鑒廣大程序員的智慧,我首先嘗試寫了一下(只貼出關(guān)鍵部分)
           1 public void init(byte[] keyBytes) {
           2 
           3     // 如果密鑰不足16位,那么就補足. 這個if 中的內(nèi)容很重要
           4     int base = 16;
           5     if (keyBytes.length % base != 0) {
           6         int groups = keyBytes.length / base
           7                 + (keyBytes.length % base != 0 ? 1 : 0);
           8         byte[] temp = new byte[groups * base];
           9         Arrays.fill(temp, (byte) 0);
          10         System.arraycopy(keyBytes, 0, temp, 0, keyBytes.length);
          11         keyBytes = temp;
          12     }
          13     // 轉(zhuǎn)化成JAVA的密鑰格式
          14     key = new SecretKeySpec(keyBytes, "AES");
          15     try {
          16         // 初始化cipher
          17         cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
          18     } catch (NoSuchAlgorithmException e) {
          19         e.printStackTrace();
          20     } catch (NoSuchPaddingException e) {
          21         e.printStackTrace();
          22     } 
          23 }
          24 
          25 /**
          26  * 加密方法
          27  * @param content 待加密內(nèi)容字符串
          28  * @param keySrc 加解密密秘鑰字符串
          29  * @param iv 算法所需向量
          30  * @return
          31  * @throws UnsupportedEncodingException
          32  */
          33 public String encrypt(String content, String keySrc,String iv) throws UnsupportedEncodingException {
          34     byte[] encryptedText = null;
          35     init(keySrc.getBytes("utf-8"));
          36     try {
          37         cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv.getBytes()));
          38         encryptedText = cipher.doFinal(content.getBytes("utf-8"));
          39     } catch (Exception e) {
          40         e.printStackTrace();
          41     }
          42     return Base64.encodeBase64String(encryptedText);
          43 }
          44 
          45 /**
          46  * 解密方法
          47  * @param encryptedData 待解密數(shù)據(jù)
          48  * @param keySrc 加解密密秘鑰字符串
          49  * @param iv 算法所需向量
          50  * @return
          51  * @throws UnsupportedEncodingException 
          52  */
          53 public String decrypt(String encryptedData, String keySrc,String iv) throws UnsupportedEncodingException {
          54     byte[] decryptedText = null;
          55     init(keySrc.getBytes("utf-8"));
          56     try {
          57         cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv.getBytes()));
          58         decryptedText = cipher.doFinal(Base64.decodeBase64(encryptedData));
          59     } catch (Exception e) {
          60         e.printStackTrace();
          61     }
          62     return new String(decryptedText);
          63 }
          64 
          65 public static void main(String[] args) throws UnsupportedEncodingException {
          66     EncryptingUtil eu = new EncryptingUtil();
          67     
          68     String content = "abc";
          69     // 加密字符串
          70     System.out.println("加密前的:" + content);
          71     // 加密方法
          72     String enc = eu.encrypt(content,"秘鑰值","向量值");
          73     System.out.println(enc);
          74     // 解密方法
          75     String dec = eu.decrypt(enc,"秘鑰值", "向量值");
          76     System.out.println("解密后的內(nèi)容:" + dec);
          77 }

          Java版本的實現(xiàn),目前有幾個問題,一個就是補齊方式的問題,在C#中默認(rèn)的補齊方式PKCS7,但是Java默認(rèn)并不支持該補齊方式,只有PKCS5;其次就是秘鑰的長度問題,C#代碼中的秘鑰長度是256位的,但是Java默認(rèn)最大支持128位的,執(zhí)行時會報出”Illegal key size”的問題。這位大牛的東東幫到我了,感謝。查看

          當(dāng)需要使用256位長度的秘鑰時,需要下載對應(yīng)Java版本的JCE拓展包,圖中的問題就是因為JCE拓展包和Java版本不匹配引起的

          posted on 2016-03-28 22:12 都較瘦 閱讀(207) 評論(0)  編輯  收藏 所屬分類: 工具案例積累Java相關(guān)案例積累


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


          網(wǎng)站導(dǎo)航:
           
          <2016年3月>
          282912345
          6789101112
          13141516171819
          20212223242526
          272829303112
          3456789

          導(dǎo)航

          統(tǒng)計

          公告

          博客定位:囿于目前的水平,博客定位在記錄自己的學(xué)習(xí)心得和隨手的練習(xí)

          常用鏈接

          留言簿

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 玉屏| 石家庄市| 额尔古纳市| 清镇市| 肃南| 屏东市| 车致| 济宁市| 阜阳市| 县级市| 彭阳县| 利津县| 惠州市| 平塘县| 新建县| 兴国县| 肇东市| 昌平区| 遂川县| 高平市| 新干县| 原平市| 玉田县| 贡嘎县| 思茅市| 田阳县| 沛县| 泾阳县| 合肥市| 子洲县| 广德县| 张掖市| 翁源县| 斗六市| 奉节县| 吴桥县| 台州市| 桃江县| 水城县| 玛沁县| 特克斯县|