换位加密算法
打乱明文的顺序的一种方法:
列数即作为key值,这里key=8
列表中对应有key个字符串
末尾不用读
确定每个字符串的值,最后再把他们连接起来 形成密文
有个小问题是若结尾后面有若干个空格,需要加上一个识别符号来确定
加密“zhe ge she ji lie biao zhong de zi fu chuan si xiang.”,其中(s)为空格的标记 避免看成空
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
z | h | e | (s) | g | e | (s) | s |
h | e | (s) | j | i | (S) | l | i |
e | (s) | b | i | a | o | (s) | z |
h | o | n | g | (s) | d | e | (s) |
z | i | (s) | f | u | (s) | c | h |
a | n | (s) | s | i | (s) | x | i |
a | n | g | . |
读出第一列[0]:'zhehzaa'
读出第二列[1]:'he(s)oinn'
读出第三列[2]:'e(s)bn(s)(s)g'
读出第四列[3]:'(s)jigfs.'
读出第五列[4]:'gia(s)ui'
读出第六列[5]:'e(s)od(s)(s)'
读出第七列[6]:'(s)l(s)ecx'
读出第八列[7]:'siz(s)hi'
密文:'zhehzaa'+'he(s)oinn'+'e(s)bn(s)(s)g'+'(s)jigfs.'+'gia(s)ui'+'e(s)od(s)(s)'+'(s)l(s)ecx'+'siz(s)hi'='zhehzaahe oinne bn g jigfs.gia uie od l ecxsiz hi'
加密算法:
# Transposition Cipher Encryption # http://inventwithpython.com/hacking (BSD Licensed) import pyperclip def main(): myMessage = 'Common sense is not so common.' myKey = 8 #得到整个密文字符串 ciphertext = encryptMessage(myKey, myMessage) # Print the encrypted string in ciphertext to the screen, with # a | (called "pipe" character) after it in case there are spaces at # the end of the encrypted message. print(ciphertext + '|') # Copy the encrypted string in ciphertext to the clipboard. pyperclip.copy(ciphertext) #形参(parameter)是在函数被调用时包含被传递实参(argumrnt)的变量,形参会在函 #数返回时候自动删除 形参在def语句中 实参在调用中 实参的实际上在调用的时候 #赋值给了形参,对形参的修改只存在于函数内 也就是说形参如果被修改,提供实参值的 #变量不会改变 def encryptMessage(key, message): # Each string in ciphertext represents a column in the grid. #列表list [项,项,项,项,项...] 有索引操作和分片操作 注意第一项的索引是0 #注意切片操作是字符串的拷贝,列表里面的项也可以是列表:多重列表myList[0][1] #for可以迭代列表里的项 list上有len()和in运算 使用+和* 链接和复制列表 #先记住这个就好了,能对字符操作的大多数事情也能对列表list操作 ''' list()函数zai区间对象上构造列表 myList = list(range(10)) --> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] myList = list('Hello world!') --> ['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!'] ''' #创建列表,使之包含正确的空字符串 ciphertext = [''] * key # Loop through each column in ciphertext. for col in range(key): pointer = col # Keep looping until pointer goes past the length of the message. while pointer < len(message): # Place the character at pointer in message at the end of the # current column in the ciphertext list. ciphertext[col] += message[pointer] # move pointer over pointer += key # Convert the ciphertext list into a single string value and return it. return ''.join(ciphertext) # If transpositionEncrypt.py is run (instead of imported as a module) call # the main() function. if __name__ == '__main__': main()
输出:Cenoonommstmme oo snnio. s s c|
=====================================================================分割线================================================================================================
P.S. 用join()方法接受一个字符串列表返回一个字符串 即合并,调用jion()的字符串会放到列表里的各字符串之间作为分隔符 常用''.jion(myList)不要分割直接连接起来
>>> eggs = ['dogs', 'cats', 'mose'] >>> ''.jion(eggs) Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'str' object has no attribute 'jion' >>> ''.join(eggs) 'dogscatsmose' >>> '*'.join(eggs) 'dogs*cats*mose'
P.S. 当一个python程序运行时,在第一行代码运行前,有一个特殊的叫做__name__的变量会被赋值为字符串值'__main__',如果这个文档transpositionEncrypt.py被其他.py程序导入,
执行import transpositionEncrypt时,会加上.py来查找文件transpositionEncrypt.py,当一个transpositionEncrypt.py程序被导入时,
那么__name__会被赋值为字符串值’transpositionEncrypt‘,然后运行这个程序,但我们只是希望所有的def被执行而不运行main()函数,
# the main() function. if __name__ == '__main__': main()
这种单独的main()方法,使我们的程序可以作为一个程序单独运行,也可以作为一个模块导入另一个程序。
=====================================================================分割线================================================================================================
解密算法:
当收到'zhehzaahe oinne bn g jigfs.gia uie od l ecxsiz hi'并且知道key=8,我们来进行破译:
z |
h | e | h | z | a | a |
h | e | (s) | o | i | n | n |
e | (s) | b | n | (s) | (s) | g |
(s) | j | i | g | f | s | . |
g | i | a | (s) | u | i | |
e | (s) | o | d | (s) | (s) | |
(s) | l | (s) | e | c | z | |
s | i | z | (s) | h | i |
然后依次对每列向下读出,连接起来:'zhe ge she ji lie biao zhong de zi fu chuan si xiang.'
首先需要明白怎么画格子,解密时的格子和加密时候有很大不同,但是有相关的性质
1、将消息的长度除以密钥并向上取整数计算需要的列数
2、画出一定数量的格子,列数第一部计算,行数和密钥一样长
3、将总格子数减去密文长度得到最右边的那一列要涂黑的格子数
4、填入密文,从最上面一行开始,从左向右填入,跳过黑色的格子
5、获取明文,从最左边一列开始读取,从上往下读,依次对每列读取
# Transposition Cipher Decryption # http://inventwithpython.com/hacking (BSD Licensed) #同时导入多个模块用,分隔即可 import math, pyperclip def main(): myMessage = 'Cenoonommstmme oo snnio. s s c' myKey = 8 plaintext = decryptMessage(myKey, myMessage) # Print with a | (called "pipe" character) after it in case # there are spaces at the end of the decrypted message. print(plaintext + '|') pyperclip.copy(plaintext) def decryptMessage(key, message): # The transposition decrypt function will simulate the "columns" and # "rows" of the grid that the plaintext is written on by using a list # of strings. First, we need to calculate a few values. # The number of "columns" in our transposition grid: #/除法表达式返回浮点数21 / 3 = 7.0 #四舍五入 向下取整 和 向上取整 #四舍五入 round(22/5)=4 #向上取整 math.ceil() math.ceil(9.5) = 10 #向下取整 math.floor() math.floor(9.5) = 9 numOfColumns = math.ceil(len(message) / key) # The number of "rows" in our grid will need: numOfRows = key # The number of "shaded boxes" in the last "column" of the grid: numOfShadedBoxes = (numOfColumns * numOfRows) - len(message) # Each string in plaintext represents a column in the grid. #最后我们是要把所有的列读出来连接到一起 plaintext = [''] * numOfColumns # The col and row variables point to where in the grid the next # col和raw 来跟踪massge里的下一个字符所在的行和列 # character in the encrypted message will go. col = 0 row = 0 # 调整col和raw, 把symbol连接带plaintext列表里的所有字符串 for symbol in message: plaintext[col] += symbol col += 1 # point to next column # If there are no more columns OR we're at a shaded box, go back to # the first column and the next row. # and 和 or 运算用来简化代码 #有两种情况需要把col重新赋值为0,以便进行下一行的赋值 #1递增之后col超过了plaintext的最后一个索引numOfColumns-1 所以 col == numOfColumns #2col等于最后一个索引但是这时候不能填入格子因为这时的格子是黑的 if (col == numOfColumns) or (col == numOfColumns - 1 and row >= numOfRows - numOfShadedBoxes): col = 0 row += 1 return ''.join(plaintext) # If transpositionDecrypt.py is run (instead of imported as a module) call # the main() function. if __name__ == '__main__': main()
输出:Common sense is not so common.
暴力破译的话,在一定的范围内遍历key就好了。
尝试写一个自动测试加解密方案的小程序来确定算法的可行性:
# Transposition Cipher Test # http://inventwithpython.com/hacking (BSD Licensed) import random, sys, transpositionEncrypt, transpositionDecrypt def main(): #random.seed(数)是设置伪随机种子,特定的算法,所以一个种子产生的随机数都是可以预测的 random.seed(42) # set the random "seed" to a static value #测试20次 for i in range(20): # run 20 tests # Generate random messages to test. # The message will have a random length: message = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' * random.randint(4, 40) # Convert the message string to a list to shuffle it. # 随机打乱一个字符串66666666666666666666 # 先使用list()把这个字符串转化成列表mylist,每一个项都是一个字母, # 然后使用random.shuffle(mylist)打乱这个列表,请记住random.shuffle()是就地修改, # 而不是某个对象的调用,是random的方法。 # 最后再用''.join(mylist)把这个列表里的每一个字符串连接起来形成一个大的字符串#done message = list(message) random.shuffle(message) message = ''.join(message) # convert list to string #字符串的切片操作是字符串的拷贝message[:50] 不改变原massage print('Test #%s: "%s..."' % (i+1, message[:50])) # Check all possible keys for each message. for key in range(1, len(message)): encrypted = transpositionEncrypt.encryptMessage(key, message) decrypted = transpositionDecrypt.decryptMessage(key, encrypted) # If the decryption doesn't match the original message, display # an error message and quit. if message != decrypted: print('Mismatch with key %s and message %s.' % (key, message)) print(decrypted) # 这里的sys.exit()是让整个程序提前退出,立刻中止 sys.exit() print('Transposition cipher test passed.') # If transpositionTest.py is run (instead of imported as a module) call # the main() function. if __name__ == '__main__': main()
输出:
Test #1: "JEQLDFKJZWALCOYACUPLTRRMLWHOBXQNEAWSLGWAGQQSRSIUIQ..."
Test #2: "SWRCLUCRDOMLWZKOMAGVOTXUVVEPIOJMSBEQRQOFRGCCKENINV..."
Test #3: "BIZBPZUIWDUFXAPJTHCMDWEGHYOWKWWWSJYKDQVSFWCJNCOZZA..."
Test #4: "JEWBCEXVZAILLCHDZJCUTXASSZZRKRPMYGTGHBXPQPBEBVCODM..."
Test #5: "DMMEDKAHCZJDBNCCCZNENAOSJUKGHGUANOCHFGSEVDOMYHVBRK..."
Test #6: "WPOWKFRGLWZFRPXYPDUQADOXPGEABHKNMDLYTITYOBEATVLAIB..."
Test #7: "KVNJOCYPGIUNVLPRZFFAESDUTZRMDKRSSAWQIWXWCPGWUISLHP..."
Test #9: "PVHJOFQJRGXYXFFRRJZTQXRFLWVHPQSHNYOZRJSKJFNRIGQYCH..."
Test #10: "CFWPWYEKXSREXTZZLITJIXIXESHFJCSPLVZQTMWBRTSYBEDCHK..."
Test #11: "QNUZXADCRFYBODYWYJZTPFMGYNWNKGYUBCJXHSSPIIWYYRXCXK..."
Test #12: "DZSEKFURFHNLMFRITPTNQWEVVJVDSBOUUFKXZJNRXHANWCBEYX..."
Test #13: "FXCAYLCKJIACMGATEPYLHAHVSMTHIHDHNBBNFWVXURLVADSGDB..."
Test #15: "WHXYUOUIJQLVDKKSZBTPYOHHGAJFUGILNMQAWTMUOICNFIOJXO..."
Test #16: "GMZMPQAMZDMWCMDMCLUOSWDRJZBVPKYGZDXCWOUVIQLLECWSMU..."
Test #17: "KPKHHLPUWPSSIOULGKVEFHZOKBFHXUKVSEOWOENOZSNIDELAWR..."
Test #18: "OYLFXXZENDFGSXTEAHGHPBNORCFEPBMITILSSJRGDVMNSOMURV..."
Test #19: "SOCLYBRVDPLNVJKAFDGHCQMXIOPEJSXEAAXNWCCYAGZGLZGZHK..."
Test #20: "JXJGRBCKZXPUIEXOJUNZEYYSEAEGVOJWIRTSSGPUWPNZUBQNDA..."
Transposition cipher test passed.