Virginia 密码的Maple实现

先放程序:Virginia的Maple实现

其中Virginia 1.0是正常版本,仅仅支持由纯小写字母构成的字符串的加密解密,而Virginia 2.0仅仅是为了好玩,添加了对特殊符号(例如空格、逗号等)的支持,但是目前都不知道大写字母的加密解密。以下只解释Virginia 1.0 。


一、维吉尼亚密码

wiki给出的解释是:Vigenère cipher,百度百科给出的解释是:维吉尼亚密码,总的来说,就是凯撒密码的加强版本。同时引入了“密钥”的概念。
一般密钥长度比明文长度要短。

二、加密

维吉尼亚密码需要由26张凯撒密表合成的一张密码表,作坐标图用。如下
《Virginia 密码的Maple实现》

                                    图1 维吉尼亚坐标图
有了这个坐标表,接下来就是对明文进行加密,假设要加密的信息是 virginia ,密钥是 good ,那么加密方法就是以明文和密钥作为坐标,通过查表即得到密文,首先明文第一个字母是v,而密钥第一个字母是g,那么查看v所在的那一行和g所在的那一列,可以得到交叉点的字母为b,即为密文的第一个字母。明文第二个字母是i,密钥第二个字母是o,那么查看i行o列,可以得到密文的第二个字母是w。依次,得到密文第三个字母是f,第四个字母是j。当明文到达第五个字母i时,此刻密钥已经用完了,那么循环利用,即又回到密钥的第一个字母,用明文的i和密钥的g进行对应,查上图得到密文第五个字母是o。依次下去,最后得到密文是bwfjobwd。
而我们自己观察上图可以看到上图是存在规律的,我们可以发现,假如将a到z按照英文字母表的顺序从0到25进行编号,用 clear 表示明文。用 clear[ i ] 表示明文的第 i 个字母,明文第一个字母就是 clear[ 1 ] 而不是 clear[ 0 ] 。类似的,用 key 表示密钥,用 key[ i ] 表示密钥的第 i 个字母,用 protect 表示密文,用 protect[ i ] 表示密文的第 i 个字母,那么我们可以得到如下公式:
protect[ i ] = ( clear[ i ] + key[ i ] ) mod 26
举个例子, 在字母表中按照a到z由0到25的排序方法,v对应的数字是21,而g对应的数字是6,那么就有( 21 + 6 ) mod 26 = 27 mod 26 = 1,所以密文的第一个字母就是对应着1的那个字母,也就是b。

三、解密

同样的,维吉尼亚密码也可以通过查表进行解密。但是既然我们知道了加密的数学表达,我们就可以推出解密的数学表达来降低我们的工作量。沿用加密时的规则,可以发现解密公式为:
clear[ i ] = ( protect[ i ] + 26 – key[ i ] ) mod 26

比如我们的密文第一个字母为b,那么就对应着数字1,而密钥第一个字母是g,对应数字6,所以就有( 1 + 26 – 6) mod 26 = 21 mod 26 = 21,所以明文的第一个字母就是对应着21的那个字幕,也就是v。

四、密钥和明文、密文联系

既然得到了计算公式,那么我们想,明文的第 i 个字母对应的是密钥的第 j 个字母,假如我们可以很快得到 i 和 j 的关系,那么加密和解密起来就很简单了。由于密钥是循环使用的,所以可以很快得到对应关系为:
j = i mod ( length( key ) )
但是很容易就可以发现上述公式的一个致命缺点:当 i 等于length( key )时,也就是原文的第 length( key ) 个字母,应该对应密钥的最后一个字母,也就是对应密钥的第 length( key ) 个字母,假如使用上述公式直接计算的话,得到 j = 0,这样子会导致出错,所以我们采用先减 1 再 加1 补齐的方法,得到 i 和 j 的正确对应方式为:
j = ( i – 1 ) mod ( length( key ) ) + 1

这样子,原文的第 length(key) 个字母对应的便是密钥的第 ( length(key) – 1 ) mod ( length(key) ) + 1 = length( key ) – 1 + 1 = length( key ) 个字母,至此,便是程序设计的思路。

五、程序设计

原文存储在cleartext.txt中,密码储存在key.txt中,由Alice输入,密文储存在pro.txt中,由加密文件c2p.mw生成,解密之后得到的原文信息储存在answer.txt中,由解密文p2c.mw生成。

假设原文为:mymaplehomeworkhasdoneiamsohappy
密码为:love
那么Alice在cleartext.txt中输入:
mymaplehomeworkhasdoneiamsohappy
在keytxt.txt输入:
love
然后保存。运行c2p.mw加密程序进行加密:

restart: 
clear := readline("cleartext.txt"): 
#从文件读入明文,保存为clear
key := readline("key.txt"):
#从文件读入密钥,保存为key
with(StringTools):
#加载字符串工具包
clearnumber := map(Ord, Explode(clear)):
keynumber := map(Ord, Explode(key)):
#将明文和密钥转换为Ascii码
P := "":
#新建空字符串P,用于保存密文,便于后面的拼接
for count to length(clear) do 
    clearnumber[count] :=(clearnumber[count] + keynumber[ (count - 1 mod length(key))+1]-194) mod 26:
    #算法核心,得到密文的Ascii码
    P := LowerCase(CaseJoin([P, Char(clearnumber[count]+97)])):
    #将密文Ascii码转换为小写字母并拼接
end do:
with(FileTools):
#加载文件工具包 
Text[WriteFile]("pro.txt", P):
#保存密文

然后Alice打开pro.txt查看加密后的密文,为:

xmheazzlzazazffllgysysdexgjlldkc

然后Alice将该密文和密码或者密文文件和密码文件发送给Bob。

Bob接收到密文或者密文文件之后,运行以下p2c.mw解密程序进行解密:

restart:
protext := readline("pro.txt"):
#从文件读入密文,保存为protext
key := readline("key.txt"):
#从文件读入密钥,保存为key
with(StringTools):
#加载字符串工具包
pronumber := map(Ord, Explode(protext)):
keynumber := map(Ord, Explode(key)):
#讲密文和密钥转换为Ascii码
C := "": 
#新建空字符串C,用于保存明文,便于后面拼接
for count to length(protext) do 
    pronumber[count] := (pronumber[count] - keynumber[ (count - 1 mod length(key))+1]+26) mod 26:
    #算法核心,得到明文的Ascii码
    C := LowerCase(CaseJoin([C, Char(pronumber[count]+97)])):
    #将明文Ascii码转换为小写字母并拼接
end do:
with(FileTools):
#加载文件工具包 
Text[WriteFile]("answer.txt", C):
#保存明文

然后Bob查看answer.txt文件查看原文,为:

mymaplehomeworkhasdoneiamsohappy

这样,Bob就得到了Alice传递的信息。

五、小结

维吉尼亚密码为较为基础的密码,基于凯撒移位密码,同时又是后世多种密码的基础,思路较为简单,用Maple实现的时候难点在于如何让Maple这一门符号变量为基础的程序语言支持Ascii码以及如何保证输入和查看的方便性,个中数学公式推导,只要有一点数论的基础就可以推导出来。

    原文作者:维吉尼亚加密问题
    原文地址: https://blog.csdn.net/walstruzz/article/details/50491557
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞