您的位置:首页 > 编程语言 > C#

关于对象实例序列化加密解密并写入文件的技巧

2015-08-19 10:37 561 查看
最近在网上看见一些文章在讨论如何将一个对象或对象的列表序列化并加密后存储到文件中的讨论,有很多方法针对英文字符串和数值型数据都能很好完成,但是加入中文,或者加入一些诸如DateTime类型的数据后,在反序列化或解密时总是会出现异常,不能正确执行,经过一天的测试和比对,发现要解决这个问题,要注意以下几点
1、只讨论TripleDES加密算法,其它算法也类似,密钥Key和密钥向量IV在加密和解密时应一致,就是说要使用和加密相同的Key和IV进行解密(有的文章说要Key和IV一致,没有必要,也做不到!),KEY最好是24字节,IV最好是8字节(其他算法根据算法要求)。
2、加密处理顺序:序列化-->加密-->写入文件。解密处理顺序:读取文件-->解密-->反序列化
3、序列化后的结果要保存到byte[ ]中,序列化时建议使用MemoryStream作为缓冲区,直接使用ToArray方法将字节数组返回,不要用任何EnCoding的GetBytes方法。
4、将序列化得到的字节数组直接进行加密,不要把它转换成字符串或者字符。
5、加密的结果也直接以字节数组的形式写入文件,不要使用BinaryWriter之类会自己加入一些编码字符的写入器。
6、解密时也相同,直接用字节数组,不要有什么转换,一路byte[ ]到底,反序列化会自动将字节数据转换为合适的数据类型存入对象的对应字段。

class TripleDESApplay
{
private TripleDESCryptoServiceProvider tp;

public byte[] DESKey
{
get { return tp.Key; }
set
{
if(value.Length<24)
{
throw new ArgumentException("密钥Key的长度应该为24个字节!");
}
else
{
tp.Key = value.Take(24).ToArray();
}
}
}

public byte[] DESIV
{
get { return tp.IV; }
set
{
if(value.Length<8)
{
throw new ArgumentException("密钥向量IV的长度应该为24个字节!");
}
else
{
tp.IV = value.Take(8).ToArray();
}
}
}

public TripleDESApplay()
{
tp = new TripleDESCryptoServiceProvider();
tp.GenerateKey();
tp.GenerateIV();
}
public TripleDESApplay(byte[] key,byte[] iv)
{
tp = new TripleDESCryptoServiceProvider();
DESKey = key;
DESIV = iv;
}
/// <summary>
/// 将字节数组进行加密,并返回加密后的字节数组
/// </summary>
/// <param name="encryptBytes">要加密的字节数组</param>
/// <returns>加密后的字节数组</returns>
public byte[] EncryptBytes(byte[] encryptBytes)
{
byte[] result = null;
try
{
//用来存储加密结果的内存流
using (MemoryStream s = new MemoryStream())
{
//创建加密流
using (CryptoStream cs = new CryptoStream(s, tp.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(encryptBytes, 0, encryptBytes.Length);
cs.FlushFinalBlock();
//根据Stream中加密的数据将其读出到result字节数组中
//重置Stream的指针位置到开始处
s.Seek(0, SeekOrigin.Begin);
//读出Stream中的字节到result字节数组
result = s.ToArray();
}
}
}
catch(Exception e)
{
throw e;
}
return result;
}
/// <summary>
/// 对字符串进行加密,并返回加密后的字节数组
/// </summary>
/// <param name="encryptString">要加密的字符串</param>
/// <returns>加密后的字节数组</returns>
public byte[] EncryptString(string encryptString)
{
byte[] result = null;
try
{
byte[] source = Encoding.Default.GetBytes(encryptString);
result = EncryptBytes(source);
}
catch(Exception e)
{
throw e;
}
return result;

}
/// <summary>
/// 将使用TripleDES算法加密的字节数组解密
/// </summary>
/// <param name="decryptBytes">加密过的字节数组</param>
/// <returns>解密后的字节数组</returns>
public byte[] DecryptBytes(byte[] decryptBytes)
{
byte[] result = null;
try
{
using (MemoryStream s = new MemoryStream(decryptBytes, 0, decryptBytes.Length))
{
using (CryptoStream cs = new CryptoStream(s, tp.CreateDecryptor(), CryptoStreamMode.Read))
{
result = new byte[decryptBytes.Length];
cs.Read(result, 0, decryptBytes.Length);
}
}
}
catch(Exception e)
{
throw e;
}
return result;
}
/// <summary>
/// 将使用TripleDES算法加密后生成的字节数组解密,并返回解密后的字符串
/// </summary>
/// <param name="decryptBytes">加密后的字节数组</param>
/// <returns>解密后的字符串</returns>
public string DecryptString(byte[] decryptBytes)
{
byte[] result = null;
try
{
result = DecryptBytes(decryptBytes);
}
catch(Exception e)
{
throw e;
}
return Encoding.Default.GetString(result);
}
/// <summary>
/// 序列化对象
/// </summary>
/// <param name="obj">指定进行序列化的对象,对象应该具有[Serializable]特性</param>
/// <returns>序列化后的字节数组</returns>
public byte[] SerializeObject(object obj)
{
byte[] result = null;
try {
using (MemoryStream s = new MemoryStream())
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(s, obj);
result = s.ToArray();
}
}
catch(Exception e)
{
9684
throw e;
}

return result;
}
/// <summary>
/// 反序列化对象
/// </summary>
/// <typeparam name="T">指定反序列化对象的类型</typeparam>
/// <param name="seriaBytes">反序列化的字节数组</param>
/// <returns>反序列化后的对象</returns>
public T DeserializeObject<T>(byte[] seriaBytes) where T :class
{
T obj = default(T);
try
{
using (MemoryStream s = new MemoryStream(seriaBytes, 0, seriaBytes.Length))
{
BinaryFormatter bf = new BinaryFormatter();
obj = bf.Deserialize(s) as T;
}
}
catch (Exception e)
{

throw e;
}
return obj;
}
/// <summary>
/// 将字节数组写入指定的文件,如果文件已经存在会覆盖原来的文件,如果文件不存在会新建一个文件
/// </summary>
/// <param name="filename">指定文件的完整路径名</param>
/// <param name="outBytes">要写入的字节数组</param>
public void WriteBytesToFile(string filename,byte[] outBytes)
{
try
{
using (FileStream fWriter = new FileStream(filename, FileMode.Create, FileAccess.Write))
{
fWriter.Write(outBytes, 0, outBytes.Length);
fWriter.Close();
}
}
catch (Exception e)
{

throw e;
}
}
/// <summary>
/// 从指定文件读取字节数组
/// </summary>
/// <param name="filename">指定文件的完整路径名</param>
/// <returns>字节数组</returns>
public byte[] ReadBytesFromFile(string filename)
{
byte[] result = null;
try
{
using (FileStream fReader = new FileStream(filename, FileMode.Open, FileAccess.Read))
{
result = new byte[fReader.Length];
fReader.Read(result, 0, result.Length);
}
}
catch (Exception e)
{

throw e;
}
return result;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息