admin管理员组文章数量:1639675
题目:
文件的传输会有明文和密文的区别,明文发送是不安全的。本题目实现对文件的加密和解密操作,采用的加密算法是根据密钥将明文中的字母置换为其它字母,所有字母不区分大小写,不考虑除英文字母外的字符。例如:明文是:They will arrive tomorrow,密钥k=Monday,具体加密过程如下:
① 设置英文字母与0到25有如下的对应关系:
②依据上述对应关系将明文和密钥转化为一组数字:
k=(12,14,13,3,0,24)
m=(19,7,4,24,22,8,11,11,0,17,17,8,21,4,19,14,12,14,17,17,14,22)
③将明文数字依据密钥长度分段,并逐一与密钥数字相加(模26),得到密文数字,即:
C=(5,21,17,1,22,6,23,25,13,20,17,6,7,18,6,17,12,12,3,5,1,25)
④依据字母和数字对应关系将密文数字转换为字母串,即密文为:
c=FVRBWGXZNURGHSGRMMDFBZ
解密过程与加密过程类似,采用的是减运算模26。
功能要求:
主函数提供功能菜单供用户选择,用户可以选择调用以下各个功能,也可以选择退出程序。系统应提供以下功能:
(1) 加密:对给定文件file1.txt内容按照密钥k=Monday进行加密,加密后密文写到文件file2.txt中;
(2) 解密:对给定密文文件file3.txt 利用密钥k=Monday进行解密,解密后的明文存放在文件file4.txt中;
(3) 破解密钥的长度:对给定密文文件file5.txt,搜索长度>=3且出现次数>=3的相同密文段keyi,将这些相同密文段及其出现的次数写入文件file6.txt。
例如密文若为:hksabcdiukoabcdhkslslabcdpphkslll,则相同密文段及其出现的次数为:hks *3 abc *3 abcd *3 bcd *3 。
实现代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
/*宏定义秘钥和模,数组容量, 结构体数组大小*/
#define Key "Monday"
#define Mod 26
#define MAXSIZE 1000
#define SubStrMaxSize 1000000
/*定义子串结构体*/
struct subString {
char str[MAXSIZE]; /*子串名称*/
int sum; /*子串出现次数*/
} subStr[SubStrMaxSize]; /*定义结构体数组个数*/
/*定义全局变量*/
char alphabetUpper[26] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z'}; /*单词对照表大写*/
char alphabetLower[26] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
'y', 'z'};/*单词对照表小写*/
/*文件读取*/
void readFile(FILE *fp, char *buff) {
int i = 0;
char c;
while (1) {
c = fgetc(fp);
// 去空格, EOF 结束
if (c != EOF && c != ' ') {
buff[i++] = c;
} else if (c == EOF){
break;
}
}
fclose(fp);
}
/*文件写入*/
void writeFile(FILE *fp, char *buff) {
int i = 0;
char c;
while ((c = buff[i])!= '0') {
fputc(c, fp);
i++;
}
fclose(fp);
}
/*获取整型数组长度*/
/*因为数组作为参数传参时,无法再使用 sizeof 计算长度了,所以抽取出一个公共函数*/
int getIntLength(int intArr[]) {
int *p;
int len = 0;
p = intArr;
while (p != NULL && *p != -1) {
len++;
p++;
}
return len;
}
/*获取字符数组有效长度, '0' 为无效值*/
int getCharLength(char charArr[]) {
char *p;
int len = 0;
p = charArr;
/*必须要再加一个限定条件 *p != '\0', 否则计算字符串长度会出现 bug, 长度几百 */
while (p != NULL && *p != '0' && *p != '\0') {
len++;
p++;
}
return len;
}
/*字母转数字*/
void alpToNum (char *buff, int *num) {
int index = 0;
for (int i = 0; i < getCharLength(buff); ++i) {
for (int j = 0; j < strlen(alphabetLower); ++j) {
if (buff[i] == alphabetUpper[j] || buff[i] == alphabetLower[j]) {
num[index++] = j;
break;
}
}
}
}
/*数字转字母*/
void numToAlp(int *num, char *buff) {
int index = 0;
for (int i = 0; i < getIntLength(num); ++i) {
buff[index++] = alphabetUpper[num[i]];
}
}
/*加密过程*/
void encryption(int *clearNum, int *keyNum, char *encryptText) {
int index = 0;
/*待加密数组和秘钥数组的长度*/
int clearNumLen = getIntLength(clearNum);
int keyNumLen = getIntLength(keyNum);
/*存放加密后的整形数组*/
int EncryptNum[MAXSIZE];
memset(EncryptNum, -1, sizeof(int)*1000);
/*存储 i 到数组结尾的距离*/
int dist;
/*逐一与密钥数字相加(模26)操作*/
for (int i = 0; i < clearNumLen; i+= keyNumLen) {
dist = clearNumLen - i;
/*当dist大于秘钥长度则一一对应相加模26加运算处理,当 dist 小于 秘钥长度则遍历前 dist 个的秘钥一直相加模运算*/
if (dist > keyNumLen) {
for (int j = 0; j < keyNumLen; ++j) {
// 加密
EncryptNum[index++] = (clearNum[j + i] + keyNum[j]) % Mod;
}
} else {
for (int j = 0; j < dist; ++j) {
// 加密
EncryptNum[index++] = (clearNum[j + i] + keyNum[j]) % Mod;
}
}
}
/*整形数组转换成字符数组*/
numToAlp(EncryptNum, encryptText);
}
/*解密过程*/
void decryption(char *encryptedText, int *keyNum, char *decryptText) {
int index = 0;
/*已加密数组和秘钥数组的长度*/
int encryptedTextLen = getCharLength(encryptedText);
int keyNumLen = getIntLength(keyNum);
/*存放已加密字符数组转化后的数字*/
int encryptedNum[MAXSIZE];
memset(encryptedNum, -1, sizeof(int) * 1000);
/*字母转数字*/
alpToNum(encryptedText, encryptedNum);
/*存放明文数字数组*/
int clearNum[MAXSIZE];
memset(clearNum, -1, sizeof(int) * MAXSIZE);
/*存储 i 到数组结尾的距离*/
int dist;
/*存储秘钥和密文各个数字的差值*/
int diffVal;
/*存放 x - y[x/y] 的值*/
int resVal;
/*逐一减运算再模运算*/
/*取余和模运算有区别:可能你会觉得数学中的 余数(remainder) 其实就是 取模(mod)
x%y = x - y[x/y]
虽然数学中的余数概念和我们的计算机中的余数概念一致,但实现却不一致,对于正数,二者计算出的
结果是相等的,但是负数就不相等了。*/
for (int i = 0; i < encryptedTextLen; i+= keyNumLen) {
/*解密*/
dist = encryptedTextLen - i;
if (dist > keyNumLen) {
for (int j = 0; j < keyNumLen; ++j) {
diffVal = encryptedNum[j + i] - keyNum[j];
resVal = ceil(fabs(((double)diffVal / (double)Mod)));
/*被除数小于 0, [x/y] 向下取整 */
if (diffVal < 0) {
/*取绝对值再向上取整(计算机默认向下取整,导致差异,我们需要向上取整), 再转回负数*/
clearNum[index++] = diffVal + (Mod * resVal);
} else {
/*res > 0 正常处理即可*/
clearNum[index++] = (encryptedNum[j + i] - keyNum[j]) % Mod;
}
}
} else {
/*解密*/
for (int j = 0; j < dist; ++j) {
diffVal = encryptedNum[j + i] - keyNum[j];
resVal = ceil(fabs(((double)diffVal / (double)Mod)));
/*被除数小于 0, [x/y] 向下取整 */
if (diffVal < 0) {
/*取绝对值再向上取整(计算机默认向下取整,导致差异,我们需要向上取整),再转回负数*/
clearNum[index++] = diffVal + (Mod * resVal);
} else {
/*res > 0 正常处理即可*/
clearNum[index++] = (encryptedNum[j + i] - keyNum[j]) % Mod;
}
}
}
}
/*整形数组转换成字符数组*/
numToAlp(clearNum, decryptText);
}
/*破解秘钥长度*/
void crackSecretLen(char *secretKeyText, char *cipherSection) {
int index; /*结构体数组下标*/
int i; /*该行字符串的最大长度*/
int j; /*这个子串的最大长度*/
int k; /*遍历的初始下标*/
int z = 0; /*k的偏移量*/
char TempSection[MAXSIZE]; /*定义临时存放每个长度>=3且出现次数>=3的相同密文段*/
/*获取一个函数的所有子串存入结构体数组, 排除空串*/
for (i = getCharLength(secretKeyText); i >= 1; i--) {
for (j = 1; j <= i ; ++j) {
/*定义一个临时数组存放字符*/
char tempChar[j+1];
for (k = 0; k < j; ++k) {
/*字符存入,生成子串字符数组*/
tempChar[k] = secretKeyText[k + z];
}
/*踩坑!!: strcpy 必须复制必须是字符串,所以必须 tempChar 最后添加 \0, 否则乱码*/
tempChar[j] = '\0';
/*设立一个标志位, 为 0 说明不存在相同的,为 1 说明存在相同的*/
int flag = 0;
/*判断是否子串已存在,存在则原基础 sum + 1, 否则添加子串*/
for (int l = 0; l < index+1; ++l) {
/*字符比较,相等则存在,原基础 sum + 1*/
if (strcmp(tempChar, subStr[l].str) == 0) {
subStr[l].sum++;
/*标志位改变,不存入*/
flag = 1;
break;
}
}
/*不存在相同的字符串,则数据存入结构体*/
if (!flag) {
/*存入*/
strcpy(subStr[index].str, tempChar);
/*个数设为1*/
subStr[index].sum = 1;
/*自增*/
index++;
/*复位 0*/
flag = 0;
}
}
z++;
}
/*搜索出长度>=3且出现次数>=3的相同密文段*/
for (int m = 0; m < index; ++m) {
if (getCharLength(subStr[m].str) >= 3 && subStr[m].sum >= 3) {
sprintf(TempSection,"%s * %d ", subStr[m].str, subStr[m].sum);
strcat(cipherSection, TempSection);
}
}
}
int main() {
/*选择操作*/
int choice;
/*
* 秘钥转数字操作
* */
/*存放Key转换后的数字*/
int keyNum[MAXSIZE];
memset(keyNum, -1, sizeof(int) * MAXSIZE);
alpToNum(Key, keyNum);
while(1) {
printf("1--加密1\n");
printf("2--解密2\n");
printf("3--破解秘钥长度3\n");
printf("0--退出\n");
printf("your choice(0/1/2/3):");
scanf("%d", &choice);
switch (choice) {
case 1: {
/*
* 明文转数字操作
* */
FILE *file1 = fopen("D:\\OrderProject\\Encryption\\file1.txt", "r");
/*存放明文file1.txt里面读取出的字符串*/
char clearText[MAXSIZE];
/*初始化为 '0'*/
memset(clearText, '0', sizeof(char) * MAXSIZE);
/*存放 clearText[] 转换后的数字*/
int clearNum[MAXSIZE];
/*设默认值为 -1, 不在区间 [0,25] 即可, 显然取 -1 最佳*/
/*直接 clearNum[1000] = {-1} 是无法赋初值的,而需使用 memset*/
memset(clearNum, -1, sizeof(int) * MAXSIZE);
readFile(file1, clearText);
alpToNum(clearText, clearNum);
/*
* 加密操作
* */
/*存放加密后的字符串*/
char encryptText[MAXSIZE];
memset(encryptText, '0', sizeof(char) * MAXSIZE);
encryption(clearNum, keyNum, encryptText);
/*
* 加密数据写入文件中
* */
FILE *file2 = fopen("D:\\OrderProject\\Encryption\\file2.txt", "w");
writeFile(file2, encryptText);
};
break;
case 2: {
/*
* 解密操作
* */
FILE *file3 = fopen("D:\\OrderProject\\Encryption\\file3.txt", "r");
/*存放已加密file3.txt里面读取出的字符串*/
char encryptedText[MAXSIZE];
memset(encryptedText, '0', sizeof(char) * MAXSIZE);
/*存放 encryptedText[] 转换后的数字*/
int encryptedNum[MAXSIZE];
memset(encryptedNum, -1, sizeof(int) * MAXSIZE);
readFile(file3, encryptedText);
alpToNum(encryptedText, encryptedNum);
/*
* 解密操作
* */
char decryptText[MAXSIZE];
memset(decryptText, '0', sizeof(char) * MAXSIZE);
decryption(encryptedText, keyNum, decryptText);
/*
* 解密数据写入文件中
* */
FILE *file4 = fopen("D:\\OrderProject\\Encryption\\file4.txt", "w");
writeFile(file4, decryptText);
};
break;
case 3: {
/*
* 破解密钥长度操作
*/
FILE *file5 = fopen("D:\\OrderProject\\Encryption\\file5.txt", "r");
/*存放file5里面读取出的密钥字符串*/
char secretKeyText[MAXSIZE];
/*初始化 '0'*/
memset(secretKeyText, '0', sizeof(char) * MAXSIZE);
/*定义存放长度>=3且出现次数>=3的相同密文段的字符数组*/
char cipherSection[MAXSIZE];
/*读取file5文件数据*/
readFile(file5, secretKeyText);
crackSecretLen(secretKeyText, cipherSection);
/*
* 秘钥字段写入文件中
* */
FILE *file6 = fopen("D:\\OrderProject\\Encryption\\file6.txt", "w");
fputs(cipherSection, file6);
}
break;
default:
exit(0);
}
}
}
版权声明:本文标题:密码学: Vigenere 密码法实现文件加密与解密 (C 语言) 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.elefans.com/dongtai/1729293927a1194495.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论