1. Base64加密算法
Base64准确来说并不像是一种加密算法,而更像是一种编码标准。
我们知道现在最为流行的编码标准就是ASCLL,它用八个二进制位(一个char的大小)表示了127个字符,任何二进制序列都可以用这127个字符表示出来。
而Base64则是用6个二进制位表示了64个字符,也就是说,任何的二进制序列也都可以用这64个字符表示出来,这也是其名称的来源。
我们加密的方法,就是将原来的信息以ACSLL的标准转化为二进制序列(如果不是6的倍数,就用0补齐),然后按照Base64的标准,将其转化为该标准下的字符。
例如:
ASCLL(含换行符):
hello world
hello world
hello worldBase64:
aGVsbG8gd29ybGQKaGVsbG8gd29ybGQKaGVsbG8gd29ybGQA
如此加密之后的信息具有不可读性,广泛运用通信领域。
但是,这样加密过后的信息并不安全,只要你有心,就可以对照Basd64对照表和ASCLL码表解密出原来的内容。
对于Base64算法,我们仅做这么多介绍,感兴趣的小伙伴可以自己去深入了解一下。
2. 加密解密函数函数
2.1 加密函数Into_Base64
函数原型如下方代码所示。
在使用时,要求用户传入目标文件和原文件的文件名,函数就可以将原文件的信息加密存储到目标文件中。
void Into_Base64(const char dest[], const char src[])//加密函数//目标文件,源文件
{
FILE* srcx = fopen(src, "r");
if(srcx == NULL)
{
perror("source:");
return;
}
FILE* destx = fopen(dest, "w");
if(destx == NULL)
{
perror("destination:");
return;
}
int flag = 1;
while(flag)
{
char secret[5] = {0};//存储加密后数据
int binary[25] = {0};//6和8的最小公倍数为24
char ch = 0;
for(int i = 0; i < 3; i++)
{
ch = getc(srcx);
if(ch == -1)
{
flag = 0;
goto interruption;
}
Into_Binary(binary + i * 8, ch, 0);
}
interruption:
for(int i = 0; i < 4; i++)
{
Into_Char(secret + i, binary + i * 6, 1);
}
fprintf(destx, "%s", secret);
}
fclose(srcx);
fclose(destx);
}
在while循环中,我们每次读取24个字节的数据,这是因为6(Base64中一个字符的二进制长度)和8(ASCLL中一个字符的二进制长度)的最小公倍数为24,便于实现两种编码之间的转换。
2.2 解密函数Out_Base64
函数原型如下方代码所示。
在使用时,要求用户传入目标文件和原文件的文件名,函数就可以将原文件的信息解密存储到目标文件中。
void Out_Base64(const char dest[], const char src[])//解密函数//目标文件,源文件
{
FILE* srcx = fopen(src, "r");
if(srcx == NULL)
{
perror("source:");
return;
}
FILE* destx = fopen(dest, "w");
if(destx == NULL)
{
perror("destination:");
return;
}
int flag = 1;
while(flag)
{
char secret[4] = {0};//存储解密后数据//
int binary[25] = {0};//6和8的最小公倍数为24
char ch = 0;
for(int i = 0; i < 4; i++)
{
ch = getc(srcx);
if(ch == -1)
{
flag = 0;
goto interruption;
}
Into_Binary(binary + i * 6, ch, 1);
}
interruption:
for(int i = 0; i < 3; i++)
{
Into_Char(secret + i, binary + i * 8, 0);
}
fprintf(destx, "%s", secret);
}
fclose(srcx);
fclose(destx);
}
该函数与加密函数基本相同,只是在调用Into_Binary函数和Into_Char函数时的传参时有所差别,并且每24个字节解密得到的字符的仅有三个,所以secret数组的容量也相应减少了。
2.3 字符转二进制序列函数Into_Binary
函数原型如下方代码所示。
在使用时,要求用户传入存储二进制序列的数组的起始地址,要转换的字符,以及flag。
其中,flag==1时,将字符按照Base64编码转换为二进制;flag==0时,将字符按照ASCLL编码转换为二进制。
在加密函数中,flag==0;在解密函数中flag==1。
//将src转换为二进制存到dest中
//flag==1将Base64编码转换为二进制,flag==0将ascll转换为二进制
void Into_Binary(int* dest, char src, int flag)
{
int n = 2;
int num = 0;
if(flag)
{
num = 5;//六位,最高位下标5
src = Base64_Int(src);
}
else
{
num = 7;//八位,最高位下标7
}
for(int i = num; i >= 0; i--)
{
*(dest + i) = src % n;
src /= 2;
}
}
由于计算机是以ASCLL编码标准识别字符的,所以我们直接将其当作整形处理即可。
但是计算机并不懂得Base64的编码标准是怎样的,所以我写了一个函数,将字符按照Base64标准转换为整形。
char Base64_Int(char tem)//字符转Base64编码
{
if(tem >= 'A'&&tem <= 'Z')
return tem - 'A';
else if(tem >= 'a'&&tem <= 'z')
return tem + 26 - 'a';
else if(tem >= '0'&&tem <= '9')
return tem + 52 - '0';
else if(tem == '+')
return 62;
else if(tem == '/')
return 63;
}
2.4 二进制序列转字符函数
函数原型如下方代码所示。
在使用时,要求用户传入存储要转换的二进制序列的数组的起始地址,存储转换后字符的地址,以及flag。
其中,flag==1时,将二进制序列按Base64编码转换为字符;flag==0时,将二进制序列按ASCLL编码转换为字符。
在加密函数中,flag==1;在解密函数中flag==0。
//将二进制数转换为char类型
//flag==1转换为Base64,flag==0转换为ascll
void Into_Char(char* dest, int* src, int flag)
{
int tem = 0;
int n = 1;
int num = 0;
if(flag)
num = 5;
else
num = 7;
for(int i = num; i >= 0; i--)
{
tem += *(src + i) * n;
n *= 2;
}
if(flag)
*dest = Base64_Char(tem);
else
*dest = tem;
}
与刚才同理,Base64_Char用于将整形按照Base64标准转换为字符。
char Base64_Char(int tem)//Base64编码转字符
{
if(tem >= 0&&tem <= 25)
return tem + 'A';
else if(tem >= 26&&tem <= 51)
return tem + 'a' - 26;
else if(tem >= 52&&tem <= 61)
return tem + '0' - 52;
else if(tem == 62)
return '+';
else if(tem == 63)
return '/';
}
3. 测试
写好之后,我们就可以写个main函数来进行一下测试啦!
int main()
{
Into_Base64("test2.txt", "test1.txt");//把test1.txt加密后存到test2.txt
Out_Base64("test3.txt", "test2.txt");//把test2.txt解密后存到test3.txt
return 0;
}
注意要先创建好“test1.txt”文件,以免打开文件时失败。
运行之后得到两个文件
也是包成功的啊。