transpositionEncrypt and decrypt

换位加密算法


打乱明文的顺序的一种方法:

  列数即作为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)
 h  e  (s)  j  i  (S)  l
 e  (s)  b  i  a  o  (s)
 h (s)  (s) 
 z (s)  (s) 
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.

原文地址:https://www.cnblogs.com/PiaYie/p/13469532.html