[C# & Java].Net加密(DESCryptoServiceProvider) VS. Java解密

本文介绍了使用.NET的DESCryptoServiceProvider进行加密,并在Java平台上实现解密的过程。具体探讨了不同填充模式(None、Zeros及PKCS7)下.NET加密的数据如何在Java中正确解密的方法。
摘要由CSDN通过智能技术生成

前言:這邊只列出我工作上有遇到的情況,並未對所有的加解密做很完整的舉例/說明。
          不過如果有人能提供其他情況,我是可以試著去解看看。

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

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

01//建立一個Mode=ECB, Padding=None, Key為12345678的DESCryptoServiceProvider
02DESCryptoServiceProvider objDESCryptoServiceProvider = new DESCryptoServiceProvider();
03//Key的長度要64bits -> 8bytes;用ASCII編碼將Key轉為byte[]
04objDESCryptoServiceProvider.Key = Encoding.ASCII.GetBytes("12345678");
05objDESCryptoServiceProvider.Mode = CipherMode.ECB;
06objDESCryptoServiceProvider.Padding = PaddingMode.None;
07  
08//用UTF-8編碼, 將字串轉為byte[]
09byte[] bysData = Encoding.UTF8.GetBytes("我是一個PaddingMode.None的測試字串!");
10//因為PaddingMode.None的關係, byte[]的長度要是8的倍數
11byte[] bysFixSizeData = new byte[(int)Math.Ceiling(bysData.Length / 8.0) * 8];
12//將資料複製到長度為8的倍數的byte[]
13Array.Copy(bysData, bysFixSizeData, bysData.Length);
14  
15//進行加密
16byte[] bysEncrypted = objDESCryptoServiceProvider.CreateEncryptor().TransformFinalBlock(bysFixSizeData, 0, bysFixSizeData.Length);
17//將byte[]轉為Base64的字串
18Console.WriteLine(Convert.ToBase64String(bysEncrypted));
19//輸出: 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:
 

01//建立一個Mode=ECB, Padding=None, Key為12345678的DESCryptoServiceProvider
02DESCryptoServiceProvider objDESCryptoServiceProvider = new DESCryptoServiceProvider();
03//Key的長度要64bits -> 8bytes
04objDESCryptoServiceProvider.Key = Encoding.ASCII.GetBytes("12345678");
05objDESCryptoServiceProvider.Mode = CipherMode.ECB;
06objDESCryptoServiceProvider.Padding = PaddingMode.Zeros;
07  
08//用UTF-8編碼, 將字串轉為byte[]
09//因為PaddingMode.Zeros的關係, 不用像上一個Sample一樣, 另外弄一個byte[]去將資料補到8的倍數
10byte[] bysData = Encoding.UTF8.GetBytes("我是一個PaddingMode.Zeros的測試字串!");
11  
12//進行加密
13byte[] bysEncrypted = objDESCryptoServiceProvider.CreateEncryptor().TransformFinalBlock(bysData, 0, bysData.Length);
14//將byte[]轉為Base64的字串
15Console.WriteLine(Convert.ToBase64String(bysEncrypted));
16//輸出: xnygZZ+WkN4pmDVDjBJ41o9LePFibMJkYe6Sq5Y3mpq2JD91DLtxC/66itziI0rD

Java的程式不用改變,維持原狀即可。
 

try {
    //解密的Key
    String strKey = "12345678";
    //已加密的Base64字串
    String strEncrypted = "xnygZZ+WkN4pmDVDjBJ41o9LePFibMJkYe6Sq5Y3mpq2JD91DLtxC/66itziI0rD";

    //先將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.Zeros
    Cipher objCipher = Cipher.getInstance("DES/ECB/NoPadding");
    //設定為解密模式, 並設定解密的key
    objCipher.init(Cipher.DECRYPT_MODE, objSecretKey);
    
    //輸出解密後的字串. 注意一樣會多一些空字元. 因為加密時有指定PaddingMode.Zeros, 所以會自動補空字元
    //這邊一樣用String的trim()將這些空字元刪掉
    String strDecrypted = new String(objCipher.doFinal(bysDecoded), "utf-8").trim();
    System.out.println("[" + strDecrypted + "]");
    //輸出:[我是一個PaddingMode.Zeros的測試字串!]
} catch (Exception e) {
    e.printStackTrace(System.out);
}

最後測試.Net中的PaddingMode.PKCS7:
 

01//建立一個Mode=ECB, Padding=None, Key為12345678的DESCryptoServiceProvider
02DESCryptoServiceProvider objDESCryptoServiceProvider = new DESCryptoServiceProvider();
03//Key的長度要64bits -> 8bytes
04objDESCryptoServiceProvider.Key = Encoding.ASCII.GetBytes("12345678");
05objDESCryptoServiceProvider.Mode = CipherMode.ECB;
06objDESCryptoServiceProvider.Padding = PaddingMode.PKCS7;
07  
08//用UTF-8編碼, 將字串轉為byte[]
09//這邊也不用另外做補資料的動作
10byte[] bysData = Encoding.UTF8.GetBytes("我是一個PaddingMode.PKCS7的測試字串!");
11  
12//進行加密
13byte[] bysEncrypted = objDESCryptoServiceProvider.CreateEncryptor().TransformFinalBlock(bysData, 0, bysData.Length);
14//將byte[]轉為Base64的字串
15Console.WriteLine(Convert.ToBase64String(bysEncrypted));
16//輸出: 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);
}

 

因為目前只有這些加解密的需求,所以就沒去測其他的。
也許以後有用到其他的,就再補上

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值