Hill2密码加解密及破译的C语言实现

加解密部分代码参考这位老哥Hill密码的加密与解密,做了相应的一些修改,需要注意的是代码中有两个问题尚待解决:

1.代码中补全位没有起到相应作用,如果输入明文为奇数则无法正常加解密。

2.当选取的密钥矩阵求逆后有小数元,无法实现正确解密。

代码如下:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define N 60

int main()
{
    int K1[2][2] = {0}, K2[2][2] = {0};
    int Temp1[2] = {0}, Temp2[2] = {0};
    char P[N] = {0}, C[N] = {0};
    int T1[N] = {0}, T2[N] = {0};
    int len, flag=0, temp, temp1, i, j;


    printf("Hill2密码\n\n");
    printf("请依次输入密钥矩阵的值:\n");
    
    for(i=0; i<2; i++)  //存储密钥 
    {
        for(j=0; j<2; j++)
        {
            scanf("%d", &K1[i][j]);
        }
    }

        //输入明文 
        printf("请输入明文:\n");
        scanf("%s", P);
        len = strlen(P);

        // 当长度为奇数时补齐一位
        if(len % 2 == 1)
        {
            P[len] = 'a';
            len = strlen(P);
            flag = 1;
        }

        // 将大写转成小写,并赋值给T1数组
        for(i=0; i<len; i++)
        {
            if(P[i] >= 'A' && P[i] <= 'Z')
            {
                P[i] = P[i] + 32;
            }

            T1[i] = P[i] - 'a';
        }


        // 得到加密后结果,存储在T2中
        for(i=0; i<len; i+=2)
        {
            Temp1[0] = T1[i];
            Temp1[1] = T1[i + 1];

            // Temp2存储密文int值
            Temp2[0] = (Temp1[0] * K1[0][0] + Temp1[1] * K1[1][0]) % 26;
            Temp2[1] = (Temp1[0] * K1[0][1] + Temp1[1] * K1[1][1]) % 26;

            T2[i] = Temp2[0];
            T2[i + 1] = Temp2[1];
        }

        //如果有补全位,输出时去掉补全位 
        if(flag == 1) 
        {
            len = len - 1;
        }

        printf("加密结果为:\n");
        for(i=0; i<len; i++)
        {
            C[i] = T2[i] + 'a';
            printf("%c ", C[i]);
        }
        printf("\n");
    

        //解密 
        printf("请输入密文:\n");
        scanf("%s", C);

        len = strlen(C);

        // 当长度为奇数时补齐一位
        if(len % 2 == 1)
        {
            C[len] = 'a';
            len = strlen(C);
            flag = 1;
        }

        //大小写转换 
        for(i=0; i<len; i++)
        {
            if(C[i] >= 'A' && C[i] <= 'Z')
            {
                C[i] = C[i] + 32;
            }

            T2[i] = C[i] - 'a';
        }

        // 求K的逆
        temp = -1;
        for(i=1; temp < 0; i++)
        {
            temp = (K1[0][0] * K1[1][1] - K1[0][1] * K1[1][0]) + 26 * i;
        }

        i = 1;
        while(1)
        {
            if((temp * i) % 26 == 1)
            {
                temp1 = i;
                break;
            }
            else
            {
                i++;
            }
        }

        K2[0][0] = K1[1][1] * temp1;
        K2[0][1] = (((-1 * K1[0][1]) + 26) * temp1) % 26;
        K2[1][0] = (((-1 * K1[1][0]) + 26) * temp1) % 26;
        K2[1][1] = K1[0][0] * temp1;


        // 得到解密后结果,存储在T2中
        for(i=0; i<len; i+=2)
        {
            Temp2[0] = T2[i];
            Temp2[1] = T2[i + 1];

            // Temp1存储明文int值
            Temp1[0] = (Temp2[0] * K2[0][0] + Temp2[1] * K2[1][0]) % 26;
            Temp1[1] = (Temp2[0] * K2[0][1] + Temp2[1] * K2[1][1]) % 26;

            T1[i] = Temp1[0];
            T1[i + 1] = Temp1[1];
        }

        if(flag == 1)
        {
            len = len - 1;
        }

        printf("解密结果为:\n");
        for(i=0; i<len; i++)
        {
            P[i] = T1[i] + 'a';
            printf("%c ", P[i]);
        }
        printf("\n"); 
        
    return 0;
}
 

破译原理网上很多利用,利用矩阵运算,再此不赘述,直接放上代码,和加解密一样,明文矩阵的逆若有小数元无法实现正常破译。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h> 
#define N 60

int main()
{
    int K[2][2] = {0};
    int Temp1[2] = {0}, Temp2[2] = {0};
    char c[N]={0},m[N]={0},_c[N]={0};
    int T1[N] = {0}, T2[N] = {0};
    int lenc,lenm,temp,temp1,i,j; 

    printf("破译Hill2密码\n\n");

        //输入已知明文段 
        printf("请输入已知明文:\n");
        scanf("%s", c);
        lenc = strlen(c);
         //输入已知密文段 
        printf("请输入已知密文:\n");
        scanf("%s", m);
        lenm= strlen(m);

        //当明密文长度不足4时报错 
        if(lenc<4||lenm<4)
        {
        	printf("明密文字段不满足破译条件");
        	assert(0);
        }

        //取前四位明文,将大写转成小写,并赋值给T1数组 
        for(i=0; i<4; i++)
        {
            if(c[i] >= 'A' && c[i] <= 'Z')
            {
                c[i] = c[i] + 32;
            }

            T1[i] = c[i] - 'a';
        }
        //取前四位密文,将大写转成小写,并赋值给T2数组
        for(i=0; i<4; i++)
        {
            if(m[i] >= 'A' && m[i] <= 'Z')
            {
                m[i] = m[i] + 32;
            }

            T2[i] = m[i] - 'a';
        }
        // 求明文数组的逆
        temp = -1;
        for(i=1; temp < 0; i++)
        {
            temp = (T1[0]*T1[3]-T1[1]*T1[2]) + 26 * i;
        }

        i = 1;
        while(1)
        {
            if((temp*i)%26==1)
            {
                temp1 = i;
                break;
            }
            else
            {
                i++;
            }
        }

        _c[0]=(T1[3]*temp1)%26;
        _c[1]=(((-1*T1[1]+26))*temp1)%26;
        _c[2]=(((-1*T1[2]+26))*temp1)%26;
        _c[3]=(T1[0]*temp1)%26;
        
        //密文矩阵右乘明文逆矩阵 
        K[0][0]=(T2[0]*_c[0]+T2[2]*_c[1])%26;
        K[0][1]=(T2[1]*_c[0]+T2[3]*_c[1])%26;
        K[1][0]=(T2[0]*_c[2]+T2[2]*_c[3])%26;
        K[1][1]=(T2[1]*_c[2]+T2[3]*_c[3])%26;
		 
        printf("密钥为:");
        for(i=0;i<2;i++)
		{
			for(j=0;j<2;j++)
			{
				printf("%d ",K[i][j]);
			}
		 } 
    
    return 0;
}
 

 

    原文作者:维吉尼亚加密问题
    原文地址: https://blog.csdn.net/MoKatto/article/details/84261131
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞