近日,在做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; }}