admin管理员组

文章数量:1639831

严格意义上的加密算法有对称加密算法和非对称加密算法,对称加密算法是指加密与解密的key相同,而非对称加密算法是指加密(使用公钥,所有人都可以获取)与解密(使用私钥,只有指定方有私钥)的key不相同。这种严格的加密算法依赖于矩阵乘法进行数据加密,运算量较大,通常适用于短信息的加密,而针对于长信息(较大的文件)则不适用(具体可以参考压缩文件的加密)。

1、现有通行的加密方法

加密的本质就是对信息进行混淆,使拿到数据的人无法有效的识别出原始信息;而解密则是将混淆后的信息进行还原。因此,可以基于对信息的混淆进行数据加密。进行本工作前,博主进行粗略调查,c++实现文件加密的有以下方法:
1、基于异或操作的加密;https://blog.csdn/zhaxun/article/details/125027503
2、基于取反操作的加密;https://blog.csdn/weixin_50964512/article/details/123977481
3、基于ascall码表的加密;https://blog.csdn/weixin_46897073/article/details/110410141
这些加密方法的第一操作原理在于将文件以二进制的方式读取为char数组(每个char对应一个ascall值),相关c++代码如下

vector<char> read_file(string fname) {
    //读取文件
    ifstream inFile(fname, ios::in | ios::binary | ios::ate);
    long size = inFile.tellg();
    inFile.seekg(0, ios::beg);
    vector<char> buffers(size);
    inFile.read(buffers.data(), size);
    inFile.close();
    return buffers;
}
以上三个方法所存在的问题
  • 基于异或操作的加密 其加密与解密过程是一样的;进行异或操作的code只有8位,256个值;如果加密方式泄露,很容易通过碰撞检测进行解密;
  • 基于取反操作的加密 其加密与解密过程是一样的;不存在加密的code,针对整个文件进行取反很容易被识别出来
  • 基于ascall码表的加密 加密时的密码表必须为256,且不能重复(这对于使用上比较困难);通过很容易通过频率统计分析出密码表

2、所设计的加密方法

通过对现行三个文件加密方法的思考,认为实现加密解密算法的本质就是定义一个数据混淆规则,这个规则应该有一个人为参与的code,而且这个code不能太短。在进行加密时,根据code进行相应的操作。

2.1 可用的混淆操作

考虑到基于密码表的加密限制了code的范围;使用异或操作的加密则使code的值变得更小。博主以对vector的操作为思考起点。

共得出以下基本的数据混淆操作:

  • 取反操作 将数据进行取反;解密操作也是取反操作;以单个char为操作单元
  • 倒序操作 将数组的顺序进行翻转;解密操作也是倒序操作;以char数组为操作单元
  • 滑动操作 将数组首位相连,进行一定的转动;解密操作也是滑动操作;以char数组为操作单元;(如,滑动值为20%,则将数组前20%的数据截取下来放到最后面)
    以上三个操作的实现代码如下
//取反操作
void reverse_value(vector<char>& data) {
    for (int i = 0; i < data.size();i++) {
        data[i] = 255 - data[i];
    }
}
//倒序操作
void reverse_sort(vector<char>& data) {
    reverse(data.begin(), data.end());
}
//滑动操作
//根据start对vector进行截断, 让datain=dataout2+dataout1既实现了滑动操作
void vector_cut(vector<char>& datain, long start, vector<char>& dataout1, vector<char>& dataout2) {
    dataout1.assign(datain.begin(), datain.begin() + start);
    dataout2.assign(datain.begin() + start, datain.end());
}
//重载vector的运算符
template <typename T>
vector<T>& operator +(vector<T>& v1, vector<T>& v2)
{
    v1.insert(v1.end(), v2.begin(), v2.end());
    return v1;
}

2.2 加密方法

考虑到加密方法需要用户参与,将code设为多个数字。加密时,代码根据code中的数字对数据进行切分(用于实现滑动操作)得到切片1和切片2,对切片1进行取反操作,对切片2进行倒序操作;解密时,代码根据code中的数字对数据进行切分(用于实现滑动操作)得到切片1和切片2,对切片1进行倒序操作,对切片2进行取反操作。

由于加密和解密的基本操作都是一样,且都依赖于滑动操作。故,所实现的加密和解密方法如下。其中,datain表示输入的数据,start表示滑动的位置,encode=true表示进行加密操作,false表示进行解密操作。这里考虑到每个数据的size可能不一样,使用固定的start可能会超出数据的长度,故以百分比描述滑动的位置。当srart>=100时为无效值

void move_vector(vector<char>& datain, int start, bool encode = true) {
    vector<char> data1, data2;
    if (start >= 100) {//大于等于100不进行任何操作
        return;
    }
    start = int(start * datain.size() / 100);
    if (!encode) {
        //解码时的位置要调整
        start = datain.size() - start;
    }
    vector_cut(datain, start, data1, data2);
    if (!encode) {
        //解码时的位置要调整
        reverse_sort(data1);
        reverse_value(data2);
    }
    else {
        reverse_sort(data2);
        reverse_value(data1);
    }
    datain = data2 + data1;//交换这一段的位置
}

2.3 多轮加密

这里的设定是基于code进行加密,多个code则对应了多次加密次数,这使得数据基本上不可能被还原(打乱顺序比较简单,从混乱的数据中恢复顺序比较困难)。

加密函数

code为加密规则,示例:“13 41 54 19 12 4 42 54”,可以为任意长度,以空格分开每一个值

void encry_data(vector<char>& data, string code) {
    vector<string> codes = split_char(code, ' ');
    for (int i = 0; i < codes.size(); i++) {
        int offset;
        convertFromString(offset, codes[i]);
        move_vector(data, offset);
    }
}
解密函数

与encry_data函数共用相同的code,只是倒序进行操作

void decry_data(vector<char>& data, string code) {
    vector<string> codes = split_char(code, ' ');
    for (int i = codes.size() - 1; i >= 0; i--) {
        int offset;
        convertFromString(offset, codes[i]);
        move_vector(data, offset, false);
    }
}

3、加密示例

3.1 加密文本

这里对二进制文件进行加密示意。二进制文件的原始内容如下

加密解密代码如下:

#include "EncryFile.hpp" 
using namespace std;
int main() {
    string fname = "C:/Users/xxx/Pictures/a.txt";
    string codes = "18 5 63 41 22";//文件的加密码
    string fencry= "C:/Users/xxx/Pictures/a_en.txt";
    string fdecry = "C:/Users/xxx/Pictures/a_de.txt";
    encry_file(fname, codes, fencry);
    decry_file(fencry, codes, fdecry);
    return 0;
}

加密后的内容如下,可以看到部分内容已经倒序,部分内容已经取反;而且出现了空行,数据的行数与原来无法对应。在不知道数据混淆规则(code)的情况下对数据进行还原是异常困难的。

3.2 加密图片

具体加密代码如下

#include "EncryFile.hpp"
using namespace std;
int main() {
    string fname = "C:/Users/xxx/Pictures/bj.bmp";
    string codes = "18 5 63 41 22";//文件的加密码
    string fencry= "C:/Users/xxx/Pictures/bj_encry.bmp";
    string fdecry = "C:/Users/xxx/Pictures/bj_decry.bmp";
    encry_file(fname, codes, fencry);
    decry_file(fencry, codes, fdecry);
    return 0;
}

最终加密解密效果如下所示,可以看到计算机已经无法有效识别bj_encry.bmp(对于特定格式的文件,进行混淆后是无法被原来的软件进行解析的的(因为出现了数据错位、数据值部分取反、数据局部顺序翻转))。这表明这种数据加密规则是可以应用到绝大部分文件中。

补充:在本博文中有4个非重要函数并未公开。各位可以下载我的(付费资源)使用完整代码,或者自行根据以下代码提示补齐函数。

本文标签: 数组文件加密Char