Java和C#中3DES的加密與解密
阿新 • • 發佈:2019-01-08
最近在工作中遇到將Java環境的一個使用者ID用表單形式傳遞給.net環境做校驗,考慮到不能將使用者ID作為明文傳遞,因此利用簡單的3DES進行加密解密操作。
需要注意的就是:
(1)兩種環境下3DES加密解密的一致性問題:C#會對解密生成的byte在不滿足長度16時,自動填充'/0'直至長度為16,因此在接收到Java端的加密資料後,我們要對生成的byte做處理把末尾的'\0'去掉。
(2)另外在傳輸上我們採用BASE64編碼傳輸,一方面它具有簡單的不可讀性,另一方面它能規避一些特殊字元的傳輸問題。
下面的Java中3DES加密解密的示例程式碼:
執行例子如下圖所示:import java.security.Key; import java.io.IOException; import java.security.InvalidKeyException; import javax.crypto.Cipher; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.DESedeKeySpec; import javax.crypto.spec.IvParameterSpec; import java.util.Scanner; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; public class destest { public static void main(String[] args) throws Exception { // TODO Auto-generated method stub byte[] key = new BASE64Decoder().decodeBuffer("YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4"); byte[] keyiv = {1, 2, 3, 4, 5, 6, 7, 8}; Scanner sc = new Scanner(System.in); System.out.println("請輸入加密前的字串:"); String str = sc.nextLine(); System.out.println("原始字串為: " + str); byte[] data = str.getBytes("UTF-8"); System.out.println("開始CBC加密解密"); byte[] strEncode = des3EncodeCBC(key, keyiv, data); System.out.println("以BASE64編碼輸出加密後的byte為:" + new BASE64Encoder().encode(strEncode)); for (int i = 0; i < strEncode.length; i++) // 輸出加密後的strEncode每位元組的內容 { System.out.println("Encode byte[" + i + "] " + strEncode[i]); } byte[] strDecode = des3DecodeCBC(key, keyiv, strEncode); String strGet = new String(strDecode, "UTF-8"); System.out.println("解密後的字串內容為:" + strGet); for (int i = 0; i < strDecode.length; i++) // 輸出解密後strDecode每位元組的內容 { System.out.println("Decode byte[" + i + "] " + strDecode[i]); } } public static byte[] des3EncodeCBC(byte[] key, byte[] keyiv, byte[] data) throws Exception { Key deskey = null; DESedeKeySpec spec = new DESedeKeySpec(key); SecretKeyFactory keyfactory = SecretKeyFactory.getInstance("desede"); deskey = keyfactory.generateSecret(spec); Cipher cipher = Cipher.getInstance("desede" + "/CBC/PKCS5Padding"); IvParameterSpec ips = new IvParameterSpec(keyiv); cipher.init(Cipher.ENCRYPT_MODE, deskey, ips); byte[] bOut = cipher.doFinal(data); return bOut; } public static byte[] des3DecodeCBC(byte[] key, byte[] keyiv, byte[] data) throws Exception { Key deskey = null; DESedeKeySpec spec = new DESedeKeySpec(key); SecretKeyFactory keyfactory = SecretKeyFactory.getInstance("desede"); deskey = keyfactory.generateSecret(spec); Cipher cipher = Cipher.getInstance("desede" + "/CBC/PKCS5Padding"); IvParameterSpec ips = new IvParameterSpec(keyiv); cipher.init(Cipher.DECRYPT_MODE, deskey, ips); byte[] bOut = cipher.doFinal(data); return bOut; } }
下面是C#中3DES加密解密的示例程式碼:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using System.Security.Cryptography; namespace DES { class Program { private static byte[] key = Convert.FromBase64String("YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4"); private static byte[] iv = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }; public static byte[] Des3EncodeCBC(byte[] key, byte[] iv, byte[] data) { try { MemoryStream mStream = new MemoryStream(); TripleDESCryptoServiceProvider tdsp = new TripleDESCryptoServiceProvider(); tdsp.Mode = CipherMode.CBC; tdsp.Padding = PaddingMode.PKCS7; CryptoStream cStream = new CryptoStream(mStream, tdsp.CreateEncryptor(key, iv), CryptoStreamMode.Write); cStream.Write(data, 0, data.Length); cStream.FlushFinalBlock(); byte[] ret = mStream.ToArray(); cStream.Close(); mStream.Close(); return ret; } catch (CryptographicException e) { Console.WriteLine("A Cryptographic error occurred: {0}", e.Message); return null; } } public static byte[] Des3DecodeCBC(byte[] key, byte[] iv, byte[] data) { try { MemoryStream msDecrypt = new MemoryStream(data); TripleDESCryptoServiceProvider tdsp = new TripleDESCryptoServiceProvider(); tdsp.Mode = CipherMode.CBC; tdsp.Padding = PaddingMode.PKCS7; CryptoStream csDecrypt = new CryptoStream(msDecrypt, tdsp.CreateDecryptor(key, iv), CryptoStreamMode.Read); byte[] fromEncrypt = new byte[data.Length]; csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length); return fromEncrypt; } catch(CryptographicException e) { Console.WriteLine("A Cryptographic error occurred: {0}", e.Message); return null; } } static void Main(string[] args) { System.Text.Encoding utf8 = System.Text.Encoding.UTF8; Console.WriteLine("請輸入加密前的字串:"); string str = Console.ReadLine(); Console.WriteLine("原始字串為: " + str); byte[] data = utf8.GetBytes(str); System.Console.WriteLine("開始CBC加密解密"); byte[] strEncode = Program.Des3EncodeCBC(key, iv, data); string base64Str = Convert.ToBase64String(strEncode); System.Console.WriteLine("以BASE64編碼輸出加密後的byte為:" + base64Str); for (int i = 0; i < strEncode.Length; i++) // 輸出加密後的strEncode每位元組的內容 { Console.WriteLine("Encode : byte[" + i + "] " + strEncode[i]); } byte[] strDecode = Program.Des3DecodeCBC(key, iv, strEncode); string strGet = utf8.GetString(strDecode); Console.WriteLine("解密後的字串內容為:" + strGet + ",長度為" + strGet.Length); for (int i = 0; i < strDecode.Length; i++) // 輸出加密後的strDecode每位元組的內容 { Console.WriteLine("Decode byte[" + i + "] " + strDecode[i]); } // 去除生成byte的末尾的一些ASCII碼為0的字元 int len = 0; for (int i = 0; i < strDecode.Length; i++) { if (strDecode[i] != 0) len++; } byte[] strDecodeEmit = new byte[len]; for (int i = 0; i < len; i++) { strDecodeEmit[i] = strDecode[i]; } System.Console.WriteLine("去掉末尾0後獲得的字串為:" + utf8.GetString(strDecodeEmit) + ",長度為:" + utf8.GetString(strDecodeEmit).Length); System.Console.ReadLine(); } } }
執行例子如下圖所示: