前言:這邊只列出我工作上有遇到的情況,並未對所有的加解密做很完整的舉例/說明。
不過如果有人能提供其他情況,我是可以試著去解看看。
情境:在.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
02 | DESCryptoServiceProvider objDESCryptoServiceProvider = new DESCryptoServiceProvider(); |
04 | objDESCryptoServiceProvider.Key = Encoding.ASCII.GetBytes( "12345678" ); |
05 | objDESCryptoServiceProvider.Mode = CipherMode.ECB; |
06 | objDESCryptoServiceProvider.Padding = PaddingMode.None; |
09 | byte [] bysData = Encoding.UTF8.GetBytes( "我是一個PaddingMode.None的測試字串!" ); |
11 | byte [] bysFixSizeData = new byte [( int )Math.Ceiling(bysData.Length / 8.0) * 8]; |
13 | Array.Copy(bysData, bysFixSizeData, bysData.Length); |
16 | byte [] bysEncrypted = objDESCryptoServiceProvider.CreateEncryptor().TransformFinalBlock(bysFixSizeData, 0, bysFixSizeData.Length); |
18 | Console.WriteLine(Convert.ToBase64String(bysEncrypted)); |
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:
02 | DESCryptoServiceProvider objDESCryptoServiceProvider = new DESCryptoServiceProvider(); |
04 | objDESCryptoServiceProvider.Key = Encoding.ASCII.GetBytes( "12345678" ); |
05 | objDESCryptoServiceProvider.Mode = CipherMode.ECB; |
06 | objDESCryptoServiceProvider.Padding = PaddingMode.Zeros; |
10 | byte [] bysData = Encoding.UTF8.GetBytes( "我是一個PaddingMode.Zeros的測試字串!" ); |
13 | byte [] bysEncrypted = objDESCryptoServiceProvider.CreateEncryptor().TransformFinalBlock(bysData, 0, bysData.Length); |
15 | Console.WriteLine(Convert.ToBase64String(bysEncrypted)); |
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:
02 | DESCryptoServiceProvider objDESCryptoServiceProvider = new DESCryptoServiceProvider(); |
04 | objDESCryptoServiceProvider.Key = Encoding.ASCII.GetBytes( "12345678" ); |
05 | objDESCryptoServiceProvider.Mode = CipherMode.ECB; |
06 | objDESCryptoServiceProvider.Padding = PaddingMode.PKCS7; |
10 | byte [] bysData = Encoding.UTF8.GetBytes( "我是一個PaddingMode.PKCS7的測試字串!" ); |
13 | byte [] bysEncrypted = objDESCryptoServiceProvider.CreateEncryptor().TransformFinalBlock(bysData, 0, bysData.Length); |
15 | Console.WriteLine(Convert.ToBase64String(bysEncrypted)); |
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);
}
因為目前只有這些加解密的需求,所以就沒去測其他的。
也許以後有用到其他的,就再補上