基于Hill Cipher的C语言加解密程序输出错误排查求助
Hill密码C程序加解密错误排查与修复
你的程序存在多个核心逻辑错误,导致加解密输出异常,以下是具体问题和修复方案:
1. 数组维度定义错误
你定义的plaintxt[2][0]、encrypted[2][0]、decrypted[2][0]都是0列数组,无法存储任何数据。Hill密码中,明文/密文是2×1的向量,应该改为:
int plaintxt[2][1], encrypted[2][1], decrypted[2][1];
2. 加密矩阵乘法逻辑错误
加密循环中,你错误地使用了plaintxt[i][0]作为乘数,导致密钥行的每个元素都乘同一个明文元素,完全不符合矩阵行乘列的规则。正确的写法应该是遍历明文的列(这里是第0列),用plaintxt[j][0]:
// 错误写法 k = k + matrix[i][j] * plaintxt[i][0]; // 正确写法 k = k + matrix[i][j] * plaintxt[j][0];
3. 解密逻辑的多重错误
3.1 密文未初始化
解密模式下,你直接使用encrypted[i][0],但这个数组在解密流程中从未被赋值,导致使用垃圾数据计算。同时,解密应该提示用户输入密文而非明文。
3.2 逆矩阵计算错误(模26下的逆)
Hill密码的逆矩阵是在模26域下计算的,不能直接用浮点数除法。正确步骤是:
- 计算行列式的模26逆元(而非普通除法),只有当行列式与26互质时,逆元存在(你的程序只判断了行列式不为0,但没判断与26互质,比如行列式是2的话,模26没有逆元)。
- 伴随矩阵每个元素乘逆元后再模26,得到整数形式的逆矩阵,避免浮点数精度问题。
3.3 解密乘法逻辑错误
和加密的问题一样,矩阵乘法的索引错误,应该用密文的j索引而非i索引。
4. 模运算的负数处理
当计算结果为负数时(比如伴随矩阵的负元素),直接模26会得到负数,转字符时会出错。需要先加26再取模,确保结果在0-25之间:
// 示例:处理负数 value = (value % 26 + 26) % 26;
5. 流程逻辑顺序错误
程序应该先判断命令行参数(加密/解密),再根据模式提示输入明文或密文,而非统一输入明文。
修复后的完整代码
#include <stdio.h> #include <stdlib.h> #include <string.h> // 计算模m下a的逆元,返回-1表示无逆元 int mod_inverse(int a, int m) { a = a % m; for (int x = 1; x < m; x++) { if ((a * x) % m == 1) return x; } return -1; } int main(int argc, char *argv[]) { int i, j, k; int matrix[2][2], adjoint[2][2], plaintxt[2][1], encrypted[2][1], decrypted[2][1]; int determinant, inv_det; int inv_matrix[2][2]; // 改用整数存储模26下的逆矩阵 char msg[10]; // 检查命令行参数 if (argc != 2 || (strcmp(argv[1], "-e") != 0 && strcmp(argv[1], "-d") != 0)) { printf("用法: %s [-e|-d]\n", argv[0]); exit(EXIT_FAILURE); } // 输入密钥矩阵 printf("输入2X2密钥矩阵的元素,用空格分隔:\n"); for (i = 0; i < 2; i++) { for (j = 0; j < 2; j++) { scanf("%d", &matrix[i][j]); // 确保密钥元素在模26范围内 matrix[i][j] = (matrix[i][j] % 26 + 26) % 26; } } printf("\n密钥矩阵:\n"); for (i = 0; i < 2; i++) { for (j = 0; j < 2; j++) { printf("%d\t", matrix[i][j]); } printf("\n"); } // 计算行列式并验证有效性 determinant = (matrix[0][0] * matrix[1][1] - matrix[1][0] * matrix[0][1]) % 26; // 处理负行列式 determinant = (determinant + 26) % 26; if (determinant == 0) { printf("\n无效密钥:行列式为0,无逆矩阵。\n"); exit(EXIT_FAILURE); } inv_det = mod_inverse(determinant, 26); if (inv_det == -1) { printf("\n无效密钥:行列式与26不互质,模26下无逆矩阵。\n"); exit(EXIT_FAILURE); } // 计算伴随矩阵 adjoint[0][0] = matrix[1][1]; adjoint[1][1] = matrix[0][0]; adjoint[0][1] = (-matrix[0][1]) % 26; adjoint[1][0] = (-matrix[1][0]) % 26; // 处理伴随矩阵的负元素 for (i = 0; i < 2; i++) { for (j = 0; j < 2; j++) { adjoint[i][j] = (adjoint[i][j] + 26) % 26; } } // 计算模26下的逆矩阵 printf("\n模26下的逆矩阵:\n"); for (i = 0; i < 2; i++) { for (j = 0; j < 2; j++) { inv_matrix[i][j] = (adjoint[i][j] * inv_det) % 26; inv_matrix[i][j] = (inv_matrix[i][j] + 26) % 26; printf("%d\t", inv_matrix[i][j]); } printf("\n"); } // 根据模式输入明文/密文 if (strcmp(argv[1], "-e") == 0) { printf("\n输入2个明文字符:\n"); scanf("%s", msg); // 转换为0-25的整数 for (i = 0; i < 2; i++) { plaintxt[i][0] = (msg[i] - 'a' + 26) % 26; } // 加密:C = K * P mod 26 for (i = 0; i < 2; i++) { k = 0; for (j = 0; j < 2; j++) { k += matrix[i][j] * plaintxt[j][0]; } encrypted[i][0] = (k % 26 + 26) % 26; } printf("加密后的密文: "); for (i = 0; i < 2; i++) { printf("%c", encrypted[i][0] + 'a'); } } else if (strcmp(argv[1], "-d") == 0) { printf("\n输入2个密文字符:\n"); scanf("%s", msg); // 转换为0-25的整数 for (i = 0; i < 2; i++) { encrypted[i][0] = (msg[i] - 'a' + 26) % 26; } // 解密:P = K^-1 * C mod 26 for (i = 0; i < 2; i++) { k = 0; for (j = 0; j < 2; j++) { k += inv_matrix[i][j] * encrypted[j][0]; } decrypted[i][0] = (k % 26 + 26) % 26; } printf("解密后的明文: "); for (i = 0; i < 2; i++) { printf("%c", decrypted[i][0] + 'a'); } } printf("\n"); return 0; }
内容的提问来源于stack exchange,提问作者Kadie Webb
相关产品推荐
相关产品推荐

