1. 程式人生 > >Java和C#中3DES的加密與解密

Java和C#中3DES的加密與解密

最近在工作中遇到將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();
        }
    }
}

執行例子如下圖所示: