原文:
C语言单片和C#语言服务器端DES及3DES加密的实现
公司最近在做单片机和C#语言的通信。用的是Socket通信。传输的数据是明文,后来 在会上讨论准备用DES加密(对称加密)来做。
双方约定 相应的“密钥”。
以前做的加密一般都是用C#加密和C#解密。一直以为是个简单的问题,现在和用C写的单片机通信的时候却出了问题。
问题是什么呢?
我找了几个在线加密 解密的网站,还下了几个加密解密的工具。结果相同的数据,用相同的密钥却得到不同的结果。
而且现在网上C语言实现的DES资料基本上是不靠谱,好多是错误的,都是你抄我,我抄你,抄来抄去,抄到最后没有一个完整实现DES几种模式加密的。
没办法,赶紧去找DES的原理来看,好研究了一番现在终于解决完成。保证了自己写的代码和几种工具一样的结果。现在将代码奉上,希望能帮上大家的忙。
一,ECB模式
ECB(Electronic
Code
book电码本)模式,相对简单,将数据按照每8字节一段进行DES加解密的(一次加解密操作必须是8字节,这是算法决定的),如果最后一段不足8字节,
则按照需要补0x00或者0xFF进行计算.之后按照数据顺序将所有的数据连接在一起。
这个模式说了这么多,我也不明白啥意思,不过 现在网上流传的C语言实现的DES加密算法基本上都是这种模式。
采用这个模式以后 ,设置不设置 加密向量都没有用的。
请注意,我在这里实现的都是 采用这种模式,所以 文中出现的加密向量有关的语句,你都可以把它给无视掉,你删除掉它,也会得到相同的结果。
二,CBC模式
CBC(Cipher-block chaining密文分组链接)模式,该模式使得各段数据存在一些联系,实现原理比较复杂,我也没有搞懂,不过以前写C#代码的时候,有个加密向量,就像下面代码这样子的Byte数组
private static byte[] IV = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF };
我一直不明白它有什么用,现在我终于明白了,C#默认的就是这种模式。
现在奉上C#的实现代码:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
string str = "abcdefgh";
string str1 = "1234567887654321";
string str2 = DES3Encrypt(str, str1);
Console.WriteLine(str2);
Console.WriteLine(DES3Decrypt(str2, str1));
}
#region DES加解密
private static byte[] IV = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF };///这段代码可以删除掉
//默认密钥向量
//private static byte[] IV = { 0xEF, 0xCD, 0xAB, 0x89, 0x67, 0x45, 0x23, 0x01 };
/// <summary>
/// DES加密
/// </summary>
/// <param name="input">待加密的字符串</param>
/// <param name="key">加密密钥</param>
/// <returns></returns>
public static string Encrypt(string pToEncrypt, string sKey)
{
DESCryptoServiceProvider provider = new DESCryptoServiceProvider();
provider.Mode = CipherMode.CBC;
//provider.Padding = PaddingMode.None;
byte[] bytes = Encoding.Default.GetBytes(pToEncrypt);
provider.Key = Encoding.ASCII.GetBytes(sKey);
provider.IV = Encoding.ASCII.GetBytes(sKey);
/* 创建一个内存流对象 */
MemoryStream stream = new MemoryStream();
/* 创建一个加密流对象 */
CryptoStream stream2 = new CryptoStream(stream, provider.CreateEncryptor(), CryptoStreamMode.Write);
/* 将要加密的文本写到加密流中 */
stream2.Write(bytes, 0, bytes.Length);
/* 更新缓冲 */
stream2.FlushFinalBlock();
/* 获取加密过的文本 */
StringBuilder builder = new StringBuilder();
foreach (byte num in stream.ToArray())
{
builder.AppendFormat("{0:X2}", num);
}
stream2.Close();
stream.Close();
return builder.ToString();
//return Convert.ToBase64String(stream.ToArray());
//byte[] bytes4 = stream.ToArray();
//string str=Encoding.Default.GetString(bytes4);
//return str;
}
/// <summary>
/// DES解密
/// </summary>
/// <param name="input">待解密的字符串</param>
/// <param name="key">解密密钥,要求为8位,和加密密钥相同</param>
/// <returns>解密成功返回解密后的字符串,失败返源串</returns>
public static string Decrypt(string DecryptString, string Key)
{
try
{
//byte[] inputByteArray = Convert.FromBase64String(DecryptString);
/**
**将一个字符串转16进制字节数组而已
**/
byte[] inputByteArray = new byte[DecryptString.Length / 2];
for (int x = 0; x < DecryptString.Length / 2; x++)
{
int i = (Convert.ToInt32(DecryptString.Substring(x * 2, 2), 16));
inputByteArray[x] = (byte)i;
}
//byte[] inputByteArray = Encoding.UTF8.GetBytes(DecryptString);
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
des.Mode = CipherMode.CBC;
des.Padding = PaddingMode.None;
des.Key = Encoding.ASCII.GetBytes(Key);
des.IV = Encoding.ASCII.GetBytes(Key);
MemoryStream mStream = new MemoryStream();
CryptoStream cStream = new CryptoStream(mStream, des.CreateDecryptor(), CryptoStreamMode.Write);
cStream.Write(inputByteArray, 0, inputByteArray.Length);
cStream.FlushFinalBlock();
mStream.Close();
cStream.Close();
return Encoding.Default.GetString(mStream.ToArray());
}
catch
{
return "";
}
}
#endregion
#region 3DES 加密解密
public static string DES3Encrypt(string data, string key)
{
TripleDESCryptoServiceProvider DES = new TripleDESCryptoServiceProvider();
//DES.GenerateKey();
//byte[] cKey = DES.Key;
DES.Key = ASCIIEncoding.ASCII.GetBytes(key);
DES.Mode = CipherMode.ECB;
DES.Padding = PaddingMode.None;
ICryptoTransform DESEncrypt = DES.CreateEncryptor();
byte[] Buffer = ASCIIEncoding.ASCII.GetBytes(data);
byte[] result = DESEncrypt.TransformFinalBlock(Buffer, 0, Buffer.Length);
StringBuilder builder = new StringBuilder();
foreach (byte num in result)
{
builder.AppendFormat("{0:X2}", num);
}
return builder.ToString();
//return Convert.ToBase64String(DESEncrypt.TransformFinalBlock(Buffer, 0, Buffer.Length));
}
public static string DES3Decrypt(string DecryptString, string key)
{
TripleDESCryptoServiceProvider DES = new TripleDESCryptoServiceProvider();
//DES.GenerateKey();
DES.Key = ASCIIEncoding.ASCII.GetBytes(key);
DES.Mode = CipherMode.ECB;
DES.Padding = PaddingMode.None;
ICryptoTransform DESDecrypt = DES.CreateDecryptor();
string result = "";
try
{
//byte[] Buffer = Convert.FromBase64String(data);
/*字符串转16进制字节数组*/
byte[] inputByteArray = new byte[DecryptString.Length / 2];
for (int x = 0; x < DecryptString.Length / 2; x++)
{
int i = (Convert.ToInt32(DecryptString.Substring(x * 2, 2), 16));
inputByteArray[x] = (byte)i;
}
//byte[] Byteresult = DESDecrypt.TransformFinalBlock(inputByteArray, 0, inputByteArray.Length);
//StringBuilder builder = new StringBuilder();
//foreach (byte num in Byteresult)
//{
// builder.AppendFormat("{0:X2}", num);
//}
//return builder.ToString();
result = ASCIIEncoding.ASCII.GetString(DESDecrypt.TransformFinalBlock(inputByteArray, 0, inputByteArray.Length));
}
catch (Exception e)
{
}
return result;
}
#endregion
}
}
然后我们对比一下效果:
这是一个工具加密后的效果,使用的是DES。
要加密的字符串是:abcdefg
加密的密钥为:12345678

这是C#的加密 解密效果图:

OK一样的效果。
然后再把单片机那那边的实现效果给展示一下:
当然C语言版本的是我下载别人的代码,链接在这里
http://files.cnblogs.com/erwin/yxyDES2_C_Edition.rar
