最近在做Java和DotNet之间的互通,本着简单的原则,我不使用HTTPS对通道进行加密,所以采用的是自己加密所有的数据的处理方式,即使在这种情况之下,安全性不能被保证,但是基础的数据安全是可以了,毕竟是行业应用软件,试图破解的渠道比较少,而且数据针对性太强,没有太大的意义。
我的设计是:
-
几乎所有在Web服务和客户端之间的交互数据都进行加密,数字和日期除外
-
加密之后都生成BASE64编码,所以几乎所有的参数都是字符串
-
客户端和服务器共享同样的密码生成机制,一般是时间戳加上固定密码的格式,客户端和服务器都使用这个密码进行加密和解密。
-
传递的对象,先经过序列化之后,加密成Byte数组,然后转换成BASE64编码,反之亦然。
-
如果函数没有参数,必须设置一个默认的参数值,参数值进行加密,保障访问的源是合法的访问。
一开始我考虑使用BASE64+MD5进行摘要,但是很遗憾,这种摘要不能反向,也就是说在实际的传输过程中,还是需要携带明文信息,信息在传输过程中可以被轻易的查看。所以,我选择了AES加密协议(尝试过其他的协议,都未能在Java和DotNet之间正确的加密和解密)。
在Java和DotNet的AES之间,有点遗憾的是JAVA的密码强度只能设置成16位的密码,所以在代码中进行了折中处理,这种处理会带来密码的不安全。所幸,我们的安全系数也不需要那么高。
贴出代码来
Java
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import java.security.NoSuchAlgorithmException;
import java.io.UnsupportedEncodingException;
public class AES
{
private static final String Encoding = "UTF8";
private static final String AES = "AES";
public static String decrypt(String strSrcString,String strPassword)
throws Exception
{
if(null == strSrcString || strSrcString.trim().length() < 1)
{
return null;
}
strPassword = generateKey(strPassword);
byte[] raw = strPassword.getBytes(Encoding);
SecretKeySpec skeySpec = new SecretKeySpec(raw,AES);
Cipher cipher = Cipher.getInstance(AES);
cipher.init(Cipher.DECRYPT_MODE,skeySpec);
byte[] encrypted1 = new BASE64Decoder().decodeBuffer(strSrcString);
byte[] original = cipher.doFinal(encrypted1);
String originalString = new String(original);
return originalString;
}
public static String encrypt(String strSrcString,String strPassword)
throws Exception
{
if(null == strSrcString || strSrcString.trim().length() < 1)
{
return null;
}
strPassword = generateKey(strPassword);
byte[] raw = strPassword.getBytes(Encoding);
SecretKeySpec skeySpec = new SecretKeySpec(raw,AES);
Cipher cipher = Cipher.getInstance(AES);
cipher.init(Cipher.ENCRYPT_MODE,skeySpec);
byte[] encrypted = cipher.doFinal(strSrcString.getBytes());
return(new sun.misc.BASE64Encoder()).encode(encrypted);
}
private static String generateKey(String str)
throws NoSuchAlgorithmException,UnsupportedEncodingException
{
if(null == str)
{
str = "defaultpassword";
}
else if(str.length() < 1)
{
str = "emptypassword";
}
java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
md.update(str.getBytes(Encoding));
String strret = (new sun.misc.BASE64Encoder()).encode(md.digest());
while(strret.length() < 16)
{
strret += "%";
}
if(strret.length() > 16)
{
int nbegin = (strret.length() - 16) / 2;
strret = strret.substring(nbegin,nbegin + 16);
}
return strret;
}
public static void main(String[] args)
throws Exception
{
String strMessage = "中文输入法";
String strPassword = "a";
String desc = encrypt(strMessage,strPassword);
System.out.println(desc);
System.out.println(decrypt(desc,strPassword));
System.out.println(generateKey(""));
System.out.println(generateKey(""));
System.out.println(generateKey("a"));
System.out.println(generateKey("a"));
System.out.println(generateKey("A"));
System.out.println(generateKey("asdasdsadsadasdsadasdsad"));
System.out.println(generateKey("asdasdsadsadasdsadasdsad"));
}
}
C#
using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;
internal class AES
{
private static String generateKey(String str)
{
if (null == str)
{
str = "defaultpassword";
}
else if (str.Length < 1)
{
str = "emptypassword";
}
System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(str);
bytes = md5.ComputeHash(bytes);
md5.Clear();
String strret = Convert.ToBase64String(bytes);
while (strret.Length < 16)
{
strret += "%";
}
if (strret.Length > 16)
{
int nbegin = (strret.Length - 16) / 2;
strret = strret.Substring(nbegin, 16);
}
return strret;
}
public static string Encrypt(string toEncrypt, string strPassword)
{
strPassword = generateKey(strPassword);
byte[] keyArray = System.Text.Encoding.UTF8.GetBytes(strPassword);
byte[] toEncryptArray = System.Text.Encoding.UTF8.GetBytes(toEncrypt);
RijndaelManaged rDel = new RijndaelManaged();
rDel.Key = keyArray;
rDel.Mode = CipherMode.ECB;
rDel.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = rDel.CreateEncryptor();
byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
public static string Decrypt(string toDecrypt, string strPassword)
{
if (null == toDecrypt)
{
return toDecrypt;
}
strPassword = generateKey(strPassword);
byte[] keyArray = System.Text.Encoding.UTF8.GetBytes(strPassword);
byte[] toEncryptArray = Convert.FromBase64String(toDecrypt);
RijndaelManaged rDel = new RijndaelManaged();
rDel.Key = keyArray;
rDel.Mode = CipherMode.ECB;
rDel.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = rDel.CreateDecryptor();
byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
return System.Text.Encoding.UTF8.GetString(resultArray);
}
}