什么是异或加密
异或加密是一种加密算法,利用了计算机中的异或计算,异或计算(符号记为 ‘^’)的原理是,相同为 0,不同为 1
0 ^ 0 = 0
1 ^ 1 = 0
1 ^ 0 = 1
0 ^ 1 = 1
由于 1 ^ 0 或 0 ^ 1 的结果都为 1,因此,不能直接由结果 1 推出原来的明文到底是 0 还是 1,达到保护明文的目的。
异或加密特性
简单异或密码(英语:simple XOR cipher)是密码学中一种简单的加密算法,它按照如下原则进行运算:
- A ^ 0 = A
- A ^ A = 0
- (A ^ B) ^ C = A ^ (B ^ C)
- (B ^ A) ^ A = B ^ 0 = B // 明文 B;密码 A
从原理 4 可得,对同一个明文 B,使用密钥 A 对其进行两次异或运算,可得到明文 B,我们正是利用了这一特性,进行实现加密解密
异或加密算法
异或加密算法由 3 部分组成,分别是
明文
密钥
异或运算规则
流程是通过遍历明文的每一个字符,并按照异或运算规则从密钥中取出一个或多个字符,与明文的字符进行异或运算,将异或的结果合成一个新的字符串,
但是由于异或运算的特性,有可能异或运算后为一个不可见字符,就可能无法通过字符串传递密文了,因此这里引入了 base64 编码,因为 base64 编码后的字符串都是可见字符,
base64编码
Base64是一种基于64个可打印字符来表示二进制数据的表示方法。在Base64中的可打印字符包括字母A-Z
、a-z
、数字0-9
,这样共有62个字符,加上**+和/**, 共64个字符.
- 普通的文本数据也可以使用base64进行编解码
- Base64编解码的过程是可逆的
- Base64不能当做加密算法来使用
base64编码是把3个8bit(38=24bit)编码成4个6bit(46=24bit),并在每个6bit高位添加两个0构成一个8bit,然后换算成10进制,反查编码表即可得到对应的编码。由于2^6=64,即6bit的最大值是63,所以只需要64(0~63)个ASCII字符即可表示所有编码,因此得名base64编码。
下面来举例说明:
有一个字符串”abcd”
a b c d
ASCII: 0x61 0x62 0x63 0x64
8bit: 01100001 01100010 01100011 0110 0100
6bit: 011000 010110 001001 100011 011001 000000 = =
十进制: 24 22 9 35 25 0
查码表得: Y W J j Z A = =
最终结果:YWJjZA==
你可能注意到了,是每3个8bit进行一次编码,如果编码到最后不够3字节怎么办?base64编码规定,对于不够3个8bit的,编码完成后少几个6bit添几个”=”,这会有两种情况:
1.剩1个8bit(假设为xxxxxxxx):
编码完成后得到:
xxxxxx xx0000 = =
此时还缺2个6bit,因此在末尾添加“==”
2.剩2个8bit(假设为xxxxxxxx yyyyyyyy):
2.剩2个8bit(假设为xxxxxxxx yyyyyyyy):
编码后得到:
xxxxxx xxyyyy yy0000 =
此时还缺1个6bit,因此在末尾添加“=”
这也是为什么base64编码完成后面会有1到2个”=”。
base64应用场景
- 它可用来作为[电子邮件](https://zh.wikipedia.org/wiki/%E7%94%B5%E5%AD%90%E9%82%AE%E4%BB%B6)的传输[编码](https://zh.wikipedia.org/wiki/%E5%AD%97%E7%AC%A6%E7%BC%96%E7%A0%81)。
- 附件
- 图片 -> 二进制
- 音频/视频 -> 二进制格式的文件
- 邮件传输协议只支持 ASCII字符传递,因此如果要传输二进制文件:图片、视频是无法实现的。
- Http协议
- HTTP协议要求请求行和请求头都必须是ASCII编码()
- 数据库数据读写 - blob
- blob格式
- 文件
- 音频
- 视频
- 图片
- blob格式的数据中有一些特殊的数据:
- 中文(一个汉字在window中占两个字节,在linux中占三个字节)
- 写之前进行编码
- 读出来之后解码
- 二进制数据
/*
数据通过base64编码, 编码之后的数据边长了还是变短了?
- 变长了
- 每三个字节一组, 编码之后每组增加一个字节
编码之后的数据末尾有可能有=, 这个=是什么意思?
- =代表0, 0是给最后一组补位用的, 最后一组缺几个字节就补几个0
- 在解码的时候根据=的个数去掉对应的字节数
*/
加解密
所以加密算法变成:
明文与密钥按照异或运算规则进行异或运算,产生密文
将得到的密文进行base64 编码,最后返回
而解密算法相应的变成:
将密文进行 base64 解码,得到原始的密文
将密文按照相同的异或运算规则与密文进行异或,得到明文
异或运算算法
异或运算算法是为了解决明文与密文如何进行异或运算的问题,因为明文和密文长度可能不一样,如何保证明文的每个字符都有与之对应的密文字符进行异或,并且在解密时保证按照相同的算法进行异或运算得到明文,是异或运算算法要考虑的,这里我们会用到一种新的运算,叫 取余,这里不考虑为负数的情况
取余运算(通常记为 %),表示的是 被除数 除以 除数之后的余数,比如 8 / 5 = 1 余 3,因此 8 % 5 = 3,另外取余运算规定如果被除数小于除数,那么取余结果就为被除数,因此 5 % 8 = 5,来看下面的例子:
0%3=0
1%3=1
2%3=2
3%3=0
4%3=1
5%3=2
6%3=0
7%3=1
你们发现了吗,结果总是 0,1,2 的循环,我们就可以通过让明文每个字符的索引对密文的总长度取余,得到的结果作为密文的索引下标,取出对应的密文字符,与明文字符进行异或运算就可以啦
看下面这个例子吧
代码实现
#include <iostream>
#include <vector>
#include <string>
#include <stdexcept>
#include <bitset>
#include <cstring>
#include <openssl/bio.h>//使用 OpenSSL 库中的 BIO 函数来处理 Base64 编码和解码。你需要在编译时链接 OpenSSL 库(-lssl -lcrypto)。
#include <openssl/evp.h>
#include <openssl/buffer.h>//BUF_MEM 结构体是一个不完整类型(即前向声明),在使用之前需要包含相应的头文件。
// Base64 编码和解码的函数
std::string Base64Encode(const std::string& input) {
BIO *bio, *b64;
BUF_MEM *bptr;
std::string output;
b64 = BIO_new(BIO_f_base64());
bio = BIO_new(BIO_s_mem());
bio = BIO_push(b64, bio);
BIO_write(bio, input.data(), input.size());
BIO_flush(bio);
BIO_get_mem_ptr(bio, &bptr);
output.assign(bptr->data, bptr->length - 1);
BIO_free_all(bio);
return output;
}
//BIO_read 函数在读取解码后的数据时可能没有正确处理输入的长度,或者输出的字符串长度没有正确计算。
std::string Base64Decode(const std::string &input) {
BIO *bio, *b64;
char *buffer = (char*)malloc(input.length());
memset(buffer, 0, input.length());
b64 = BIO_new(BIO_f_base64());
bio = BIO_new_mem_buf(input.c_str(), input.length());
BIO_push(b64, bio);
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
int decoded_size = BIO_read(b64, buffer, input.length());
BIO_free_all(b64);
std::string output(buffer, decoded_size);
free(buffer);
return output;
}
// XOR 加密和解密函数:XORCipher 函数执行 XOR 操作来加密或解密数据。
std::string XORCipher(const std::string& text, const std::string& key) {
std::string result(text.size(), '\0');
size_t keyLength = key.size();
for (size_t i = 0; i < text.size(); ++i) {
result[i] = text[i] ^ key[i % keyLength];
}
return result;
}
//Encode 函数先进行 XOR 加密,然后进行 Base64 编码。
std::string Encode(const std::string& plainText, const std::string& key) {
std::string encryptedText = XORCipher(plainText, key);
return Base64Encode(encryptedText);
}
//Decode 函数先进行 Base64 解码,然后进行 XOR 解密。
std::string Decode(const std::string& cipherText, const std::string& key) {
std::string decodedBase64 = Base64Decode(cipherText);
return XORCipher(decodedBase64, key);
}
int main() {
std::string key = "3567d8cndkei%*x9(-32[]KDF(32222";
std::string plainText = "Hello World!";
std::string encodedText = Encode(plainText, key);
std::cout << "Encoded: " << encodedText << std::endl;
std::string decodedText = Decode(encodedText, key);
std::cout << "Decoded: " << decodedText << std::endl;
return 0;
}