最近在做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);
        }
    }


Jeason Zhao (沈胜衣,斛律光) ------雪饮再现,一个人的江湖
我知道我是谁,我是沈胜衣,默默的活着,就像空气。