C语言实现hill(希尔)密码

简介: C语言实现hill(希尔)密码

一.认识hill密码

1.1基础认识

 Hill密码是一种经典的分组密码,使用线性代数的方法将每个字符映射到一个数字,并使用矩阵乘法来加密和解密文本。具体地说,Hill密码将明文分成n个字符一组,将每组看作是一个列向量,然后用一个n×n的可逆矩阵A对其进行乘法运算,得到一个新的列向量,这个新的列向量就是密文。要解密密文,只需使用A的逆矩阵A^-1进行矩阵乘法即可。

为了更好地保护加密数据的安全性,必须仔细选择矩阵A以确保Hill密码的安全性。如果矩阵A不是可逆矩阵或者选择的矩阵有某些规律可循,那么Hill密码就会很容易被破解。因此,在实际应用中,需要使用高质量的伪随机数生成器来生成随机矩阵,或者使用特定的加密标准中定义的固定矩阵。

1.2使用范围

虽然Hill密码相对简单,但它已经被广泛应用于一些领域,比如计算机网络安全、金融领域以及军事通信等。

二.基本原理

2.1 前提条件

由于Hill密码是一种线性密码,因此加密矩阵的选取至关重要。如果加密矩阵不合适,就可能导致加密后的密文不安全。为了保证密码的安全性,加密矩阵必须满足以下两个条件:

  • 加密矩阵必须是可逆的;
  • 加密矩阵的行列式必须不为0。

满足上述两个条件的加密矩阵可以通过随机生成或者其他复杂的方式来获得,从而提高Hill密码的安全性。

2.2加密步骤

具体地,假设要对一个长度为n的明文字符串进行Hill加密,分组大小为m,加密矩阵为K,则Hill加密的基本流程如下:

  • 对明文字符串进行填充,使其长度为m的倍数(可以使用空格、随机字符等进行填充);
  • 将填充后的明文字符串按照m个字符一组划分为n/m个明文分组,每个分组看作是一个m维列向量;
  • 将每个明文分组与加密矩阵K进行乘法运算,得到m维的密文列向量;
  • 将所有密文列向量拼接起来,得到加密后的密文字符串。

需要注意的是,加密矩阵K必须满足可逆性和行列式非零的条件,否则无法正常进行加密。

2.3解密步骤

Hill解密的基本步骤如下:

  • 将密文字符串按照分组大小m划分为若干个密文分组;
  • 对于每个密文分组,将其看作是一个m维列向量,并用加密矩阵K的逆矩阵K^-1进行乘法运算,得到对应的明文列向量;
  • 将所有明文列向量拼接起来即可得到原始明文字符串。

需要注意的是,加密矩阵K必须是可逆的,才能求出其逆矩阵K^-1。如果加密矩阵K不可逆,则无法进行解密操作。除此之外,还需要保证加密和解密使用的是同一个加密矩阵K。

三.优缺点

3.1优点

Hill密码的优点:

  • 采用了矩阵运算,加密复杂度较高,能够提供一定的安全性;
  • 可以处理长文本,不需要分组前进行打乱或置换等预处理,保留了明文的统计特征,增加了密码的难度;
  • 加密和解密过程可以通过矩阵运算实现,速度较快;
  • 密钥空间较大,取决于矩阵的大小和可用字符集。

3.2缺点

Hill密码的缺点

  • 此密码的安全性依赖于加密矩阵的选取,如果加密矩阵被泄漏,则密码将立即失去保护作用;
  • 对于不同的分组大小,需要使用不同的加密矩阵,这意味着需要为每个分组大小选择一个新的矩阵,这给加密和解密带来了额外的复杂性;
  • 容易受到纠错码攻击,即攻击者可以改变密文中某些字符,从而影响整个分组,进而影响解密结果;
  • 不适合用于对称密钥加密,因为当密钥过多时,加、解密的计算量会变得非常大。

四.补充

4.1参数说明

hill密码的解密过程中,存在求逆矩阵这一步,而要使其逆矩阵存在,基本要求是加密矩阵可逆

4.2字母表说明

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
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

在本次实验中,我们定义每个字母代表的数字如上所示。

五.C语言实现

5.1主程序

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "nijuzhen.h"        //导入我们自己写的求逆矩阵文件
#define Maxsize 100        //定义最大信息量
#define N 2                // 定义密匙矩阵的维度
/*这里是以下面的密匙矩阵为例子,实际上我们只知道加密矩阵,需要自己求解密矩阵*/
int keys[2][2]={{11,8},{3,7}};    //加密密匙
int illkeys[2][2]={{7,18},{23,11}};    //解密密匙
//矩阵乘法运算
void muiti(char *&p)
{
  for(int i=0;i<strlen(p);i++)
  {
    p[i]= p[i]+'a'-97*2;
  }
  int result[strlen(p)] = {0}; // 用于存储结果
  for (int i = 0; i < 2; i++) { // 遍历矩阵的行
    for (int j = 0; j < 2; j++) { // 遍历矩阵的列
      result[i] += p[j] * keys[j][i]; // 计算乘积并累加到结果数组中
    }
  }
  for(int i=0;i<strlen(p);i++)
  {
    printf("%c",(char)(result[i]%26+97));
  }
}
//逆矩阵乘法运算
void illmuiti(char *&p)
{
  for(int i=0;i<strlen(p);i++)
  {
    p[i]= p[i]+'a'-97*2;
  }
  int result[strlen(p)] = {0}; // 用于存储结果
  for (int i = 0; i < 2; i++) { // 遍历矩阵的行
    for (int j = 0; j < 2; j++) { // 遍历矩阵的列
      result[i] += p[j] * illkeys[j][i]; // 计算乘积并累加到结果数组中
    }
  }
  for(int i=0;i<strlen(p);i++)
  {
    printf("%c",(char)(result[i]%26+97));
  }
}
//加密函数
void jiami(char *&p)
{
  /*一般的hill密码都是n维列向量乘以一个n阶加密矩阵,但是有时候明文长度m远大于n,
    不符合线性代数中矩阵乘法的原则,我们可以把分成若干个n维列向量,分别进行加密,最后把
    加密的密文组合即可。*/
  if(strlen(p)%2==0)
  {
    int n=strlen(p)/2;
    char mimi[n][2];
    for(int i=0;i<strlen(p);i+=2)          //分割数组,两个一起构成新的数组
    {
      mimi[i/2][0]=p[i];
      mimi[i/2][1]=p[i+1];
    }
    printf("密文:");
    for(int j=0;j<n;j++)
    {
      char a=mimi[j][0];
      char b=mimi[j][1];
      char str[Maxsize];
      str[0]=a;
      str[1]=b;
      char *p =str;
      muiti(p);
    }
  }
  if(strlen(p)%2==1)
  {
    int n=strlen(p)/2+1;    //不能被2整除时,我们需要手动补位
    char mimi[n][2];
    for(int i=0;i<strlen(p);i+=2)          //分割数组,两个一起构成新的数组
    {
      mimi[i/2][0]=p[i];
      mimi[i/2][1]=p[i+1];
    }
    printf("密文:");
    for(int j=0;j<n;j++)           //每个分割出来的数组执行运算函数
    {
      char a=mimi[j][0];
      char b=mimi[j][1];
      char str[Maxsize];
      str[0]=a;
      str[1]=b;
      char *p =str;
      muiti(p);
    }
  }
}
//解密函数
void jiemi(char *&p)
{
  if(strlen(p)%2==0)
  {
    int n=strlen(p)/2;
    char mimi[n][2];
    for(int i=0;i<strlen(p);i+=2)          //分割数组,两个一起构成新的数组
    {
      mimi[i/2][0]=p[i];
      mimi[i/2][1]=p[i+1];
    }
    printf("明文:");
    for(int j=0;j<n;j++)
    {
      char a=mimi[j][0];
      char b=mimi[j][1];
      char str[Maxsize];
      str[0]=a;
      str[1]=b;
      char *p =str;
      illmuiti(p);
    }
  }
  if(strlen(p)%2==1)
  {
    int n=strlen(p)/2+1;    //不能被2整除时,我们需要手动补位
    char mimi[n][2];
    for(int i=0;i<strlen(p);i+=2)          //分割数组,两个一起构成新的数组
    {
      mimi[i/2][0]=p[i];
      mimi[i/2][1]=p[i+1];
    }
    printf("明文:");
    for(int j=0;j<n;j++)           //每个分割出来的数组执行运算函数
    {
      char a=mimi[j][0];
      char b=mimi[j][1];
      char str[Maxsize];
      str[0]=a;
      str[1]=b;
      char *p =str;
      illmuiti(p);
    }
  }
}
int main() 
{
  char str1[Maxsize],str2[Maxsize];
  char *p=str1,*q=str2;         //两个数组指针,分别代替明文、密文
  int a,b;
  printf("请输入明文:");
  scanf("%s",str1);
  jiami(p);
  printf("\n");
  printf("-----------------");
  printf("\n");
  printf("请输入密文:");
  scanf("%s",str2);
  jiemi(q);
}

5.2求逆矩阵.h文件

#include <stdio.h>
#define N 2 // 矩阵的维度
void print_matrix(int matrix[N][N]) {
  for(int i=0; i<N; i++) {
    for(int j=0; j<N; j++) {
      printf("%d ", matrix[i][j]);
    }
    printf("\n");
  }
}
int determinant(int a[N][N]) {
  return a[0][0]*a[1][1] - a[0][1]*a[1][0];
}
int inverse_matrix(int a[N][N], double b[N][N]) {
  int det = determinant(a);
  if(det == 0) {
    return 0;
  } else {
    b[0][0] = a[1][1]/det;
    b[0][1] = -a[0][1]/det;
    b[1][0] = -a[1][0]/det;
    b[1][1] = a[0][0]/det;
    return 1;
  }
}

5.3说明

这里的主程序为了方便模拟实验,博主在写代码时直接代入了一个加密矩阵和对应的解密矩阵,事实上我们可以通过第二部分求逆矩阵函数调用求逆矩阵。

六.运行结果

38933becb410160acd0e2c101256287e.jpg

16872d1fad6a178350b09172018516ea.jpg

博主这是用C语言实现的第三种加密方式了,如果感兴趣可以点击阅读其他的加密方式。

仿射密码

移位密码

相关文章
|
2月前
|
算法 搜索推荐 C语言
C语言数据结构之排序整合与比较(冒泡,选择,插入,希尔,堆排序,快排及改良,归并排序,计数排序)
C语言数据结构之排序整合与比较(冒泡,选择,插入,希尔,堆排序,快排及改良,归并排序,计数排序)
|
9月前
|
机器学习/深度学习 Java 数据安全/隐私保护
密码检查-C语言/Java
密码检查-C语言/Java
65 0
|
9月前
|
存储 算法 数据安全/隐私保护
虚位密码验证 保护C语言程序的数据安全性。
7位密码验证:保护C语言程序的数据安全性 密码验证是程序开发过程中保护数据安全性的重要环节。在C语言编程中,我们可以通过实现7位密码验证系统来提高程序的安全性。本文将介绍如何设计和实现这个系统,并讨论它对数据安全性的作用。
63 0
|
10月前
|
算法 搜索推荐 C语言
c语言数据结构-排序(冒泡+选择+插入+希尔)
c语言数据结构-排序(冒泡+选择+插入+希尔)
|
11月前
|
算法 C语言
C语言---插入排序(直接插入和希尔)
C语言---插入排序(直接插入和希尔)
105 0
|
11月前
|
安全 数据安全/隐私保护 C语言
C语言实现仿射密码
C语言实现仿射密码
131 0
|
11月前
|
数据安全/隐私保护 C语言
C语言实现移位密码
C语言实现移位密码
279 0
|
算法 搜索推荐 C语言
c语言数据结构冒泡|选择|插入|希尔
目录 冒泡排序: 选择排序: 插入排序: 希尔排序: 冒泡排序: 原理:基于交换的排序,每一轮将序列中的最大值(最小值)放到数组的尾部。使用循环重复操作,(每轮排序都会少一个最大值或最小值),当最后只剩下一个数据的时候整个序列就已经排好序了。 代码思路:从第一个数开始,每一次在数组中选两个数继续比较,如果前面的数大于后面的数,就将两者交换位置,第一次是1,2两个位置比较,第二次就是2,3两个位置比较,以此类推 //采用两层循环实现的方法 //arr是待排序数组的首地址,n是数组元素个数 void bubblesort1(int* arr, int n) { if (n < 2)
c语言数据结构冒泡|选择|插入|希尔
|
数据安全/隐私保护
凯撒密码转化,循环,C语言版!
则是这样的: 1. 对于字母字符,将其转换成其后的第3个字母。例如:A→D,a→d,X→A,x→a; 2. 对于非字母字符,保持不变。 现在,请你根据输入的一行字符,输出其对应的密码。
178 0
|
C语言 数据安全/隐私保护 UED
C语言实现密码登录界面,你可能已被盯上!
C语言实现密码登录界面,你可能已被盯上!
1669 0