维吉尼亚密码

维吉尼亚密码(又译维热纳尔密码)是使用一系列凯撒密码组成密码字母表的加密算法,属于多表密码的一种简单形式。

【加密原理】

明文:I Love You

密钥:OK

        首先,密钥长度需要与明文长度相同,如果少于明文长度,则重复拼接直到长度相等。本例中,明文长度为8个字母(非字母忽略),密钥补全为“OKOKOKOK”。

      然后根据密码表进行加密。明文第一个字母是“I”,密钥第一个字母是“O”,在表格中找到“I”列与“O”行的相交点,字母“W”就是密文的第一个字母。同理,“L”列与“K”行交点字母是“V”。“O”列与“O”行交点字母是“C”……以此类推,得到密文: W VCFS ICE。     

【解密原理】

密文:PWZRNZBZ EA NQKBUHN LNB

密钥:wind

        首先把密钥重复拼接到和密文长度相同,上例中密文为20位字母,密钥拼接后为:windwindwindwindwind。

        密文P对应密钥W,在密码表中找出W行为P的列,沿着这一列向上找到最上面的字母是T。以此类推,得到明文:tomorrow is another day。

【卡西斯基试验】是基于类似的常用单词有可能被同样的密钥字母进行加密,从而在密文中重复出现。例如,明文中不同的CRYPTO可能被密钥ABCDEF加密成不同的密文:

密钥:ABCDEF   AB  CDEFA   BCD   EFABCDEFABCD

明文:CRYPTO  IS    SHORT   FOR  CRYPTOGRAPHY

密文:CSASXT   IT    UKSWT  GQU  GWYQVRKWAQJB

此时明文中重复的元素在密文中并不重复。然而,如果密钥相同的话,结果可能便为(使用密钥ABCD):

密钥:ABCDAB  CD  ABCDA   BCD   ABCDABCDABCD

明文:CRYPTO  IS   SHORT   FOR   CRYPTOGRAPHY

密文:CSASTP  KV  SIQUT    GQU   CSASTPIUAQJB

此时卡西斯基试验就能产生效果。对于更长的段落此方法更为有效,因为通常密文中重复的片段会更多。如通过下面的密文就能破译出密钥的长度:

密文:DYDUXRMHTVDVNQDQNWDYDUXRMHARTJGWNQD

其中,两个DYDUXRMH的出现相隔了18个字母。因此,可以假定密钥的长度是18的约数,即长度为18、9、6、3或2。而两个NQD则相距20个字母,意味着密钥长度应为20的约数,20、10、5、4或2。取两者的交集,则可以基本确定密钥长度为2。

一旦能够确定密钥的长度,密文就能重新写成多列,列数与密钥长度对应。这样每一列其实就是一个凯撒密码,而此密码的密钥(偏移量)则对应于维吉尼亚密码密钥的相应字母。与破译凯撒密码类似的方法,就能将密文破译。

【C++实现】

#include<iostream> 
using namespace std;
#define MINCHAR 32 
#define CHARSUM 94 
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] = MINCHAR + (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;
}
  • 13
    点赞
  • 69
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

.98℃

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值