古典密码(Hill加密算法)

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/ttyue_123/article/details/52166464

      “Hill的加密与解密” 


650) this.width=650;" width="574" height="277" title="无标题.png" style="width:643px;height:242px;" src="http://s3.51cto.com/wyfs02/M00/7E/04/wKiom1b06QajKGjaAAAqLz5Pxr4581.png" alt="wKiom1b06QajKGjaAAAqLz5Pxr4581.png" />

       Hill加密是另一种多字母代替密码,与多表代替密码不同的是,Hill密码要求将明文分成同等规模的若干个分组(最后一个分组涉及到填充),每一个分组被整体的加密代换,即希尔密码属于分组加密。Hill密码的算法思想是:将一个分组中的d个连续的明文字母通过线性变换转换为d个密文字母。这种变换由d个线性方程决定,其中每个字母被分配一个数值(0,1,。。。,25)。解密只需要做一次逆变换就可以了,密钥就是变换矩阵本身。


       设明文为一维矩阵m,密文为一维矩阵c,密钥用k矩阵表示,则:

650) this.width=650;" width="673" height="198" title="无标题.png" style="width:596px;height:129px;" src="http://s3.51cto.com/wyfs02/M01/7E/00/wKioL1b057mQ0rzVAAAdTWnxYAQ682.png" alt="wKioL1b057mQ0rzVAAAdTWnxYAQ682.png" />

即密文分组=明文分组*密钥矩阵。


       本程序使用的密钥是:

650) this.width=650;" width="511" height="212" title="无标题.png" style="width:402px;height:97px;" src="http://s2.51cto.com/wyfs02/M02/7E/04/wKiom1b06CTSjgy9AAAZnz97wrs097.png" alt="wKiom1b06CTSjgy9AAAZnz97wrs097.png" />


      下面是具体的源程序:

—头文件:classical.h
#pragma once
 
//古典密码之希尔加密
#include <math.h>
#include <string.h>
 
#define ROW 4    //行
#define COL 4     //列
 
int* plus(int(*K)[COL], int * num)     //进行加密
{
    int *arr = (int *)calloc(sizeof(int),4);
    int sum = 0;
    int sub = 0;
    for (int i = 0; i < ROW; i++)      //1*4的行列式与4*4的行列式相乘
   {
       for (int j = 0; j < COL; j++)
       {
           sum = (*(num + j)) * (*(*(K + j) + i));
           sub = sub + sum;
       }
       arr[i] = (arr[i] + sub) % 26;
       sub = 0;
   }
    return arr;
}
 
int fun(int i, int j, int(*K)[COL])       //求伴随矩阵
{
    int num = 0;
    int arr[ROW][COL] = { 0 };
    int left = 0;
    int right = 0;
    for (int k1 = 0; k1 < ROW; k1++)
    {
        for (int k2 = 0; k2 < COL; k2++)
        {
            if (k1 < i && k2 < j)
            {
                arr[k1][k2] = *(*(K + k1) + k2);
            }
            else if (k1 < i && k2 > j)
            {
                arr[k1][k2 - 1] = *(*(K + k1) + k2);
            }
            else if (k1 > i && k2 > j)
           {
                arr[k1 - 1][k2 - 1] = *(*(K + k1) + k2);
            }
            else if (k1 > i && k2 < j)
           {
                arr[k1 - 1][k2] = *(*(K + k1) + k2);
           }
       }
    }
    left = arr[1][1] * arr[2][2] * arr[0][0] + arr[0][1] * arr[1][2] * arr[2][0]
           + arr[1][0] * arr[2][1] * arr[0][2];
    right = arr[0][2] * arr[1][1] * arr[2][0] + arr[0][1] * arr[1][0] * arr[2][2]
           + arr[0][0] * arr[1][2] * arr[2][1];
    num = pow((double)(-1), (i + 1) + (j + 1)) * (left - right);
    return num;
}
 
int* answer(int(*K)[COL], int * str, int det)      //希尔解密
{
    int ptr[ROW][COL] = { 0 };     //ptr为逆矩阵
    int* ans = (int *)calloc(sizeof(int), 4);
    int sum = 0;
    int sub = 0;
    int bag = 0;
    for (int i = 0; i < ROW; i++)
    {
        for (int j = 0; j < COL; j++)
        {
            bag = fun(i, j, K) / (det);
            if (bag < 0)
            {
                ptr[j][i] = (26 + bag) % (26);
             }
            else
            {
                ptr[j][i] = bag % (26);
            }
        }
    }
    for (int i = 0; i < ROW; i++)
    {
        for (int j = 0; j < COL; j++)
        {
            sum = (*(str + j)) * ptr[j][i];
            sub = sub + sum;
         }
        ans[i] = (ans[i] + sub) % 26;
        sub = 0;
    }
    return ans;
}
 
void menu()      //菜单
{
    printf("      ——古典密码          \n\n");
    printf("**********   1.加密    *******\n");
    printf("**********   2.解密    *******\n");
    printf("**********   0:退出    *******\n");
    printf("请选择:");
}
 
char* inputclear()       //输入明文
{
     printf("请输入明文:");
     char num[20] = {'\n'};
     char *ptr = num;
     int i = 0;
     char ch;
     fflush(stdin);      //清除缓冲区
     while ((ch = getchar()) != '\n')
     {
         num[i] = ch;
         i++;
      }
     return ptr;
}
 
char* inputsecret()       //输入密文
{
    printf("请输入密文:");
    char num[20] = { '\n' };
    char *ptr = num;
    int i = 0;
    char ch;
    fflush(stdin);      //清除缓冲区
    while ((ch = getchar()) != '\n')
    {
        num[i] = ch;
        i++;
    }
    return ptr;
}
 
void judge(int n, int(*K)[4])     //处理加密或解密
{
    char *ptr, *pln;
    int src[20];
    int num[4] = { 0 };
    int *parr = NULL;
    int *pnum = NULL;
    int det = -1;     //计算K的行列式的值
    switch (n)
    {   
        case 1:                                 //加密
            ptr = inputclear();
            for (int i = 0; i < strlen(ptr); i++)      //将字符串转化为数字
           {
               if (*ptr != '\n' && *ptr != EOF)
               {
                   src[i] = *(ptr + i) - 'A';
               }
               else
               {
                   break;
               }
           }
           printf("加密后得到的密文:");
           pnum = src;
           while (*pnum >= 0 && *pnum <= 25)
           { 
               for (int i = 0; i < ROW; i++)
               {
                   num[i] = *(pnum + i);
               }
               parr = plus(K, num);
               for (int j = 0; j < ROW; j++)
               {
                   printf("%c", *(parr+j) + 'A');
               }
                pnum = pnum + ROW;
           }
           printf("\n");
           free(parr);
           break;
      case 2:
           pln = inputsecret();
           for (int i = 0; i < strlen(pln); i++)      //将字符串转化为数字
           {
               if (*pln != '\n' && *pln != EOF)
               {
                   src[i] = *(pln + i) - 'A';
               }
               else
               {
                   break;
               }
            }
            printf("解密后得到的明文:");
            pnum = src;
            while (*pnum >= 0 && *pnum <= 25)
            {
                for (int i = 0; i < ROW; i++)
               {
                   num[i] = *(pnum + i);
               }
                parr = answer(K, num, det);
                for (int j = 0; j < ROW; j++)
                {
                    printf("%c", *(parr + j) + 'A');
                }
                pnum = pnum + ROW;
            }
            printf("\n");
            free(parr);
            break;
       case 0:
            exit(EXIT_FAILURE);
       default:
            break;
     }
}
 
—源文件:test.cpp
#define _CRT_SECURE_NO_WARNINGS 1
//希尔加密
 
#include <stdio.h>
#include <stdlib.h>
 
#include "classical.h"
 
int main()
{
     int K[4][4] = { { 8, 6, 9, 5 }, { 6, 9, 5, 10 }, { 5, 8, 4, 9 }, { 10, 6, 11, 4 } };   //密钥
   int left=K[0][0] * K[1][1] * K[2][2] * K[3][3] + K[1][0] * K[0][3] * K[3][2] * K[2][1]+ K[2][0] * K[3][1] * K[0][2] * K[1][3] + K[3][0] * K[0][1] * K[1][2] * K[2][3];
   int right = K[0][3] * K[1][2] * K[2][1] * K[3][0] + K[0][0] * K[1][3] * K[2][2] * 
  K[3][1]+ K[0][1] * K[1][0] * K[2][3] * K[3][2] + K[0][2] * K[1][1] * K[2][0] * K[3][3];
   int n = 0;
   menu();
   scanf("%d", &n);
   judge(n, K);
   system("pause");
   return 0;
}


       —运行结果:

          Hill加密:

650) this.width=650;" title="无标题.png" src="http://s2.51cto.com/wyfs02/M00/7E/01/wKioL1b07gOii5f3AABI-OH-6VM474.png" alt="wKioL1b07gOii5f3AABI-OH-6VM474.png" />

       Hill解密:

650) this.width=650;" title="无标题.png" src="http://s4.51cto.com/wyfs02/M02/7E/04/wKiom1b07giSCh5OAABKzpL1Dck643.png" alt="wKiom1b07giSCh5OAABKzpL1Dck643.png" />


         很明显,Hill密码将解密的长消息分组,分组的长度取决于密钥矩阵的维数,Hill密码的强度在于完全隐藏了单字母的频率。字母和数字的对应也可以更改为其他的方案,使得不容易攻击成功。一般来说,对抗仅有密文的攻击强度较高,但易受到已知明文攻击。



本文出自 “无心的执着” 博客,谢绝转载!

展开阅读全文

没有更多推荐了,返回首页