本文介绍如何使用JavaScript实现Playfair和Hill两种古典密码算法。详细讲解了Playfair基于5x5密钥矩阵的替换规则及去重处理,以及Hill密码利用3x3矩阵进行线性变换加密的过程。代码包含密钥生成、明文整理及加解密逻辑,并分析了面向过程设计的不足与优化方向。
JavaScript实现Playfair与Hill古典密码算法详解
期末复习信息安全概论课程作业时,接触到Playfair和Hill这两种古典密码算法。使用JavaScript语言进行实现既有趣味性,又能借此机会巩固JS基础知识,边查阅资料边编码学习。
Playfair密码算法实现
Playfair算法部分
Playfair密码(英文:Playfair cipher 或 Playfair square)属于一种多表替换密码。它依赖一个由25个字母组成的5x5正方形密码表进行加密。针对英语26个字母,通常移除使用频率较低的Z,从而构成包含剩余25个字母的密码表。
实现思路如下:
第一步,编制密码表。
密码表依据用户提供的密钥(单词或词组)生成。若密钥中包含重复字母,需去除后续重复项,仅保留首次出现的字母。
例如,若密钥为“crazy dog”,可据此编制出相应的密码表结构。
|
C
|
O
|
H
|
M
|
T
|
|
R
|
G
|
I
|
N
|
U
|
|
A
|
B
|
J
|
P
|
V
|
|
Y
|
E
|
K
|
Q
|
W
|
|
D
|
F
|
L
|
S
|
X
|
具体代码如下:
/*
* 功能:编制密码表
*
* 参数:密钥(经过去除空格和大写处理)
*
* 返回:密码表
*/
function createKey(keychars){
//字母顺序数组
var allChars = ['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'];
//变量keychars获取字母在字母顺序表中位置,删除该字母
for(var i = 0 ;i<keychars.length;i++){
var index = allChars.indexOf(keychars[i]);
if (index > -1) {
allChars.splice(index, 1);
}
}
//将keychar中的字母插入到字母表中
for(var i = keychars.length-1;i>=0;i--){
allChars.unshift(keychars[i]);
}
//从第一列将keychars插入至密码表
for(var i = 0 ; i<5 ; i++){
for(var j = 0; j<5 ;j++){
key[j][i] = allChars[i*5+j];
}
}
}
在将密钥字符插入密码表时,需考虑去除重复字符及字母Z的情况,相关算法设计如下:
具体代码如下:
/*
* 功能:去除字符串中重复字母
*
* 参数:需要进行处理的字符串
*
* 返回:处理过的字符串
*/
function removeDuplicate(str){
var result = [],tempStr = "";
var arr = str.split('');//把字符串分割成数组
//arr.sort();//排序
for(var i = 0; i < arr.length; i++){
var repeatBack = true;//设计变量是为确保字符串前部分不存在相同字符,因为以下算法只能确保连在一起相同的字符
for(var j = 0;j<result.length ;j++){
if(arr[i] == result[j])
repeatBack = false;
}
if(arr[i] !== tempStr && repeatBack){
result.push(arr[i]);
tempStr = arr[i];
}else{
continue;
}
}
return result.join("");//将数组转换为字符串
}
第二步,整理明文。
将明文每两个字母分为一组。若分组后出现两个相同字母相邻,或最后一个字母单独剩余,则插入字母X进行填充。初期编码时未充分考虑单数个数的情况,曾强制拒绝输入,导致用户体验不佳,后续已优化处理。
var k = document.getElementById("keychars").value.toUpperCase().replace(/\s/ig,''); 对明文去除空格并转换为大写格式。
第三步,编写密文。
明文加密规则(参考常见资料): 1 )若p1 p2在同一行,对应密文c1 c2分别是紧靠p1 p2 右端的字母。其中第一列被看做是最后一列的右方。如,按照前表,ct对应oc 2 )若p1 p2在同一列,对应密文c1 c2分别是紧靠p1 p2 下方的字母。其中第一行被看做是最后一行的下方。 3 )若p1 p2不在同一行,不在同一列,则c1 c2是由p1 p2确定的矩形的其他两角的字母(至于横向替换还是纵向替换要事先约好,或自行尝试)。如按照前表,wh对应tk或kt。 如,依照上表,明文where there is life,there is hope. 可先整理为wh er et he re is li fe th er ei sh op ex 然后密文为:kt yg wo ok gy nl hj of cm yg kg lm mb wf 将密文变成大写,然后几个字母一组排列。 如5个一组就是KTYGW OOKGY NLHJO FCMYG KGLMM BWF 4,解密 将密钥填写在一个5*5的矩阵中(去出重复字母和字母z),矩阵中其它未用到的字母按顺序填在矩阵剩余位置中,根据替换矩阵由密文得到明文。反其道而行。 实现效果如图:

Hill密码算法实现
Hill算法部分
希尔密码(Hill Password)是基于基本矩阵论原理的替换密码。它同样依据一个由25个字母组成的5x5正方形密码表进行编写,表中排列有25个字母。对于英语中的26个字母,去掉最常用的Z,构成密码表。
实现思路如下:
第一步,编写字母表 var chars = ['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']; 第二步,随机生成密匙
具体代码如下:
/*
* 功能:随机生成密钥
*
* 返回:密匙矩阵
*/
function randomCreateKey(){
//随机生成0到26的数字
for(var i = 0;i<3;i++){
for(var j = 0;j<3;j++){
key[i][j] = Math.round(Math.random()*100%26)
}
}
}第三步,关键性代码,根据自动生成的密匙,对明文进行处理:
具体代码如下:
/*
* 功能:hill算法
*
* 参数:长度是3的倍数的大写数组
*
* 返回:加密后的字符串
*/
function hill(p){
//大写字母密文
var res = "";
//制定总共需要对字符串经行遍历的次数
var round = Math.round(p.length/3);
//处理
for(var b = 0;b<round;b++){
//明文3
var temp3 ="";
var tempArr3 = [];
var sumArr3 = [];
for(var i = 0;i<3;i++){
temp3 += p.shift();
for(var j = 0;j<chars.length;j++){
if(temp3[i] == chars[j])
tempArr3[i] = j;
}
}
//计算
for(var i =0;i<3;i++){
for(var j = 0;j<3;j++){
sumArr3[i] = (tempArr3[j]*key[i][j])%26;
}
}
//获取字符在字母表中对应索引
for(var i =0;i<3;i++){
res += chars[sumArr3[i]];
}
}
return res;
};
实现效果如图:

算法不足与总结
上述算法存在以下不足:
1,面向过程设计,耦合度高
2,过多嵌套循环,算法效率有待优化
3,对于可能出现的情况考虑不周到,例如没有对用户输入非字母字符时进行处理。
总结:
学习了一段时间的信息安全概论这门课,目前仅对信息安全了解皮毛。信息安全是一门很有趣的科目,平时遇到一些问题尽可能多思考,多动手,多运用。同时也要加强数学基础积累,巩固js基础,拓宽知识面。这条路任重道远。