所谓凯撒加密是一种替换加密的技术,明文中的所有字母都在字母表上向后(或向前)按照一个固定数目进行偏移后被替换成密文。
例如,当偏移量是3的时候,所有的字母A将被替换成D,B变成E,以此类推。
明: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
密: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
message = 'hello world! Nice to meet you.'
key = 13
mode = 'encrypt' # encrypt or decrypt 选择加密或解密
letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
translated = ''
message = message.upper() #字母转为大写
for symbol in message:
if symbol in letters:
num = letters.find(symbol)
if mode == 'encrypt':
num = num + key
elif mode == 'decrypt':
num = num - key
if num >= len(letters):
num = num - len(letters)
elif num < 0:
num = num + len(letters)
translated = translated + letters[num]
else:
translated = translated + symbol
print(translated)
首先创建了一个名为letters的字符集,然后将需要加密的内容按照字符集中的顺序偏移进行加密。如:
H在字符集中是第7位(从0开始数)偏移13位(密匙)则是U(第20位)
O在字符集中是第14位偏移13位则是27位,但是字符集只有26位,便减去26等于1(B)
明文字母 | 明文数字 | 密匙 | 结果 | 密文字母 |
---|---|---|---|---|
H | 7 | 13 | 20 | 20=U |
E | 4 | 13 | 17 | 17=R |
L | 11 | 13 | 24 | 24=Y |
L | 11 | 13 | 24 | 24=Y |
O | 14 | 13 | 27>26 | 27-26=1=B |
所以最后的结果为:URYYB JBEYQ! AVPR GB ZRRG LBH.
解密的方法也是如此,若所得的结果小于0时,则相应的加上26。
message = 'URYYB JBEYQ! AVPR GB ZRRG LBH.'
letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
for key in range(len(letters)):
translated = ''
for symbol in message:
if symbol in letters:
num = letters.find(symbol)
num = num - key
if num < 0:
num = num + len(letters)
translated = translated +letters[num]
else:
translated = translated + symbol
print('key #%s: %s ' %(key,translated))
我们只需要尝试26种不同密匙就能将凯撒加密法破译,而计算机能够轻而易举的完成这件工作。显然为了确保信息的安全,这种密匙少容易破解的加密法是不适合的。
换位加密法很好的解决了密匙少易破解的缺陷
换位加密法不是把字符替换成其他字符,而是搞乱消息符号的顺序,使原来的的消息不可读。
假设我们的密匙为8,则先画出8个格子,依次放入一个字符。如果不够再添加一行
最后两个灰色的格子是为了提醒我们忽略他们。密文是从左上往下读:Hretel ldtyl!ooo u Nm.wieoce (最后两个灰色格子不算入其内)
#transpositionEncrypt.py
def main():
myMessage = 'Hello world! Nice to meet you.'
myKey = 8
ciphertext = encryptMessage(myKey,myMessage)
print(ciphertext + '|') #密文末尾加上 | 符号是为了方便看出密文末尾是否有空格符
def encryptMessage(key,message):
ciphertext = [''] * key
for col in range(key):
pointer = col
while pointer < len(message):
ciphertext[col] += message[pointer]
pointer += key
return ''.join(ciphertext)
if __name__ == '__main__':
main()
在while循环中,我们会把每隔key个字符挑选出来放入ciphertext[col]中
如果我们将while循环改为:
运行结果为:
join()方法
在shell做个小测试
join()方法的用途就是接受一个字符串列表,返回一个字符串
调用join()方法的字符串会放在列表字符串的中间,如’00’.join(h)
解密方法和加密其实是差不多的(这里密匙同样是8)
#transpositionDecrypt.py
import math
def main():
myMessage = 'Hretel ldtyl!ooo u Nm.wieoce'
myKey = 8
plaintext = decryptMessage(myKey,myMessage)
print(plaintext + '|')
def decryptMessage(key,message):
numOfColumns = math.ceil(len(message) / key) #求出所需列数
numOfRows = key
numOfShadeedBoxes = (numOfColumns * numOfRows) - len(message) #计算灰格子个数
plaintext = [''] * numOfColumns #创建列表
col = 0
row = 0
for symbol in message:
plaintext[col] += symbol
col += 1
if(col == numOfColumns) or (col == numOfColumns - 1 and row >= numOfRows - numOfShadeedBoxes):
col = 0
row += 1
return ''.join(plaintext)
if __name__ == '__main__':
main()
在这个循环中,第一步是把symbol连接到plaintext列表中col位置的字符串。接着就是col自增,以便symbol会被连接到下一个字符串。
有两种情况我们会把col重新设为0。一、col超过plaintext的最后一个索引(即col=numOfColumns)二、col等于最后一个索引,且row指向的行在最后一列有灰色格子。
见详细过程:
这里其实就可以发现换位加密法的密匙与需要加密的密文长度有关,如果需要加密的只有十几个字符,但是密匙确实二十,显而易见这样的加密是毫无意义的。但是如果你的密文是长篇大论,那么就会有成千上万个密匙。
import os,time,sys,transpositionEncrypt,transpositionDecrypt
def main():
inputFilename = 'hello.txt'
outputFilename = 'hello.encrypted.txt'
myKey = 10
myMode = 'encrypt' #encrypt or decrypt
#检查待读文件是否存在
if not os.path.exists(inputFilename):
print('%s 文件不存在' %(inputFilename))
sys.exit()
if os.path.exists(outputFilename):
print('%s 文件已存在,将会覆盖原文件。是否继续? YES or NO?' %(outputFilename))
response = input('>')
if not response.lower().startswith('y'):
sys.exit()
#读文件
fileObj = open(inputFilename)
content = fileObj.read()
fileObj.close()
print('%sing...' %(myMode.title()))
if myMode == 'encrypt':
translated = transpositionEncrypt.encryptMessage(myKey,content)
elif myMode == 'decrypt':
translated = transpositionDecrypt.decryptMessage(myKey,content)
outputFileObj = open(outputFilename,'w')
outputFileObj.write(translated)
outputFileObj.close()
print('over')
if __name__ == '__main__':
main()
Al Sweigart《Python密码学编程》读后笔记