• 用 Java 解密 C# 加密的数据(DES)(转)


    今天遇到java解密url的问题。我们的系统要获取外部传过来的URL,URL是采用 DES 算法对消息进行加密,再用 BASE64 编码。不过对方系统是用 C# 写的。

    在网上搜了几篇文章终于找到一篇可以解决了,感谢这位老兄。

    [原文地址:http://yilinliu.blogspot.com/2010/07/c-java-net-descryptoserviceprovider-vs.html]

    前言: 這邊只列出我工作上有遇到的情況, 並未對所有的加解密做很完整的舉例/說明. 

            不過如果有人能提供其他情況, 我是可以試著去解看看. 

    情境: 在 .Net 中, 利用 DESCryptoServiceProvider 進行加密. 加密的 Mode 為 ECB, Padding 為 None, Zeros 與 PKCS7。

    import javax.crypto.Cipher;  
    import javax.crypto.SecretKey;  
    import javax.crypto.SecretKeyFactory;  
    import javax.crypto.spec.DESKeySpec;  
    import org.apache.commons.codec.binary.Base64;  
    .Net 加密的程式如下: PaddingMode.None  
      
    //建立一個Mode=ECB, Padding=None, Key為12345678的DESCryptoServiceProvider  
    DESCryptoServiceProvider objDESCryptoServiceProvider = new DESCryptoServiceProvider();  
    //Key的長度要64bits -> 8bytes;用ASCII編碼將Key轉為byte[]  
    objDESCryptoServiceProvider.Key = Encoding.ASCII.GetBytes("12345678");  
    objDESCryptoServiceProvider.Mode = CipherMode.ECB;  
    objDESCryptoServiceProvider.Padding = PaddingMode.None;  
      
    //用UTF-8編碼, 將字串轉為byte[]  
    byte[] bysData = Encoding.UTF8.GetBytes("我是一個PaddingMode.None的測試字串!");  
    //因為PaddingMode.None的關係, byte[]的長度要是8的倍數  
    byte[] bysFixSizeData = new byte[(int)Math.Ceiling(bysData.Length / 8.0) * 8];  
    //將資料複製到長度為8的倍數的byte[]  
    Array.Copy(bysData, bysFixSizeData, bysData.Length);  
      
    //進行加密  
    byte[] bysEncrypted = objDESCryptoServiceProvider.CreateEncryptor()  
      .TransformFinalBlock(bysFixSizeData, 0, bysFixSizeData.Length);  
    //將byte[]轉為Base64的字串  
    Console.WriteLine(Convert.ToBase64String(bysEncrypted));  
    //輸出: xnygZZ+WkN4pmDVDjBJ41o9LePFibMJkfvLkf9phS9mW2tbtS6JcMSiwX2N1KbGp  
    Java 解密的程式如下:: 使用 org.apache.commons.codec.binary.Base64 這個類別做 Base64 字串的解碼.  
    try {  
      //解密的Key  
      String strKey = "12345678";  
      //已加密的Base64字串  
      String strEncrypted = "xnygZZ+WkN4pmDVDjBJ41o9LePFibMJkfvLkf9phS9mW2tbtS6JcMSiwX2N1KbGp";  
      
      //先將Base64字串轉碼為byte[]  
      Base64 objBase64 = new Base64();  
      byte[] bysDecoded = objBase64.decode(strEncrypted.getBytes());  
      
      //建立解密所需的Key. 因為加密時的key是用ASCII轉換, 所以這邊也用ASCII做  
      DESKeySpec objDesKeySpec = new DESKeySpec(strKey.getBytes("ASCII"));  
      SecretKeyFactory objKeyFactory = SecretKeyFactory.getInstance("DES");  
      SecretKey objSecretKey = objKeyFactory.generateSecret(objDesKeySpec);  
      
      //設定一個DES/ECB/NoPadding的Cipher  
      //ECB對應到.Net的CipherMode.ECB  
      //NoPadding對應到.Net的PaddingMode.None  
      Cipher objCipher = Cipher.getInstance("DES/ECB/NoPadding");  
      //設定為解密模式, 並設定解密的key  
      objCipher.init(Cipher.DECRYPT_MODE, objSecretKey);  
      
      //輸出解密後的字串. 因為加密是用UTF-8將字串轉為byte[], 所以這邊要用UTF-8轉回去  
      //注意後面會多一些空字元. 因為加密前有因為資料長度的關係補上一些空的bytes  
      //這邊用String的trim()將這些空字元刪掉  
      String strDecrypted = new String(objCipher.doFinal(bysDecoded), "utf-8").trim();  
      System.out.println("[" + strDecrypted + "]");  
      //輸出:[我是一個PaddingMode.None的測試字串!]  
    } catch (Exception e) {  
      e.printStackTrace(System.out);  
    }  
    接下來測試一下 .Net 中的 PaddingMode.Zeros:  
    //建立一個Mode=ECB, Padding=None, Key為12345678的DESCryptoServiceProvider  
    DESCryptoServiceProvider objDESCryptoServiceProvider = new DESCryptoServiceProvider();  
    //Key的長度要64bits -> 8bytes  
    objDESCryptoServiceProvider.Key = Encoding.ASCII.GetBytes("12345678");  
    objDESCryptoServiceProvider.Mode = CipherMode.ECB;  
    objDESCryptoServiceProvider.Padding = PaddingMode.Zeros;  
      
    //用UTF-8編碼, 將字串轉為byte[]  
    //因為PaddingMode.Zeros的關係, 不用像上一個Sample一樣, 另外弄一個byte[]去將資料補到8的倍數  
    byte[] bysData = Encoding.UTF8.GetBytes("我是一個PaddingMode.Zeros的測試字串!");  
      
    //進行加密  
    byte[] bysEncrypted = objDESCryptoServiceProvider.CreateEncryptor()  
      .TransformFinalBlock(bysData, 0, bysData.Length);  
    //將byte[]轉為Base64的字串  
    Console.WriteLine(Convert.ToBase64String(bysEncrypted));  
    //輸出: xnygZZ+WkN4pmDVDjBJ41o9LePFibMJkYe6Sq5Y3mpq2JD91DLtxC/66itziI0rD  
    Java 的程式不用改變, 維持原狀即可.  
    try {  
      //解密的Key  
      String strKey = "12345678";  
      //已加密的Base64字串  
      String strEncrypted = "xnygZZ+WkN4pmDVDjBJ41o9LePFibMJkfvLkf9phS9mW2tbtS6JcMSiwX2N1KbGp";  
      
      //先將Base64字串轉碼為byte[]  
      Base64 objBase64 = new Base64();  
      byte[] bysDecoded = objBase64.decode(strEncrypted.getBytes());  
      
      //建立解密所需的Key. 因為加密時的key是用ASCII轉換, 所以這邊也用ASCII做  
      DESKeySpec objDesKeySpec = new DESKeySpec(strKey.getBytes("ASCII"));  
      SecretKeyFactory objKeyFactory = SecretKeyFactory.getInstance("DES");  
      SecretKey objSecretKey = objKeyFactory.generateSecret(objDesKeySpec);  
      
      //設定一個DES/ECB/NoPadding的Cipher  
      //ECB對應到.Net的CipherMode.ECB  
      //NoPadding對應到.Net的PaddingMode.None  
      Cipher objCipher = Cipher.getInstance("DES/ECB/NoPadding");  
      //設定為解密模式, 並設定解密的key  
      objCipher.init(Cipher.DECRYPT_MODE, objSecretKey);  
      
      //輸出解密後的字串. 因為加密是用UTF-8將字串轉為byte[], 所以這邊要用UTF-8轉回去  
      //注意後面會多一些空字元. 因為加密前有因為資料長度的關係補上一些空的bytes  
      //這邊用String的trim()將這些空字元刪掉  
      String strDecrypted = new String(objCipher.doFinal(bysDecoded), "utf-8").trim();  
      System.out.println("[" + strDecrypted + "]");  
      //輸出:[我是一個PaddingMode.None的測試字串!]  
    } catch (Exception e) {  
      e.printStackTrace(System.out);  
    }  
    最後測試 .Net 中的 PaddingMode.PKCS7:  
    //建立一個Mode=ECB, Padding=None, Key為12345678的DESCryptoServiceProvider  
    DESCryptoServiceProvider objDESCryptoServiceProvider = new DESCryptoServiceProvider();  
    //Key的長度要64bits -> 8bytes  
    objDESCryptoServiceProvider.Key = Encoding.ASCII.GetBytes("12345678");  
    objDESCryptoServiceProvider.Mode = CipherMode.ECB;  
    objDESCryptoServiceProvider.Padding = PaddingMode.PKCS7;  
      
    //用UTF-8編碼, 將字串轉為byte[]  
    //這邊也不用另外做補資料的動作  
    byte[] bysData = Encoding.UTF8.GetBytes("我是一個PaddingMode.PKCS7的測試字串!");  
      
    //進行加密  
    byte[] bysEncrypted = objDESCryptoServiceProvider.CreateEncryptor()  
      .TransformFinalBlock(bysData, 0, bysData.Length);  
    //將byte[]轉為Base64的字串  
    Console.WriteLine(Convert.ToBase64String(bysEncrypted));  
    //輸出: xnygZZ+WkN4pmDVDjBJ41o9LePFibMJkt86hRLUM4/m2JD91DLtxC5+8Tqc7iB2f  
    Java 程式的差別就在於把 DES / ECB / NoPadding 改為 DES / ECB / PKCS5Padding.  
    try {  
      //解密的Key  
      String strKey = "12345678";  
      //已加密的Base64字串  
      String strEncrypted = "xnygZZ+WkN4pmDVDjBJ41o9LePFibMJkt86hRLUM4/m2JD91DLtxC5+8Tqc7iB2f";  
        
      //先將Base64字串轉碼為byte[]  
      Base64 objBase64 = new Base64();  
      byte[] bysDecoded = objBase64.decode(strEncrypted.getBytes());  
        
      //建立解密所需的Key. 因為加密時的key是用ASCII轉換, 所以這邊也用ASCII做  
      DESKeySpec objDesKeySpec = new DESKeySpec(strKey.getBytes("ASCII"));  
      SecretKeyFactory objKeyFactory = SecretKeyFactory.getInstance("DES");  
      SecretKey objSecretKey = objKeyFactory.generateSecret(objDesKeySpec);  
      
      //設定一個DES/ECB/PKCS5Padding的Cipher  
      //ECB對應到.Net的CipherMode.ECB  
      //用PKCS5Padding對應到.Net的PaddingMode.PKCS7  
      Cipher objCipher = Cipher.getInstance("DES/ECB/PKCS5Padding");  
      //設定為解密模式, 並設定解密的key  
      objCipher.init(Cipher.DECRYPT_MODE, objSecretKey);  
        
      //輸出解密後的字串. 因為加密時指定PaddingMode.PKCS7, 所以可以不用處理空字元  
      //不過若想保險點, 也是可以用trim()去處理過一遍  
      String strDecrypted = new String(objCipher.doFinal(bysDecoded), "utf-8").trim();  
      System.out.println("[" + strDecrypted + "]");  
      //輸出:[我是一個PaddingMode.PKCS7的測試字串!]  
    } catch (Exception e) {  
      e.printStackTrace(System.out);  
    }  
    

      

  • 相关阅读:
    学习es6中class——整合阮一峰教程、MDN
    flex 整理 笔记
    面试题中常见的布局类问题总结
    跨域问题的总结
    js中函数传递参数,究竟是值传递还是引用传递?
    webpack 从入门到放弃
    浏览器的解析和执行过程
    Office Online Server – FILE TOO LARGE
    PowerShell中汉字与ASCII码相互转换
    查询SQLSERVER执行过的SQL记录(历史查询记录)
  • 原文地址:https://www.cnblogs.com/youngerliu/p/8079278.html
Copyright © 2020-2023  润新知