c语言编译密码学仿射变换,GitHub - ihnfsa-github/polyalphabetic-substitution-cipher: Polyalphabetic Substitution ...

该博客介绍了使用C语言实现基于仿射变换的多表代换密码加密和解密的过程。文章详细阐述了如何生成满足特定要求的矩阵A和数组B,以及如何对纯字母文本进行加密和解密。通过给出的源代码,读者可以编译运行程序,生成随机文本并进行加密解密实验。博客还特别提到了在加密过程中对不足一组的明文使用字母A填充,以及使用伴随矩阵法求逆矩阵来提高效率。
摘要由CSDN通过智能技术生成

polyalphabetic-substitution-cipher

Polyalphabetic Substitution Cipher:基于仿射变换的多表代换密码的C语言实现

多表代换编程实现

原理

ecb78207782fb414fe952d70f14e3560.png

编程语言

C

编程环境

Ubuntu 18.04

编译器

gcc

源代码文件说明

polyalphabetic_substitution.tar : 源代码、程序、资源文件的集合,解压后得到以下源代码文件

det.c : 提供求解行列式的功能以及一些附加实用功能

det.h : 头文件

generatekeyA.c : 生成指定阶数且满足要求的矩阵A

generatekeyB.c : 生成指定长度的数组B

gettext.c : 提供随机生成指定长度的纯字母文本的实用功能

encrypt.c : 加密文本

inverseA.c : 生成矩阵A的逆矩阵A_1

decrypt.c : 解密文本

准备工作

使用以下指令编译源代码 :

gcc generatekeyA.c det.c -o generatekeyA

gcc generatekeyBc det.c -o generatekeyB

gcc gettext.c det.c -o gettext

gcc encrypt.c det.c -o encrypt

gcc inverseA.c det.c -o incerseA

gcc decrypt.c det.c -o decrypt

注意 : polyalphabetic_substitution.tar 提供了生成好的程序文件

加解密过程

为了方便说明,以32阶矩阵为例 :

生成满足要求的矩阵A,指定阶数为32,写入到文件32keyA.txt,行列式可在标准输出查看

./generatekeyA -c 32 -o 32keyA.txt

生成数组B,指定长度为32,写入到文件32keyB.txt

./generatekeyB -c 32 -o 32keyB.txt

随机生成纯字母明文,指定长度为1000000,写入到文件plain.txt

./gettext -a 1000000 -o plain.txt

加密明文,指定阶数为32,读取文件plain.txt, 32keyA.txt, 32keyB.txt,将密文写入文件cipher.txt

./encrypt -c 32 -i plain.txt 32keyA.txt 32keyB.txt -o cipher.txt

生成逆矩阵A_1,指定阶数为32,读取文件32keyA.txt,写入文件32keyA_1.txt,行列式可在标准输出查看

./inverseA -c 32 -i 32keyA.txt -o 32keyA_1.txt

解密密文,指定阶数为32,读取文件cipher.txt, 32keyA_1.txt, 32keyB.txt,将结果写入文件output.txt

./decrypt -c 32 -i cipher.txt 32keyA_1.txt 32keyB.txt -o output.txt

注意 : 由于未做灵活的参数解析,以上指令的参数顺序不能改动。polyalphabetic_substitution.tar 包含了所有提到的文件。

结果分析

1000000个字母加密 :

16阶加密 : Use time 88591 us

16阶解密 : Use time 96396 us

32阶加密 : Use time 169211 us

32阶解密 : Use time 181925 us

细节

加密时,明文结尾无法凑够一组数组时,填充(padding)使用的是字母A。

求逆矩阵用的是且只能用伴随矩阵法。

关键代码

关键是求行列式的算法的优化。求行列式用的是递归求代数余子式的方法,但是要通过类似高斯消元的方法减小时间复杂度。

int det(int** M, int n)

{

int i, d;

int** M2 = (int**)malloc(n * sizeof(int *));

for (i = 0; i < n; ++i)

M2[i] = (int*)malloc(n * sizeof(int));

copy_matrix(M, M2, n);

// 把M2拿去算行列式,保护M1不被修改

d = det_re(M2, n);

for (i = 0; i < n; i++)

free(*(M2+i));

free(M2);

return d;

}

// 递归计算代数余子式求行列式

int det_re(int** M, int n)

{

if (n == 3)

return mod((M[0][0] * M[1][1] * M[2][2]) + (M[0][1] * M[1][2] * M[2][0]) + (M[0][2] * M[1][0] * M[2][1]) - \

((M[0][0] * M[1][2] * M[2][1]) + (M[0][1] * M[1][0] * M[2][2]) + (M[0][2] * M[1][1] * M[2][0])), MOD);

// 降低时间复杂的两个操作

elementary_transformation(M, n);

//if (n >= 16)

int count = sort_row_by_zero(M, n);

int sign = (int)(count % 2 == 0 ? 1 : -1);

// 正式计算

int i, j, k;

int len = n - 1; /*子行列式的阶*/

int s = 0;

int** p = (int**)malloc(len * sizeof(int*));

for (int i = 0; i < len; i++)

p[i] = (int*)malloc(len * sizeof(int));

for (k = 0; k < n; k++)

{

if (M[0][k] == 0)// 如果为0,就没必要继续往下算了,这就是减少时间复杂度的关键

continue;

for (i = 0; i < len; i++) {

for (j = 0; j < len; j++)

{

if (j < k) {

p[i][j] = mod(M[i + 1][j], MOD);

}

else {

p[i][j] = mod(M[i + 1][j + 1], MOD);

}

}

}

s += (int)(k % 2 == 0 ? 1 : -1) * M[0][k] * det(p, len); /*递归计算*/

}

for (i = 0; i < len; i++)

free(*(p + i));

free(p);

return mod(sign * s, MOD);

}

// 初等变换,减小时间复杂度的核心之一,输入的矩阵M需要提前分配空间,n为矩阵大小

void elementary_transformation(int **M, int n)

{

int i, j, k, temp, r, p, flag = 0;

for (p = n - 1; p >= 0; --p){ // 行,从下往上

for (r = 1; r < 4; ++r) { // 初等变换中小的那个数,从1到3都试一下

for (i = 0; i < n; ++i) // 列

{

if (M[p][i] == r) {

for (j = 0; j < n; ++j) { // 列

if (M[p][j] == 0 || j == i)

continue;

temp = M[p][j];

if (temp % r == 0) {

for (k = 0; k < n; ++k) { // 行

if (M[k][i] != 0)

M[k][j] = mod(M[k][j] - (int)(temp / r) * M[k][i], MOD);

}

}

}

if (r == 1) { // 如果有1可以变换,2和3都可以不用试了

flag = 1;

}

break;

}

}

if (flag == 1) {

flag = 0;

break;

}

}

}

return;

}

// 根据0的个数对矩阵M(提前了分配大小)的行排序,0多的行排在上面,n为矩阵大小。这也是一种初等变换,返回的是交换行的次数

int sort_row_by_zero(int **M, int n)

{

int *zero_array = (int*)calloc(n, sizeof(int));

int *zero_index = (int*)calloc(n, sizeof(int));

int i, j, temp, count = 0;

for (i = 0; i < n; ++i) {

for (j = 0; j < n; ++j) {

if (M[i][j] == 0)

zero_array[i] = zero_array[i] + 1;

}

}

count = sort_index(zero_array, n, zero_index);

free(zero_array);

int** M2 = (int**)malloc(n * sizeof(int *));

for (i = 0; i < n; ++i)

M2[i] = (int*)malloc(n * sizeof(int));

for (i = 0; i < n; ++i){

temp = zero_index[i];

for (j = 0; j < n; ++j){

M2[i][j] = M[temp][j];

}

}

copy_matrix(M2, M, n);

free(zero_index);

for (i = 0; i < n; i++)

free(*(M2+i));

free(M2);

return count;

}

// 对数组进行排序,并存储新数组在原数组的索引,输入数组array,数组大小n,输出排序后数组array,索引数组index。(都需要提前分配大小)

int sort_index(int* array, int n, int* index)

{

int i, j, temp1, temp2, count = 0;

for (i = 0; i < n; ++i)

index[i] = i;

for (i = 0; i < n - 1; i++) {

for(j = 0; j < n - 1 -i; j++)

if(array[j] < array[j+1])

{

temp1 = array[j];

array[j] = array[j+1];

array[j+1] = temp1;

temp2 = index[j];

index[j] = index[j+1];

index[j+1] = temp2;

count++;

}

}

return count;

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值