目录
1、原理
维吉尼亚密码(又译维热纳尔密码)是使用一系列凯撒密码组成密码字母表的加密算法,属于多表密码的一种简单形式。
1508年时,约翰尼斯·特里特米乌斯《隐写术》中发明的表格法成为了维吉尼亚密码的关键部分。这一加密技术也称为特里特米乌斯密码。这一方法真正出现是在吉奥万·巴蒂斯塔·贝拉索于1553年所著的书《吉奥万·巴蒂斯塔·贝拉索先生的算术》中。他以特里特米乌斯的表格法为基础,同时引入了密钥的概念。布莱斯·德·维吉尼亚于1586年亨利三世时期发明了更为简单却又更有效的自动密钥密码(autokey cipher)。之后,19世纪时贝拉索的方法被误认为是由维吉尼亚首先发明的,所以被称为维吉尼亚密码。
在凯撒密码中,每一个字母会有一定的偏移量变成另外一个字母,而维吉尼亚密码就是有多个偏移量不同的凯撒密码组成。维吉尼亚密码加密需要一个表格。表格是一个26*26的矩阵,每一行由26个英文字母组成,每一行由前一行向左偏移一位得到。加密时,明文字母作为列,对应的密钥字母作为行,所确定的坐标上的字母即为对应的密文字母,以此类推,循环使用密钥,得到密文。
用数字0-25代替字母A-Z,维吉尼亚密码加密算法为:
解密算法为:
2、流程图
3、编程实现
可以打表密码表,也可以取模计算,这也使用取模计算来加解密。
具体代码如下:
默认输入为小写英文字母可以带空格
主函数wjnyCipher.cpp
#include"wjny.h"
int main() {
while (1) {
show(); //菜单界面
keyDown(); //按键处理
system("pause");
system("cls");
}
}
wjny.h
#pragma once
#include<cstdio>
#include<iostream>
#include<cstring>
#include<Windows.h>
using namespace std;
void init();
void show();
void keyDown();
void readFile();
void saveFile();
void encrypt();
void decrypt();
wjny.cpp
#include "wjny.h"
string fileStr = "";
string finalStr = "";
void init()//初始化
{
fileStr = "";
finalStr = "";
}
void show()
{
cout << "***************维吉尼亚密码***************" << endl;
cout << "\t\t1.加密文件" << endl;
cout << "\t\t2.解密文件" << endl;
cout << "\t\t3.退出" << endl;
cout << "******************************************" << endl;
}
void keyDown()//按键处理
{
int userkey = 0;
cin >> userkey;
switch (userkey) {
case 1:
cout << "-----------------加密文件-----------------" << endl;
readFile();
encrypt();
saveFile();
init();
break;
case 2:
cout << "-----------------解密文件-----------------" << endl;
readFile();
decrypt();
saveFile();
init();
break;
case 3:
exit(0);
break;
}
}
void readFile()//读取文件
{
cout << "请输入文件名:" << endl;
string fileName;
cin >> fileName;
FILE* fp = fopen(fileName.c_str(), "r+");
if (fp == nullptr) {
cout << "未找到相关文件" << endl;
return;
}
else {
cout << "成功打开文件" << endl;
}
char ch;
int pos = 0;
while ((ch = fgetc(fp)) != EOF) {
fileStr += ch;
}
cout << endl << "待处理的文件为:" << endl;
cout << fileStr << endl;
fclose(fp);
}
void saveFile()//保存文件
{
string fileName;
cout << endl << "请输入要保存信息的文件名:" << endl;
cin >> fileName;
FILE* fp = fopen(fileName.c_str(), "w+");
if (fp == nullptr) {
cout << endl << "保存文件失败" << endl;
return;
}
else {
cout << endl << "保存成功" << endl;
}
fprintf(fp, "%s", finalStr.c_str());
fclose(fp);
}
void encrypt()//加密文件
{
string key;
cout << endl << "请输入密钥:" << endl;
cin >> key;
cout << endl << "按下任意键进行加密" << endl;
char ch = getchar(); ch = getchar();
int pos = 0;
for (char ch : fileStr) {
if (ch == ' ') {
finalStr += ' ';
}
else {
finalStr += (ch - 'a' + key[pos] - 'a') % 26 + 65;
pos = (pos + 1) % key.size();
}
}
cout << endl << "得到的密文为:" << endl;
cout << finalStr << endl;
}
void decrypt()//解密文件
{
string key;
cout << endl << "请输入密钥:" << endl;
cin >> key;
cout << endl << "按下任意键进行解密" << endl;
char ch = getchar(); ch = getchar();
int pos = 0;
for (char ch : fileStr) {
if (ch == ' ') {
finalStr += ' ';
continue;
}
else {
finalStr += (ch + 32 - 'a' - (key[pos] - 'a') + 26) % 26 + 97;
pos = (pos + 1) % key.size();
}
}
cout << endl << "得到的明文为:" << endl;
cout << finalStr << endl;
}
4、总结
对包括维吉尼亚密码在内的所有多表密码的破译都是以字母频率为基础的,但直接的频率分析频率分析却并不适用。例如,如果P是密文中出现次数最多的字母,则P很有可能对应E(前提是明文的语言为英语)。原因在于E是英语中使用频率最高的字母。然而,由于在维吉尼亚密码中,E可以被加密成不同的密文,因而简单的频率分析在这里并没有用。
破译维吉尼亚密码的关键在于它的密钥是循环重复的。如果我们知道了密钥的长度,那密文就可以被看作是交织在一起的凯撒密码,而其中每一个都可以单独破解。使用卡西斯基试验和弗里德曼试验来得到密钥的长度。(百度百科上面抄的)