字符处理:凯撒密码

凯撒密码Caesar cipher

根据历史的记载,古罗马的凯撒大帝以密码传递军事命令。他采用了一种简单的方式,即把字母按照一个固定的偏移量进行替换,如A换成E,B换成F,偏移四个位置。拿到军事命令的将军,知道这个事先约定的偏移量,就反向替换回去。
这么简单的方式,在古代是很安全的,因为古人绝大多数都目不识丁,写成明文都没多少人懂,更不要提写成密文了。
我们自己来实现一下(仅对26个字母)。我们用上面我们提到的ASCII编码的概念,可以简单低实现字母移位。ASCII码表中A-Z大写字母的编码为十六进制41-5A(十进制的65-90),a-z小写字母的编码为十六进制61-7A(十进制的97-122),可以看到编码本身是连续的,所以我们只需要统一加一个偏移量就可以了。
Python里面也提供了获取ASCII编码的函数ord(),还提供了通过ASCII码反过来得到字符的函数chr()。程序如下:

data = input("Enter message:")
Ndata=""
for c in data:
    n=ord(c)
    if ord(c)>=65 and ord(c)<=90:
        n = ord(c)+4
        if n>90:
            n=n-26
    if ord(c)>=97 and ord(c)<=122:
        n = ord(c)+4
        if n>122:
            n=n-26
    Ndata=Ndata + chr(n)
print (Ndata)

程序中,data存储用户输入的消息,Ndata就是加密后的消息。我们看一下最关键的语句:for c in data,Python很灵活,for语句能循环从一个字符串中一个一个定位字符,所以这句话的意思就是对字符串data中的每一个字符进行处理。ord(c)得到字符的ASCII编码,然后把编码加上偏移量,这个时候要注意了,加上偏移量后有的字母的编码就会超出字母的编码范围,这个时候我们就减掉26,这样实现循环移位。最后通过chr(n)转回去成新的字母。
测试一下,我们输入Hello August,程序返回Lipps Eykywx。
有了加密的程序,就得有解密的程序,如下:

data = input("Enter message:")
Ndata=""
for c in data:
    n=ord(c)
    if ord(c)>=65 and ord(c)<=90:
        n = ord(c)-4
        if n<65:
            n=n+26
    if ord(c)>=97 and ord(c)<=122:
        n = ord(c)-4
        if n<97:
            n=n+26
    Ndata=Ndata + chr(n)
print (Ndata)

很简单,把得到的字符编码减4就可以了,同样判断是否超出范围。
这样,凯撒和将军们就要有两个程序来加密和解密。有没有可能用同一个程序做到既加密又解密呢?其实稍微动一下脑筋就可以看出,如果把偏移量改成13,就可以用同一个程序了。
但是,这样的加密手段还是不够的,比较容易被解出来。更加好的方式是实现建一个对照表,将明文字母与秘文字母对照列出,不统一使用一个偏移量。

data = input("Enter message:")
Ndata=""
flt="abcdefghijklmnopqrstuvwxyz"
enc="qwertyuioplkjhgfdsazxcvbnm"
data=data.lower()
for c in data:
    i=flt.find(c)
    if i!=-1:
        Ndata=Ndata + enc[i]
    else:
        Ndata=Ndata + c
print (Ndata)

程序很简单,有一个明文串,一个密文对照串。对用户输入的消息,逐个字母找明文中的位置,然后找密文中对应的字符。注,字符串find()函数返回-1表示没有找到这个字符。
解密也是一样的,只不过是反过来先找密文中的位置,然后找明文中对应的字符。
按照这种加密方式,敌人要解密就难一些,除非他拿到了密码对照表。但是如果敌人有很多数据统计,还是能比较快地猜出对照表来的。如我们知道英语中的字母使用频度是不一样的,根据大量文本统计,频度见下表:

1 E 12.25 
2 T 9.41 
3 A 8.19 
4 O 7.26 
5 I 7.10 
6 N 7.06 
7 R 6.85 
8 S 6.36 
9 H 4.57 
10 D 3.91 
11 C 3.83
12 L 3.77
13 M 3.34 
14 P 2.89 
15 U 2.58 
16 F 2.26
17 G 1.71 
18 W 1.59 
19 Y 1.58 
20 B 1.47
21 K 0.41
22 J 0.14 
23 V 1.09 
24 X 0.21
25 Q 0.09
26 Z 0.08

字母e是用得最多的,所以拿到敌人密码后,我们可以假定出现最多次数的字母为e,这样一步步解密。
这样,历史上,在双方不断斗智斗勇的过程中,人类发展出了一整套密码术。不过我们知道,没有破不了的密码,只是时间和难度的问题。现在大家常用的是使用RSA非对称加密,据说通过这个加密后,全世界的电脑联合在一起也要数万年才能破解。世界的安全依赖于此,所以不难理解为什么量子计算会这么关键和敏感,这个技术会动摇现在的社会安全体系,原因就是理论上量子计算能在一瞬间完成现有计算机数万年才能计算出来的工作。

 

上一篇:numpy常用函数记录


下一篇:Python chr / ord 函数区别和使用 - Python零基础入门教程