一、文件加密与解密实战:简单的异或加密算法实现

说实话,加密这个话题,很多初学者一听就觉得高深莫测。其实没那么玄乎。

我最早接触文件加密,是在一个嵌入式项目里。当时需要把配置参数写到EEPROM里,但又不想让别人直接看到明文。嗯,那时候我就用了一个非常简单的办法——异或加密。

今天咱们就来聊聊这个。你想想看,加密的本质是什么?说白了,就是把原始数据(明文)通过某种规则,变成别人看不懂的东西(密文)。而解密,就是反过来操作,把密文恢复成明文。

异或加密,就是最简单、最基础的一种对称加密算法。

1.1 异或运算的基础

异或,在C语言里用 ^ 这个符号表示。它的运算规则很简单:

  • 两个位相同,结果为0
  • 两个位不同,结果为1

举个例子:

0 ^ 0 = 0
0 ^ 1 = 1
1 ^ 0 = 1
1 ^ 1 = 0

看起来是不是很简单?但异或有一个非常神奇的特性,我当年第一次发现时还觉得挺有意思的——可逆性

异或的核心特性:

如果 a ^ b = c,那么 c ^ b = a

也就是说,同一个数异或两次,就能回到原来的值。

这个特性,就是异或加密的数学基础。你拿一个密钥去异或明文,得到密文。再拿同一个密钥去异或密文,就能还原出明文。

1.2 异或加密的原理

咱们用一张图来理解这个过程:

异或加密/解密流程 明文数据 密钥 密文数据 加密:密文 = 明文 ^ 密钥 密文数据 密钥(相同) 还原明文 解密:明文 = 密文 ^ 密钥 同一个密钥,加密和解密用的是同一个操作

看到没?加密和解密用的是同一个操作。这就是对称加密的特点——加密和解密使用相同的密钥

1.3 代码实现

好了,理论说完了,咱们直接上代码。我习惯把功能拆得细一点,这样好维护。

#include <stdio.h>
#include <stdlib.h>

// 异或加密/解密函数
// 注意:加密和解密用的是同一个函数
void xor_encrypt_decrypt(const char *input_file, 
                         const char *output_file, 
                         unsigned char key) {
    FILE *fin = fopen(input_file, "rb");
    if (fin == NULL) {
        printf("无法打开输入文件:%s\n", input_file);
        return;
    }

    FILE *fout = fopen(output_file, "wb");
    if (fout == NULL) {
        printf("无法创建输出文件:%s\n", output_file);
        fclose(fin);
        return;
    }

    int ch;
    while ((ch = fgetc(fin)) != EOF) {
        // 对每个字节进行异或操作
        unsigned char encrypted = ch ^ key;
        fputc(encrypted, fout);
    }

    fclose(fin);
    fclose(fout);
    printf("操作完成!\n");
}

int main() {
    unsigned char key = 0xAB;  // 随便选一个密钥
    
    printf("=== 文件异或加密/解密演示 ===\n\n");
    
    // 加密
    printf("正在加密文件...\n");
    xor_encrypt_decrypt("plain.txt", "encrypted.bin", key);
    
    // 解密
    printf("正在解密文件...\n");
    xor_encrypt_decrypt("encrypted.bin", "decrypted.txt", key);
    
    return 0;
}

小提示:

我在项目中一般用 unsigned char 来存密钥,因为它的范围是0-255,正好一个字节。用 int 也行,但容易出一些隐式类型转换的问题。

1.4 代码详解

咱们一行一行来看:

  1. 文件打开模式:用的是 "rb""wb",也就是二进制模式。为什么要用二进制?因为文本模式在Windows下会做换行符转换,加密时可能会出问题。我踩过这个坑,后来就老老实实全用二进制模式了。
  2. 逐字节读取fgetc 一次读一个字节,读到 EOF 就结束。注意 fgetc 返回的是 int,不是 char。为什么?因为 EOF 是 -1,用 char 存不下。
  3. 异或操作ch ^ key,就这么简单。一个字节和密钥异或,得到密文。
  4. 写入文件fputc 把加密后的字节写出去。

你想想看,整个加密过程,核心代码其实就一行:unsigned char encrypted = ch ^ key;

1.5 运行效果

假设 plain.txt 里写的是 Hello, World!,密钥是 0xAB

阶段 文件内容(十六进制) 说明
明文 48 65 6C 6C 6F 2C 20 57 6F 72 6C 64 21 原始数据
密文 E3 CE C7 C7 C4 87 8B FC C4 D9 C7 CF 8A 已经看不懂了
解密后 48 65 6C 6C 6F 2C 20 57 6F 72 6C 64 21 和原来一模一样

注意:

这种加密方式虽然简单,但安全性很低。为什么呢?因为密钥只有一个字节,最多256种可能。用暴力破解的话,几秒钟就能试完。我曾经在一个玩具项目里用过,后来被同事笑话了。

所以,这个算法适合用来学习原理,或者加密一些不太重要的数据。真正要保护敏感信息,还是得用AES、RSA这些成熟的算法。

1.6 改进方向

如果你觉得单字节密钥太弱,可以试试多字节密钥:

void xor_encrypt_multi_key(const char *input_file,
                           const char *output_file,
                           const unsigned char *key,
                           int key_len) {
    FILE *fin = fopen(input_file, "rb");
    FILE *fout = fopen(output_file, "wb");
    
    int key_index = 0;
    int ch;
    
    while ((ch = fgetc(fin)) != EOF) {
        unsigned char encrypted = ch ^ key[key_index];
        fputc(encrypted, fout);
        
        // 循环使用密钥
        key_index = (key_index + 1) % key_len;
    }
    
    fclose(fin);
    fclose(fout);
}

这样密钥就不是一个字节了,而是一串字节。比如用 "MySecretKey123" 作为密钥,破解难度就大得多了。

核心要点回顾:

  • 异或加密利用的是异或运算的可逆性
  • 加密和解密使用同一个函数
  • 文件操作要用二进制模式("rb"/"wb")
  • 单字节密钥不安全,实际应用建议用多字节密钥

嗯,这一章的内容就到这儿。异或加密虽然简单,但它是理解更复杂加密算法的基础。你把这个搞明白了,后面学AES、RSA的时候,就会觉得亲切很多。

公众号:蓝海资料掘金营,微信deep3321