最近在工作中遇到将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();
}
}
}
运行例子如下图所示: