大二实习期间第一次做的一个完整的小工具,我只是一个初学者,很多东西只是自己浅显的理解,记录一下!
两个礼拜前对C#的了解仅限于知道可做Unity开发,DES算法也只在计算机网络中听过,感觉完全无从下手,但功夫不负有心人,历时两个礼拜断断续续的写出来了。
任务要求:
1.采用winform开发
2.可单独加密一个文件
3.可加密整个目录中的文件
4.加密算法使用DES
5.加密后的文件扩展名改为“cfs”
6.密文的前5个字节为原文件的扩展名,以便于解密时还原文件
即从第6个字节开始为原文件经过des加密的密文
7.可解密还原文件
8.界面上可显示待加密/解密的文件数,及当前加密/解密的进度
在自己做的过程中,我个人觉得难点在于为了增强这个工具的健壮性比如留前五个字节这种地方,以下为具体体现:
1、要将原文件的扩展名保存并写入密文的前五个字节,在解密时取出作为解密后还原的文件扩展名。开始不知道怎么取它的扩展名,最后问大佬才发现有.Extension这个获取扩展的好东西,不用我再以自己垃圾的算术能力去截取原文件名的长度,大家写的时候可以用.Extension方法,我这种笨办法是为了写自己当时的一个想法。由于刚学了一个礼拜对C#的用法不太了解,就要夸夸F12了,该用什么类型一目了然,报错也是清清楚楚。在此说一句边写边学虽然比较累但是学的真的快。
2、大家都知道DES算法必须用到“流”,标准的DES写法是用了using语句,可以不用手动去关闭流。在加密解密过程中,开辟了一个缓冲空间buffer(我写的是【1024*1024】这个随便定义只要不低于1K不大于总长度就行)。在进度条的编写中也是要借助这个buffer,这个真的难了我好久,线程什么的都没有学,无从下手。用for循环读取文件,因为已经知道了密文的长度,所以就用其除以buffer的长度,循环一次就更新进度,当然一般加、解密都是非常快的,要进度条的用处不大,但也要考虑有大文件比如视频、音频之类的,之前就没想到(因为我电脑里没这么大的),格局小了。做了个假死的摆设进度条,只能说看的过去好像是这么回事,用户看到进度条一下就好就够了,但自己知道并不能实现服务器与UI之间的真实联系,程序做了什么我能直观简洁的体现在界面上,这一点我觉得很关键。这一步真的耗了很长时间,不断试错,时刻体会增删改查,边写边改。可能在大家眼里这就是个举一反三的对称算法,没什么难的,但大一大二没用心学有时候就是一个个小问题挡在你面前,一个跨不过去就没办法走下一步,但我相信一万小时定理,死磕到底!
DES算法参考这里C#DES对较大文件和文件字节数组对象加密解密_bruce135lee的专栏-CSDN博客
PS:自己写注释真的帮助很大,.NET平台针不戳。
下面是具体代码:
public void PathLoad()
{
if (textBox1.Text == "")//若没选择要加密的文本文件
{
MessageBox.Show("请选择要加密的文件");
}
else
{
try
{
string strPath = textBox1.Text;//获取文件路径
int intLent = strPath.LastIndexOf("\\") + 1;//设置截取的起始位置
int intLong = strPath.Length;//设置截取的长度
string strName = strPath.Substring(intLent, intLong - intLent);//要加密的文件名称
int intTxt = strName.LastIndexOf(".");//设置截取的起始位置
int intTxtLeng = strName.Length;//设置截取的长度
string strTxt = strName.Substring(intTxt, intTxtLeng - intTxt);//取出文件的拓展名
strName = strName.Substring(0, intTxt);
string strOutName = strPath.Substring(0, strPath.LastIndexOf("\\") + 1) + strName + "加" + ".cfs";//加密后的文件名及路径s
strTxt = strTxt.PadRight(5, ' ');//获取原文件扩展名
key = 12345678;
byte[] desIv = new byte[] { 0xF, 0x56, 0x52, 0xCD, 0xFF, 0x3F, 0x5D, 0x4 };
string desKeyStr = key.ToString();
//string desiv = Iv.ToString();
Byte[] desKey = System.Text.Encoding.UTF8.GetBytes(desKeyStr.Substring(0,8)) ;//截取8位秘钥
FileStream ins = new FileStream(strPath, FileMode.Open, FileAccess.Read);//读取文件FileStream文件流,通过编码将字节数组转换成字符串
FileStream outs = new FileStream(strOutName, FileMode.OpenOrCreate, FileAccess.Write);//写入.cfs文件
outs.Write(System.Text.Encoding.UTF8.GetBytes(strTxt),0,5);//将原文件扩展名写入加密文件
outs.SetLength(5);//留出前五个字节的位置
byte[] buffer = new byte[1024 * 1024];//定义1M的字节数组,临时存放读入的流
long readLen = 0;
int len;
long totlen = ins.Length;//总共读入的流
DES des = new DESCryptoServiceProvider();
CryptoStream cs = new CryptoStream(outs, des.CreateEncryptor(desKey,desIv), CryptoStreamMode.Write) ;
while (readLen < totlen)
{
len = ins.Read(buffer, 0, buffer.Length);//0是buffer中的字节偏移量,从该偏移量开始写入从流中读取的数据
//byte[] encBuffer = DesClass.Encrypt(buffer, desKey, desIv);
//outs.Write(encBuffer, 0, len);
cs.Write(buffer, 0, len);
readLen += len;
Encoding.Unicode.GetString(buffer);
if (MessageBox.Show("加密成功!加密后的文件名及路径为:\n" + strOutName + ",是否删除文件", "提示信息", MessageBoxButtons.YesNo) == DialogResult.Yes)
{
File.Delete(strPath);//清除指定文件
}
else
{
textBox1.Text = "";
}
}
cs.Close();
outs.Close();
ins.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
public void PathLoad2()
{
if (textBox1.Text == "")//若没选择要解密的文本文件
{
MessageBox.Show("请选择要解密的文件");//如果没有选择则弹出提示
}
else
{
try
{ string strPath = textBox1.Text;//解密文件的路径
int intLent = strPath.LastIndexOf("\\") + 1;//设置截取的起始位置
int intLong = strPath.Length;//设置截取的长度
string strName = strPath.Substring(intLent, intLong - intLent);//要解密的文件名称
int intTxt = strName.LastIndexOf(".");//设置截取的起始位置
int intTxtLeng = strName.Length;//设置截取的长度
string strTxt = strName.Substring(intTxt, intTxtLeng - intTxt);//获取文件拓展名
strName = strName.Substring(0, intTxt);
string strInName = strPath.Substring(0, strPath.LastIndexOf("\\") + 1) + strName + "解" + ".txt";//解密后的文件名及路径
key = 12345678;
byte[] desIv = new byte[] { 0xF, 0x56, 0x52, 0xCD, 0xFF, 0x3F, 0x5D, 0x4 };
string desKeyStr = key.ToString();
byte[] desKey = System.Text.Encoding.UTF8.GetBytes(desKeyStr.Substring(0, 8));
FileStream ins = new FileStream(strPath, FileMode.Open, FileAccess.Read);
FileStream outs = new FileStream(strInName, FileMode.OpenOrCreate, FileAccess.Write);
char[] ch = new char[outs.Length];
byte[] buffer = new byte[1024 * 1024];
outs.SetLength(0);
buffer = Encoding.UTF8.GetBytes(ch);
ins.Seek(6, SeekOrigin.Begin);//从第6个字节开始读取
long readLen = 0;
long totLen = ins.Length;
int len;
DES des = new DESCryptoServiceProvider();
CryptoStream cs = new CryptoStream(outs, des.CreateDecryptor(desKey, desIv), CryptoStreamMode.Write);
while (readLen < totLen)
{
len = ins.Read(buffer, 0, buffer.Length);
//byte[] debuffer = DesClass.Encrypt(buffer, key, Iv);
//outs.Write(debuffer, 0, len);
cs.Write(buffer, 0, len);
readLen += len;
if (MessageBox.Show("解密成功!解密后的文件名及路径为:\n" + strInName + ",是否删除文件", "提示信息", MessageBoxButtons.YesNo) == DialogResult.Yes)
{
File.Delete(strPath);
}
else
{
textBox1.Text = "";
}
}
cs.Close();
outs.Close();
ins.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
这些是用到的控件:
DES加密解密网上很多介绍在此不过多赘述,但都是些对于命令行上小的字节数组加密,像文件这种内存在G以上的,就得好好改进一番,起码对我来说是要钻研的。