📄 encrypt_decrypt.c
字号:
#include "huffman.h"
/*------------------------------------------------------------------------*/
/*把原始数据文件DATAFILE进行加密得到加密数据文件ENCRYPT_DATAFILE。*/
/*加密算法密钥为"POWERZHU"。定义一个1000行8列的矩阵供加密算法用。*/
//沿行读入,沿列输出
void encrypt(FILE* fp1,FILE* fp2)
{
int i;
int j;
int k;
int flag;
int length; //文件字符总数
int line_sum;
int key_sequence[8];//存放密钥字母顺序
char ch;
char matrix[8][1000] = {'\0'}; //假设文件字符数不超过8000个
//求密钥字母顺序
SetKeySequence(key_sequence);
//求文件中字符个数总数
fseek(fp1,0,SEEK_END); //把文件指针fp1移到文件尾。
length = ftell(fp1); //文件字节个数
length /= sizeof(char); //文件字符个数
/*ftell()函数返回文件位置指示器的当前值, 这个值是指示器从文件头开始算起的字节数,
返回的数为长整型数, 当返回-1时, 表明出现错误。*/
//加密矩阵:
line_sum = length / 8 + (!(length % 8)) ? 0 : 1; //矩阵的有效行数,这里只是给出一种计算方法
//"按行读入"文件的所有字符到加密矩阵中
rewind(fp1);
i = 0;
j = 0;
while((ch = (int)(fgetc(fp1))) != EOF){ //从文件中读一个字符
if(i < 8)
matrix[j][i++] = ch;
else{
i = 0;
matrix[++j][i] = ch;
}
}
line_sum = j + 1; //矩阵的有效行数
//按照密钥字母的在字母表中的顺序"沿列读出",构成密钥文本
//密钥顺序powerzhu——ehopruwz(47215836)
rewind(fp2);
j = 8; //密钥字母个数
k = 0;
while(--j >= 0){ //读8次,因为密钥字母为8个
flag = key_sequence[k++ - 1];
for(i = 0;i < line_sum;++i){
ch= matrix[i][flag];
fputc((int)ch,fp2); //把加密文本逐字符写入文件指针fp2所指的文件中保存
}
}
}
/*-----------------------------------------------------------------------------*/
/*把加密文件ENCRYPT_DATAFILE进行解密得到数据文件DECRYPT_DATAFILE*/
//按列读入,沿行输出
void decrypt(FILE* fp1,FILE* fp2)
{
int i;
int j;
int k;
int flag;
int line_sum;
int length; //文件字符总数
int key_sequence[8];//存放密钥字母顺序
char ch;
char matrix[8][1000] = {'\0'}; //假设文件字符数不超过8000个
//求密钥字母顺序
SetKeySequence(key_sequence);
//求文件中字符个数总数
fseek(fp1,0,SEEK_END); //把文件指针fp1移到文件尾。
length = ftell(fp1); //文件字节个数
length /= sizeof(char); //文件字符个数
//加密矩阵:
line_sum = length / 8 + (!(length % 8)) ? 0 : 1; //矩阵的有效行数
//按照密钥字母的在字母表中的顺序按列读入文件的所有字符到解密矩阵中
//密钥顺序powerzhu——ehopruwz(47215836)
rewind(fp1);
j = 8;
k = 0;
while(-- j >= 0){//读8次,因为密钥字母为8个
i = 0;
flag = key_sequence[k++ - 1];
while((ch = (int)(fgetc(fp1))) != EOF){ //从文件中读一个字符
if(i < line_sum)
matrix[i++][flag] = ch;
if(i >= line_sum) //到第line_sum行后就退出换矩阵的另一列写。在这里用if和else if是不同的,体会一下!
break;
}
}
//沿行读出,构成解密文本
rewind(fp2);
for(i = 0;i < line_sum;++i)
for(j = 0;j < 8;++j){
ch= matrix[i][j];
fputc((int)ch,fp2); //把加密文本沿行逐字符写入文件指针fp2所指的文件中保存
}
}
/*---------------------------------------------------------------------------*/
//求密钥POWERZHU的字母表顺序
//密钥顺序powerzhu——ehopruwz(47215836)
//密钥的特点是:各个字母都不相同才能作为此加密算法的密钥。
//key_sequence是数组名,所以定义成常量指针
void SetKeySequence(int* const key_sequence)
{
int i;
int j;
int length; //密钥长度
char string[10];
NodePtr head; //头结点
NodePtr current; //当前工作结点
NodePtr current_before; //current的上一个结点指针
NodePtr new_node; //新结点
strcpy(string,"POWERZHU"); //密钥
length = strlen(string); //密钥长度
//把密钥按字母表顺序排序:采用插入排序法 //采用链表进行排序:从小到大
if((head = (NodePtr)malloc(sizeof(LinkListNode))) == NULL){
printf("Allocate memory ERROR !\n");
exit(1);
}
head->data = length; //建立一个空链表;在链表首增加一个头结点head,其数据域存放密钥长度
head->next = NULL; //头结点指针域存放链表的开始结点,最初为一个空链表。
i = 0;
while(--length >= 0){ //新分配length个结点空间
if((new_node = (NodePtr)malloc(sizeof(LinkListNode))) == NULL){
printf("Allocate memory ERROR !\n");
exit(1);
}
new_node->data = string[i]; //新分配结点的数据域
current = head->next; //指向链表的开始结点(即链表第一个数据结点)
current_before = head; //指向头结点head
/*---------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------*/
/*插入位置为从链表首开始遍历结点时找到链表中第一个大于新插入结点数据值的链表结点,并把此新结点
插入到这个找到的满足要求(即满足:string[i] < current->data)的链表结点之前。
*/
while(current != NULL){ //当前工作指针current指向当前数据结点
if(string[i] < current->data){ //插入到结点current之前
current_before->next = new_node;
new_node->next = current;
}
else{
current_before = current;
current = current->next;//指向下一个结点
}
}
if(current == NULL){ //链表已经遍历完,插入新结点到链表尾//在链表首插入第一个结点就属于此情况
current_before->next = new_node;
new_node->next = NULL;
}
/*---------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------*/
/*注:上述在两条虚线之间的代码段可以用如下代码段代替,此代码把在所有结点位置插入都统一起来,即只需
考虑一种情况。
代码如下:
while (current != NULL && string[i] >= current->data){ //一直到找到满足条件的结点才退出循环。
current_before = current;
current = current->next; //指向下一个结点
}
current_before->next = new_node; //插入新结点
new_node->next = current; // 等价于new_node->next = NULL;因为此时current为NULL。
*/
++i;
}
//遍历顺序链表各数据结点,把密钥字母顺序存入数组key_sequence中。
current = head->next; //指向链表开始结点
j = 0;
for(i = 0;i < length;++i){
while(current->data != (int)(string[j])) //把char型强制转换为int型
++j;
key_sequence[i] = j + 1;//存放密钥的第(j+1)个字母
j = 0;
current = current->next;//指向下一个结点
}
//释放整个链表空间
free_linklist(head);
}
/*通过增加一个头结点,把在链表首,链表中间及链表尾插入结点统一起来。
插入算法:排序按从小到大;从链表首开始分别与各结点数据比较,若比当前结点数据小,则插入在当前结点
之前;否则再与下一个结点数据比较;若比下一个结点数据小,则插入到此结点之前。
可以定义一个双向链表来实现插入操作,;本程序通过一个"哨点"指针标记上一个结点位置达到同样效果。
*/
/*----------------------------------------------------------------------------------------------*/
void free_linklist(NodePtr head) /*释放整个链表的结点空间*/
{
NodePtr ptr;
while(head != NULL){ /*包括头结点也要释放掉,因为它占同样大小内存空间*/
ptr = head;
head = head->next;
free(ptr);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -