古典密码之维吉尼亚密码实验

本文介绍了古典密码中的维吉尼亚密码,包括其原理、加密解密流程,并提供了使用高级语言实现的实验代码和结果。通过对维吉尼亚密码的学习,可以深入理解密码学中的多表密码和密钥应用。

学习目标:

维吉尼亚密码是古典密码中非常具有代表的例子。本实验要求用高级语言编写和调试一个简单的维吉尼亚密码实现及解密程序,通过本实验可以加深理解维吉尼亚密码原理。


预备知识:

人们在单一恺撒密码的基础上扩展出多表密码,称为“维吉尼亚”密码。它是由16世纪法国亨利三世王朝的布莱瑟•维吉尼亚发明的。维吉尼亚密码引入了“密钥”的概念,即根据密钥来决定用哪一行的密表来进行替换,以此来对抗字频统计。维吉尼亚密码的密钥空间大小为26m,所以即使m的值很小,使用穷尽密钥搜索方法也需要很长的时间。例如,当m=5时,密钥空间大小超过1.1*107,这样的密钥量已经超出了使用手算进行穷尽搜索的能力范围。

维吉尼亚密码引入了“密钥”的概念,即根据密钥来决定用哪一行的密表来进行替换,以此来对抗字频统计。假如以上面第一行代表明文字母,左面第一列代表密钥字母,对如下明文加密:

TO BE OR NOT TO BE THAT IS THE QUESTION

当选定RELATIONS作为密钥时,加密过程是:明文一个字母为T,第一个密钥字母为R,因此可以找到在R行中代替T的为K,依此类推,得出对应关系如下:

密钥:RELAT IONSR ELATI ONSRE LATIO NSREL

明文:TOBEO RNOTT OBETH ATIST HEQUE STION

密文:KSMEH ZBBLK SMEMP OGAJX SEJCS FLZSY

历史上以维吉尼亚密表为基础又演变出很多种加密方法,其基本元素无非是密表与密钥,并一直沿用到二战以后的初级电子密码机上。

加密流程:

(1)编号。将A-Z以编号0-25编号;

(2)选取密钥。举例:wangyuhang;

(3)明文处理。去掉所有空格;举例:明文为we are discovered save yourself;处理后:wearediscoveredsaveyourself;

(4)密钥处理。将密钥重复排列;处理后:wangyuhangwangyuhangwangyuh;

(5)加密。举例:明文第一个字母W编码为22,密钥第一个字母为W编码为22;22+22=44,因为44>26,所以44-26=18;18对应字母为Q,故将W加密为Q;明文第二个字母E编码为4,密钥第二个字母为A编码为0;4+0=4,4对应字母为E,故将E加密为E;以此类推;

(6)输出密文。举例:senxadvyyoikneqywvrekueyals。

解密流程:

(1)编号。将A-Z以编号0-25编号;

(2)获取密钥。举例:wangyuhang;

(3)密文处理。去掉所有空格;处理后:senxadvyyoikneqywvrekueyals;

(4)密钥处理。将密钥重复排列;处理后:wangyuhangwangyuhangwangyuh;

(5)解密。举例:密文第一个字母Q编码为18,密钥第一个字母为W编码为22;18-22=-4,因为-4<0,所以-4+26=22;22对应字母为W,故将Q解密为W;密文第二个字母E编码为4,密钥第二个字母为A编码为0;4-0=4,4对应字母为E,故将E解密为E,以此类推;

(6)明文处理。根据相关语言释读,按照正确的语言格式整理明文;举例:we are discovered save yourself。


实验代码:

#include <iostream> 
#include <cstring> 
using namespace std;
#define MINCHAR 97
#define CHARSUM 26
char table[CHARSUM][CHARSUM];
bool Init();
bool Encode(char* key, char* source, char* dest);
bool Dncode(char* key, char* source, char* dest);
int main()
{
  if(!Init())
  {
      cout << "初始化错误!" << endl;
      return 1;
  }
  char key[256];
  char str1[256];
  char str2[256];
  int operation;
  while(1)
  {
      do
      {
        cout << "请选择一个操作:1. 加密;2. 解密;-1. 退出\n";
        cin >> operation;
      }while(operation != -1 && operation != 1 && operation != 2);
      if(operation == -1)
        return 0;
      else if(operation == 1)//加密
      {
        cout << "请输入密钥:";
        cin >> key;
        cout << "请输入待加密字符串:";
        cin >> str1;
        Encode(key, str1, str2);
        cout << "加密后的字符串:" << str2 << endl;
      }
      else if(operation == 2)//解密
      {
        cout << "请输入密钥:";
        cin >> key;
        cout << "请输入待解密字符串:";
        cin >> str1;
        Dncode(key, str1, str2);
        cout << "解密后的字符串:" << str2 << endl;
      }
      cout << endl;
  }
  return 0;
}
// 初始化维吉尼亚方阵
bool Init()
{
  int i, j;
  for(i = 0; i < CHARSUM; i++)
  {
      for(j = 0; j < CHARSUM; j++)
      {
        table[i][j] = 65 + (i + j) % CHARSUM;
      }
  }
  return true;
}
// 加密
// key:密钥
// source:待加密的字符串
// dest:经过加密后的字符串
bool Encode(char* key, char* source, char* dest)
{
  char* tempSource = source;
  char* tempKey = key;
  char* tempDest = dest;
    do
  {
      *tempDest = table[(*tempKey) - MINCHAR][(*tempSource) - MINCHAR];
      tempDest++;
      if(!(*(++tempKey)))
        tempKey = key;
  }while(*tempSource++);
    dest[strlen(source)] = 0;
  return true;
}
// 解密
// key:密钥
// source:待解密的字符串
// dest:经过解密后的字符串
bool Dncode(char* key, char* source, char* dest)
{
  char* tempSource = source;
  char* tempKey = key;
  char* tempDest = dest;
  char offset;
    do
  {
      offset = (*tempSource) - (*tempKey);
      offset = offset >= 0 ? offset : offset + CHARSUM;
      *tempDest = MINCHAR + offset;
      tempDest++;
      if(!(*(++tempKey)))
        tempKey = key;
  }while(*++tempSource);
  dest[strlen(source)] = 0;
  return true;
}

实验结果:

实验截图

思考:

1.维吉尼亚密码属于单表密码还是多表密码?

2.维吉尼亚密码中加密密钥和解密密钥相同吗?

答案:

1.多表密码。

2.相同。

### 一、实验目的 通过本次实验,深入理解维吉尼亚密码的加密和解密原理,掌握使用编程语言(如 C 语言)实现维吉尼亚密码算法的方法,提高对古典密码学的实际应用能力和编程实践能力。 ### 二、实验原理 维吉尼亚密码是一种多表代换密码,它通过使用一个密钥词,将明文的每个字母根据密钥词中对应位置的字母进行不同的移位加密。假设密钥词为 $K = k_1k_2\cdots k_n$,明文为 $M = m_1m_2\cdots m_s$,则加密过程为:$C_i=(m_i + k_{i\bmod n})\bmod 26$,其中 $C_i$ 为密文第 $i$ 个字母,$m_i$ 为明文第 $i$ 个字母,$k_{i\bmod n}$ 为密钥词中对应位置的字母所代表的移位值。解密过程则为:$M_i=(C_i - k_{i\bmod n})\bmod 26$。 ### 三、实验环境 编程语言:C 语言 编译环境:例如 GCC 编译器 ### 四、实验步骤 #### 1. 输入处理 编写程序,实现从用户输入或文件读取明文和密钥词的功能。确保输入的明文和密钥词仅包含英文字母,若包含其他字符,可进行相应的过滤或提示用户重新输入。 #### 2. 加密实现 根据维吉尼亚密码的加密原理,编写加密函数。将明文和密钥词转换为对应的数字($A=0,B = 1,\cdots,Z = 25$),然后按照加密公式进行计算,最后将结果转换回字母形式得到密文。 以下是一个简单的 C 语言示例代码: ```c #include <stdio.h> #include <string.h> #include <ctype.h> void vigenere_encrypt(char *plaintext, char *key, char *ciphertext) { int key_length = strlen(key); int i; for (i = 0; plaintext[i] != '\0'; i++) { if (isalpha(plaintext[i])) { char base = isupper(plaintext[i]) ? 'A' : 'a'; int shift = key[i % key_length] - 'A'; ciphertext[i] = ((plaintext[i] - base + shift) % 26) + base; } else { ciphertext[i] = plaintext[i]; } } ciphertext[i] = '\0'; } int main() { char plaintext[1000]; char key[100]; char ciphertext[1000]; printf("请输入明文: "); fgets(plaintext, sizeof(plaintext), stdin); plaintext[strcspn(plaintext, "\n")] = 0; printf("请输入密钥: "); fgets(key, sizeof(key), stdin); key[strcspn(key, "\n")] = 0; vigenere_encrypt(plaintext, key, ciphertext); printf("加密后的密文为: %s\n", ciphertext); return 0; } ``` #### 3. 解密实现 编写解密函数,根据加密后的密文和密钥词,按照解密公式进行计算,将密文还原为明文。 ```c void vigenere_decrypt(char *ciphertext, char *key, char *plaintext) { int key_length = strlen(key); int i; for (i = 0; ciphertext[i] != '\0'; i++) { if (isalpha(ciphertext[i])) { char base = isupper(ciphertext[i]) ? 'A' : 'a'; int shift = key[i % key_length] - 'A'; plaintext[i] = ((ciphertext[i] - base - shift + 26) % 26) + base; } else { plaintext[i] = ciphertext[i]; } } plaintext[i] = '\0'; } ``` #### 4. 重合指数计算 统计密文中各个字母出现的频数,根据公式计算重合指数。先统计出各个字母出现的频数 $f(a),f(b),\cdots,f(z)$,且 $f(a)+f(b)+\cdots+f(z)=X$($X$ 就是密文长度),然后把所有的 $f(字母)\times(f(字母) - 1)$ 的和求出来,假设为 $sum$,$sum/(X\times(X - 1))$ 就是重合指数 [^2]。 ```c double index_of_coincidence(char *ciphertext) { int freq[26] = {0}; int i; int X = 0; for (i = 0; ciphertext[i] != '\0'; i++) { if (isalpha(ciphertext[i])) { char base = isupper(ciphertext[i]) ? 'A' : 'a'; freq[ciphertext[i] - base]++; X++; } } int sum = 0; for (i = 0; i < 26; i++) { sum += freq[i] * (freq[i] - 1); } return (double)sum / (X * (X - 1)); } ``` ### 五、实验结果 输入不同的明文和密钥词,运行程序进行加密和解密操作,记录加密后的密文和解密后的明文,验证加密和解密的正确性。同时,计算密文的重合指数,并分析重合指数与密钥长度等因素的关系。 ### 六、实验总结 通过本次实验,成功实现了维吉尼亚密码的加密和解密功能,对维吉尼亚密码的原理有了更深入的理解。在实验过程中,体会到了多表代换密码相对单表代换密码的安全性提升。同时,掌握了使用 C 语言进行字符串处理和密码算法实现的方法。在实际应用中,维吉尼亚密码虽然在古典密码学中有一定的优势,但随着密码分析技术的发展,其安全性已不能满足现代信息安全的需求。 ### 七、实验思考 1. 维吉尼亚密码的安全性与密钥长度有怎样的关系? 2. 如何通过重合指数来推测密钥长度? 3. 维吉尼亚密码在面对已知明文攻击时的脆弱性如何?
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值