C# 一个简单快速的电脑端文件加锁的小工具

有时候我们需要给电脑上的有些文件加密,之前都是用压缩工具进行加密压缩,但是太麻烦了而且还慢,于是我就自己构思写了一个小工具,用来快速的对文件进行加锁操作

具体原理是对文件的原数据和文件名进行部分异或运算,破坏文件的可读性

由于算法简单,追求速度,并且未对所有数据进行处理,所以这个小工具具有很大局限性,只能防防没有目的性且不太懂电脑的小白,遇见个稍微懂点了就没用了

看代码:

入口以及安全验证

namespace Locker {
    class Program {
        static void Main(string[] args) {
            while (true) {
                try {
                    Console.Write("code:");
                    var cmd = Console.ReadLine();
                    if (MD5(cmd) == GetCode_MD5()) { //匹配输入的验证码和配置文件中的验证码进行比较,实现简单的安全验证
                        FileLocker locker = new FileLocker();
                        locker.Process();
                    } else {
                        throw new Exception("error code!");
                    }
                } catch (Exception ex) {
                    Console.WriteLine(ex.Message);
                }
            }
        }
        /// <summary>
        /// 读取配置文件保存的md5加密字符串,防君子不防小人不用复杂的hash算法以及加盐
        /// </summary>
        static string GetCode_MD5() {
            var code_MD5 = ConfigurationSettings.AppSettings["code_MD5"];
            if (string.IsNullOrEmpty(code_MD5)) {
                throw new Exception("config file lost!");
            }
            return code_MD5;
        }
        /// <summary>
        /// 对字符串进行md5加密,得到32位大写字符串
        /// </summary>
        public static string MD5(string str) {
            byte[] array = new MD5CryptoServiceProvider().ComputeHash(Encoding.UTF8.GetBytes(str));
            return BitConverter.ToString(array).Replace("-", "");
        }
    }
}

配置文件:

其中的code_MD5的默认值是XOR127的hash字符串,即默认口令为XOR127

可以通过自己覆盖MD5值来改变口令

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7"/>
    </startup>
    <appSettings>
        <add key="code_MD5" value="5CA9E1DE9C4535946AB5888FD55C86CC"/>
    </appSettings>
</configuration>

核心逻辑:

using System;
using System.IO;
using System.Text;

namespace Locker {
    /// <summary>
    /// 一个简单的对文件加锁的工具
    /// </summary>
    public class FileLocker {
        /// <summary>
        /// 破坏数据时用到的异或码,固定写死127,避免太过复杂导致的悲剧
        /// </summary>
        public const byte XorCode = 127;
        /// <summary>
        /// 文件夹,固定写死,避免太过复杂导致的悲剧
        /// </summary>
        readonly string dirPath = Environment.CurrentDirectory + "\\XOR" + XorCode;
        /// <summary>
        /// 破坏数据的长度,设置为1M
        /// </summary>
        const int xorLenMax = 1024 * 1024;
        /// <summary>
        /// 加锁文件的后缀
        /// </summary>
        readonly string prefix = ".XOR" + XorCode;
        /// <summary>
        /// 对指定文件夹下的文件进行加锁,其原理是通过异或字节破坏文件的内容和后缀,让其不可读
        /// </summary>
        public FileLocker() {
            //为了防止破坏操作系统文件等悲剧,特限制死了必须在根目录下的指定文件夹中
            if (!Directory.Exists(dirPath)) {
                throw new Exception("未检测到目录下的XOR" + XorCode + "文件夹!");
            }
        }
        /// <summary>
        /// 对指定文件夹下的所有文件进行处理,未锁则锁,已锁就解锁
        /// </summary>
        public void Process() {
            foreach (var fi in new DirectoryInfo(dirPath).GetFiles()) {
                if (fi.Extension != prefix) {
                    Lock(fi.Name, (int)fi.Length);
                } else {
                    UnLock(fi.Name);
                }
            }
        }
        /// <summary>
        /// 对文件进行加锁
        /// </summary>
        void Lock(string name, long fileLength) {
            int xorLen = xorLenMax;
            if (xorLen > fileLength) {
                xorLen = (int)fileLength;
            }
            UpdateData(name, xorLen);
            SaveInfo(name, xorLen);
            Rename(dirPath + "\\" + name, dirPath + "\\" + Guid.NewGuid().ToString("N").ToUpper() + prefix);
        }
        /// <summary>
        /// 对文件进行解锁
        /// </summary>
        void UnLock(string name) {
            (string realName, int xorLen) = GetInfo(name);
            UpdateData(name, xorLen);
            Rename(dirPath + "\\" + name, dirPath + "\\" + realName);
        }
        /// <summary>
        /// 重命名
        /// </summary>
        void Rename(string path, string pathNew) {
            Console.WriteLine("=================================");
            Console.WriteLine("原文件:" + path);
            Console.WriteLine("新文件:" + pathNew);
            Console.WriteLine("=================================");
            File.Move(path, pathNew);
        }
        /// <summary>
        /// 异或字节数组中的数据,可以破坏文件的可读性
        /// </summary>
        byte[] XorData(byte[] arr) {
            for (int i = 0; i < arr.Length; i++) {
                arr[i] = (byte)(arr[i] ^ XorCode);
            }
            return arr;
        }
        /// <summary>
        /// 调整文件中的部分数据
        /// </summary>
        void UpdateData(string name, int xorLen) {
            byte[] arr = null;
            Read(name, (br, fs) => { arr = br.ReadBytes(xorLen); }); //读取文件中指定长度的头数据
            XorData(arr); //对其进行异或
            Write(name, (bw, fs) => { bw.Write(arr); }); //在覆写这些数据,破坏可读性
        }
        /// <summary>
        /// 保存加锁文件相关信息到文件的最后
        /// </summary> 
        void SaveInfo(string realName, int xorLen) {
            Write(realName, (bw, fs) => {
                fs.Seek(fs.Length, SeekOrigin.Begin); //在文件的最后保存文件的原有信息
                bw.Write(xorLen); //记录异或数据的长度
                byte[] bs = Encoding.UTF8.GetBytes(realName);
                XorData(bs); //文件名也要异或下,破坏可读性
                bw.Write(bs);
                bw.Write(bs.Length); //记录文件名的长度
            });
        }
        /// <summary>
        /// 读取加锁文件相关信息
        /// </summary>
        (string realName, int xorLen) GetInfo(string name) {
            string realName = string.Empty;
            int xorLen = 0;
            Read(name, (br, fs) => {
                var len = fs.Length;
                fs.Seek(len - 4, SeekOrigin.Begin); //最后4个字节记录文件名字节的长度
                int realNameLen = br.ReadInt32(); //读取文件名字节长度
                fs.Seek(len - 4 - realNameLen, SeekOrigin.Begin);
                realName = Encoding.UTF8.GetString(XorData(br.ReadBytes(realNameLen))); //读取文件名
                fs.Seek(len - 4 - realNameLen - 4, SeekOrigin.Begin);
                xorLen = br.ReadInt32(); //读取异或长度
                fs.SetLength(len - 4 - realNameLen - 4);
            });
            return (realName, xorLen);
        }
        /// <summary>
        /// 读文件
        /// </summary>
        void Read(string name, Action<BinaryReader, FileStream> action) {
            using (FileStream fs = new FileStream(dirPath + "\\" + name, FileMode.Open)) {
                using (BinaryReader br = new BinaryReader(fs)) {
                    action(br, fs);
                }
            }
        }
        /// <summary>
        /// 写文件
        /// </summary>
        void Write(string name, Action<BinaryWriter, FileStream> action) {
            using (FileStream fs = new FileStream(dirPath + "\\" + name, FileMode.Open)) {
                using (BinaryWriter bw = new BinaryWriter(fs)) {
                    action(bw, fs);
                }
            }
        }
    }
}
posted @ 2023-02-06 12:21  WmW  阅读(249)  评论(0编辑  收藏  举报