近日,在做Android设备与PC端进行通讯时遇到了要求信息加解密的问题。经过测试,如下的方法可行。
在调试时也遇到了“在DES解密时候出现pad block corrupted错误”,一并解决了。具体见代码部分。
1、用C#程序进行数据的加密,加密使用DEC算法
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Security.Cryptography;
namespace Utility
{
/// <summary>
/// 类名称 :CryptTools
/// 类说明 :加解密算法
/// </summary>
public class CryptTools
{
/// <summary>
/// 方法说明 :加密方法
/// </summary>
/// <param name="content">需要加密的明文内容</param>
/// <param name="secret">加密密钥</param>
/// <returns>返回加密后密文字符串</returns>
public static string Encrypt(string content, string secret)
{
if ((content == null) || (secret == null) || (content.Length == 0) || (secret.Length == 0))
throw new ArgumentNullException("Invalid Argument");
byte[] Key = GetKey(secret);
byte[] ContentByte = Encoding.Unicode.GetBytes(content);
MemoryStream MSTicket = new MemoryStream();
MSTicket.Write(ContentByte, 0, ContentByte.Length);
byte[] ContentCryptByte = Crypt(MSTicket.ToArray(), Key);
string ContentCryptStr = Encoding.ASCII.GetString(Base64Encode(ContentCryptByte));
return ContentCryptStr;
}
/// <summary>
/// 方法说明 :解密方法
/// </summary>
/// <param name="content">需要解密的密文内容</param>
/// <param name="secret">解密密钥</param>
/// <returns>返回解密后明文字符串</returns>
public static string Decrypt(string content, string secret)
{
if ((content == null) || (secret == null) || (content.Length == 0) || (secret.Length == 0))
throw new ArgumentNullException("Invalid Argument");
byte[] Key = GetKey(secret);
byte[] CryByte = Base64Decode(Encoding.ASCII.GetBytes(content));
byte[] DecByte = Decrypt(CryByte, Key);
byte[] RealDecByte;
string RealDecStr;
RealDecByte = DecByte;
byte[] Prefix = new byte[Constants.Operation.UnicodeReversePrefix.Length];
Array.Copy(RealDecByte, Prefix, 2);
if (CompareByteArrays(Constants.Operation.UnicodeReversePrefix, Prefix))
{
byte SwitchTemp = 0;
for (int i = 0; i < RealDecByte.Length - 1; i = i + 2)
{
SwitchTemp = RealDecByte[i];
RealDecByte[i] = RealDecByte[i + 1];
RealDecByte[i + 1] = SwitchTemp;
}
}
RealDecStr = Encoding.Unicode.GetString(RealDecByte);
return RealDecStr;
}
//使用TripleDES加密 ,三倍DES加密
public static byte[] Crypt(byte[] source, byte[] key)
{
if ((source.Length == 0) || (source == null) || (key == null) || (key.Length == 0))
{
throw new ArgumentException("Invalid Argument");
}
TripleDESCryptoServiceProvider dsp = new TripleDESCryptoServiceProvider();
dsp.Mode = CipherMode.ECB;
ICryptoTransform des = dsp.CreateEncryptor(key, null);
return des.TransformFinalBlock(source, 0, source.Length);
}
//使用TripleDES解密 来处理,三倍DES解密
public static byte[] Decrypt(byte[] source, byte[] key)
{
if ((source.Length == 0) || (source == null) || (key == null) || (key.Length == 0))
{
throw new ArgumentNullException("Invalid Argument");
}
TripleDESCryptoServiceProvider dsp = new TripleDESCryptoServiceProvider();
dsp.Mode = CipherMode.ECB;
ICryptoTransform des = dsp.CreateDecryptor(key, null);
byte[] ret = new byte[source.Length + 8];
int num;
num = des.TransformBlock(source, 0, source.Length, ret, 0);
ret = des.TransformFinalBlock(source, 0, source.Length);
ret = des.TransformFinalBlock(source, 0, source.Length);
num = ret.Length;
byte[] RealByte = new byte[num];
Array.Copy(ret, RealByte, num);
ret = RealByte;
return ret;
}
//原始base64编码
public static byte[] Base64Encode(byte[] source)
{
if ((source == null) || (source.Length == 0))
throw new ArgumentException("source is not valid");
ToBase64Transform tb64 = new ToBase64Transform();
MemoryStream stm = new MemoryStream();
int pos = 0;
byte[] buff;
while (pos + 3 < source.Length)
{
buff = tb64.TransformFinalBlock(source, pos, 3);
stm.Write(buff, 0, buff.Length);
pos += 3;
}
buff = tb64.TransformFinalBlock(source, pos, source.Length - pos);
stm.Write(buff, 0, buff.Length);
return stm.ToArray();
}
//原始base64解码
public static byte[] Base64Decode(byte[] source)
{
if ((source == null) || (source.Length == 0))
throw new ArgumentException("source is not valid");
FromBase64Transform fb64 = new FromBase64Transform();
MemoryStream stm = new MemoryStream();
int pos = 0;
byte[] buff;
while (pos + 4 < source.Length)
{
buff = fb64.TransformFinalBlock(source, pos, 4);
stm.Write(buff, 0, buff.Length);
pos += 4;
}
buff = fb64.TransformFinalBlock(source, pos, source.Length - pos);
stm.Write(buff, 0, buff.Length);
return stm.ToArray();
}
/**
* 把密钥转化为2进制byte[] 如果大于 24byte就取前24位 作为 密钥
* */
public static byte[] GetKey(string secret)
{
if ((secret == null) || (secret.Length == 0))
throw new ArgumentException("Secret is not valid");
byte[] temp;
ASCIIEncoding ae = new ASCIIEncoding();
temp = Hash(ae.GetBytes(secret));
byte[] ret = new byte[Constants.Operation.KeySize];
int i;
if (temp.Length < Constants.Operation.KeySize)
{
System.Array.Copy(temp, 0, ret, 0, temp.Length);
for (i = temp.Length; i < Constants.Operation.KeySize; i++)
{
ret[i] = 0;
}
}
else
System.Array.Copy(temp, 0, ret, 0, Constants.Operation.KeySize);
return ret;
}
//比较两个byte数组是否相同
public static bool CompareByteArrays(byte[] source, byte[] dest)
{
if ((source == null) || (dest == null))
throw new ArgumentException("source or dest is not valid");
bool ret = true;
if (source.Length != dest.Length)
return false;
else
if (source.Length == 0)
return true;
for (int i = 0; i < source.Length; i++)
if (source[i] != dest[i])
{
ret = false;
break;
}
return ret;
}
//使用md5计算散列
public static byte[] Hash(byte[] source)
{
if ((source == null) || (source.Length == 0))
throw new ArgumentException("source is not valid");
MD5 m = MD5.Create();
return m.ComputeHash(source);
}
/// <summary>
/// 对传入的明文密码进行Hash加密,密码不能为中文
/// </summary>
/// <param name="oriPassword">需要加密的明文密码</param>
/// <returns>经过Hash加密的密码</returns>
public static string HashPassword(string oriPassword)
{
if (string.IsNullOrEmpty(oriPassword))
throw new ArgumentException("oriPassword is valid");
ASCIIEncoding acii = new ASCIIEncoding();
byte[] hashedBytes = Hash(acii.GetBytes(oriPassword));
StringBuilder sb = new StringBuilder(30);
foreach (byte b in hashedBytes)
{
sb.AppendFormat("{0:X2}", b);
}
return sb.ToString();
}
//注意:密钥必须为8位
const string m_strEncryptKey = "abcd1234";
#region DES加密字符串
/// <summary>
/// 加密字符串
/// </summary>
/// <param name="p_strInput">明码</param>
/// <returns>加密后的密码</returns>
public static string DesEncryptFixKey(string p_strInput)
{
byte[] byKey = null;
byte[] IV = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };
try
{
byKey = System.Text.Encoding.UTF8.GetBytes(m_strEncryptKey.Substring(0, 8));
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
byte[] inputByteArray = Encoding.UTF8.GetBytes(p_strInput);
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(byKey, IV), CryptoStreamMode.Write);
cs.Write(inputByteArray, 0, inputByteArray.Length);
cs.FlushFinalBlock();
return Convert.ToBase64String(ms.ToArray());
}
catch (System.Exception ex)
{
throw (ex);
}
}
#endregion
#region DES解密字符串
/// <summary>
/// 解密字符串
/// </summary>
/// <param name="this.inputString">加了密的字符串</param>
/// <param name="decryptKey">密钥</param>
public static string DesDecryptFixKey(string p_strInput)
{
byte[] byKey = null;
byte[] IV = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };
byte[] inputByteArray = new Byte[p_strInput.Length];
try
{
byKey = System.Text.Encoding.UTF8.GetBytes(m_strEncryptKey.Substring(0, 8));
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
inputByteArray = Convert.FromBase64String(p_strInput);
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(byKey, IV), CryptoStreamMode.Write);
cs.Write(inputByteArray, 0, inputByteArray.Length);
cs.FlushFinalBlock();
System.Text.Encoding encoding = new System.Text.UTF8Encoding();
return encoding.GetString(ms.ToArray());
}
catch (System.Exception ex)
{
throw (ex);
}
}
#endregion
}
/// <summary>
/// 类名称 :Constants
/// 类说明 :加解密算法常量.
/// </summary>
public class Constants
{
public struct Operation
{
public static readonly int KeySize = 24;
public static readonly byte[] UnicodeOrderPrefix = new byte[2] { 0xFF, 0xFE };
public static readonly byte[] UnicodeReversePrefix = new byte[2] { 0xFE, 0xFF };
}
}
}
2、Android设备端解密方法,JAVA语言
package rtx;
import javax.crypto.*;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;import java.security.Key;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
import android.util.Base64;
import android.util.Log;
/**
* 使用DES加密和解密工具类
* */
public class CryptoTools {
/** 生成密钥的key值 */
private Key mKey;
private byte[] DESkey;// 设置密钥,略去
private byte[] DESIV = { 0x12, 0x34, 0x56, 0x78, (byte) 0x90, (byte) 0xAB,
(byte) 0xCD, (byte) 0xEF };// 设置向量,略去
private AlgorithmParameterSpec iv = null;// 加密算法的参数接口,IvParameterSpec是它的一个实现
public CryptoTools() {
try {
this.DESkey = "abcd1234".getBytes("UTF-8");// 设置密钥
DESKeySpec keySpec = new DESKeySpec(DESkey);// 设置密钥参数
iv = new IvParameterSpec(DESIV);// 设置向量
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");// 获得密钥工厂
mKey = keyFactory.generateSecret(keySpec);// 得到密钥对象
} catch (Exception ex) {
}
}
/**
* 加密String明文输入,String密文输出
*
* @param inputString
* 待加密的明文
* @return 加密后的字符串
*/
public String getEncString(String inputString) {
byte[] byteMi = null;
byte[] byteMing = null;
String outputString = "";
try {
byteMing = inputString.getBytes("UTF8");
byteMi = this.getEncCode(byteMing);
byte[] temp = Base64.encode(byteMi, Base64.DEFAULT);
outputString = new String(temp);
} catch (Exception e) {
Log.e("SSEC_RTX", "根据密钥加密字符串出错: ", e);
} finally {
byteMing = null;
byteMi = null;
}
return outputString;
}
/**
* 解密 以String密文输入,String明文输出
*
* @param inputString
* 解密后的字符串
* @return 解密后的字符串
*/
public String getDecString(String inputString) {
byte[] byteMing = null;
byte[] byteMi = null;
String strMing = "";
try {
byteMi = Base64.decode(inputString.getBytes(), Base64.DEFAULT);
byteMing = this.getDesCode(byteMi);
strMing = new String(byteMing, "UTF8");
} catch (Exception e) {
Log.e("SSEC_RTX", "根据密钥解密字符串出错: ", e);
} finally {
byteMing = null;
byteMi = null;
}
return strMing;
}
/**
* 加密以byte[]明文输入,byte[]密文输出
*
* @param byteS
* 待加密的字节码
* @return 加密后的字节码
*/
private byte[] getEncCode(byte[] byteS) {
byte[] byteFina = null;
Cipher cipher;
try {
// 得到加密对象Cipher
cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, mKey, iv);
byteFina = cipher.doFinal(byteS);
} catch (Exception e) {
Log.e("RTX", "根据密钥加密字节码出错: ", e);
} finally {
cipher = null;
}
return byteFina;
}
/**
* 解密以byte[]密文输入,以byte[]明文输出
*
* @param byteD
* 带解密的字节码
* @return 解密后的字节码
*/
private byte[] getDesCode(byte[] byteD) {
Cipher cipher;
byte[] byteFina = null;
try {
//得到加密对象Cipher
cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, mKey, iv);
byteFina = cipher.doFinal(byteD);
} catch (Exception e) {
Log.e("RTX", "根据密钥解密字节码出错: ", e);
} finally {
cipher = null;
}
return byteFina;
}}