原理介绍

在上述加密方法中,密文字母和明文字母之间是一对一映射 ,其加密方法均无法掩盖明文数据的统计特性,通过统计计算密文字母的统计特性,比较容易找出明文和密文之间的对应关系,从而达到破解密文的目的。
以英文文章为例,不同的字母在文章中出现的频率是不同的,美国密码学家William Freidman在对大量英文文章进行统计后,得到不同英文字母的普遍使用频率,不同英文字母(不区分大小写)的使用频率见下表。
字母 频率 字母 频率 字母 频率
A 0.0856 J 0.0133 S 0.0607
B 0.0139 K 0.0042 T 0.1045
C 0.0279 L 0.0339 U 0.0249
D 0.0378 M 0.0249 V 0.0092
E 0.1304 N 0.0707 W 0.0149
F 0.0289 O 0.0797 X 0.0017
G 0.0199 P 0.0199 Y 0.0199
H 0.0528 Q 0.0012 Z 0.0008
I 0.0627 R 0.0677

根据英文字母的使用频率,很容易推测出密文中的不同字符与明文中的不同字符的对应关系,从而破解密文。
以同样的方式还可以统计双字母和三字母的统计特性,例如:在双字母中TH、HE、ER和AN等是使用频率相对较高的双字母组合,而在三字母中则THE、ING、AND和HER等属于使用频率较高的三字母组合。利用双字母和三字母的统计特性,可以更有效地提高简单密码算法的准确性。
对单表代替密码进行改进,产生多表代替密码,多表代替密码隐藏了明文的统计特性,明文的结构信息被隐蔽了。
多表代替密码有两个共同的特征,其一是采用相关单表代换规则,其二是密钥决定代换的具体方法。
在这类密码算法中,比较典型的多表代替密码是维吉尼亚(Vigenere)密码和希尔(Hill)密码,希尔密码实际上也是多表代替密码的另一种变体。

维吉尼亚密码是多表代替密码中最简单的一种,它的代换规则和凯撒密码类似,每个代换表是明文字母移位到0到25次以后得到的代换单表,其代换表如下表所示。

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
a 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
b 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 A
c C D E F G H I J K L M N O P Q R S T U V W X Y Z A B
d D E F G H I J K L M N O P Q R S T U V W X Y Z A B C
e E F G H I J K L M N O P Q R S T U V W X Y Z A B C D
f F G H I J K L M N O P Q R S T U V W X Y Z A B C D E
g G H I J K L M N O P Q R S T U V W X Y Z A B C D E F
h H I J K L M N O P Q R S T U V W X Y Z A B C D E F G
i I J K L M N O P Q R S T U V W X Y Z A B C D E F G H
j J K L M N O P Q R S T U V W X Y Z A B C D E F G H I
k K L M N O P Q R S T U V W X Y Z A B C D E F G H I J
l L M N O P Q R S T U V W X Y Z A B C D E F G H I J K
m M N O P Q R S T U V W X Y Z A B C D E F G H I J K L
n N O P Q R S T U V W X Y Z A B C D E F G H I J K L M
o O P Q R S T U V W X Y Z A B C D E F G H I J K L M N
p P Q R S T U V W X Y Z A B C D E F G H I J K L M N O
q Q R S T U V W X Y Z A B C D E F G H I J K L M N O P
r R S T U V W X Y Z A B C D E F G H I J K L M N O P Q
s S T U V W X Y Z A B C D E F G H I J K L M N O P Q R
t T U V W X Y Z A B C D E F G H I J K L M N O P Q R S
u U V W X Y Z A B C D E F G H I J K L M N O P Q R S T
v V W X Y Z A B C D E F G H I J K L M N O P Q R S T U
w W X Y Z A B C D E F G H I J K L M N O P Q R S T U V
x X Y Z A B C D E F G H I J K L M N O P Q R S T U V W
y Y Z A B C D E F G H I J K L M N O P Q R S T U V W X
z Z 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
在上表中,第一行表示明文字母,第一列表示密钥字母,中间的大写字母表示加密后的密文,维吉尼亚密码的加密过程为,首先确定密钥,密钥在后续的加密过程中循环使用,然后根据密钥和明文来确定密文。
现设密钥为cipher,明文为seeyoulate,其加密结果如下:
  • 密钥:ciphereiph
  • 明文:seeyoulate
  • 密文:UMTFSLNIIL
明文的第1个字母为s,密钥的第1个字母为c,密文则是第c行第s列对应的字母U,在明文中第二个字母和第三个字母都是e,但由于密钥不同,因此加密得到的密文也不同,这样,密文隐藏了明文的统计特性。由于密钥的长度为6,那么在第6个字母之后密钥循环使用,即第7个明文字母加密时使用的是密钥的第1个字母,以此类推。因此,与单表代替密码相比维吉尼亚密码具有更高的安全性。

Cpp源代码

完整的实现共包括三个相应的文件,vigenere.h、 vigenere.cpp和main.cpp,在vigenere.h中主要完成对类的声明,vigenere.cpp文件主要完成vigenere.h中声明函数的定义,main.cpp中主要是对象的调用。
vigenere.h的代码如下:
#ifndef VIGENERE_H
#define VIGENERE_H
#include<string>

using namespace std;

class Vigenere{
	private:
		int cipherTable[26][26];		//数字编码表 
		string key;				//密钥 
		string explicitly;	        	//待处理的明文 
		string cipherText;			//加密后的密文 
		string explicitlyText;			//解密后的明文 
    public:
    	Vigenere();
		void init();				//初始化 cipherTable 
		void setKey(string k);		//设置加密密钥 
		void setExplicitly(string ex);	//设置明文 
		void encryption();			//加密明文,获得密文 
		void decryption();			//将密文转换为明文 
		void outPutCipherText();		//将处理结果(加密的密文)输出 
		void outPutExplicitlyText();	        //将处理结果(解密的明文)输出  
		int getPosition(int P,int n);	//获取密文解密的位置
};
#endif
vigenere.cpp的代码如下:
#include "vigenere.h"
#include <iostream>

Vigenere::Vigenere(){
	init();
}

void Vigenere::init(){
	int i,j;
	for(int i=0; i<26; i++){
		for(int j=0; j<26; j++){
			cipherTable[i][j]=(i+j)%26;
		}
	}
}

void Vigenere::encryption(){
	cipherText = explicitly; //初始化密文为明文
	unsigned int i;
	int m,n;
	for(i=0; i<explicitly.length(); i++){
		m=int(explicitly[i]-'a');
		n=int(key[i%(key.length())]-'a');
		cipherText[i]=char('A'+cipherTable[n][m]);
	} 
}

void Vigenere::decryption(){
	explicitlyText=cipherText;	//初始化解密明文为密文 
	unsigned int i;
	int m,n;
	for(i=0;i<cipherText.length();i++){
		n=int(key[i%(key.length())]-'a');
		m=getPosition(i,n);
		explicitlyText[i]=char('a'+m);
	} 
}

int Vigenere::getPosition(int p, int n){
	int position;
	int i;
	for(i=0;i<26;i++){
		if(char(cipherText[p])==char('A'+cipherTable[n][i])){
			position=i;
			break;
		}
	}
	return position;
}

void Vigenere::setKey(string k){
	key=k;
}

void Vigenere::setExplicitly(string ex){
	explicitly=ex;
}

void Vigenere::outPutCipherText(){
	cout<<cipherText<<endl;
}

void Vigenere::outPutExplicitlyText(){
	cout<<explicitlyText<<endl;
}
main.cpp的代码如下:
#include <iostream>
#include <string>
#include "vigenere.h"

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int main(int argc, char** argv) {
	
	Vigenere *v = new Vigenere();
	string key = "cipherciph";
	string ex = "seeyoulate";
	v->setKey(key);
	v->setExplicitly(ex);
	v->encryption();
	cout<<"加密效果:";
	v->outPutCipherText();
	
	v->decryption();
	cout<<"解密效果:";
	v->outPutExplicitlyText();
	
	return 0;
}
执行效果如下: