破解替代加密法

思路

首先必须先找出字典文件里的每个单词的模式,把它们放置在一个列表里排序好,以便获取匹配特定密词的单词模式的所有候选单词。
计算字典文件里的每个单词的单词模式,保存到另一个文件里,及 wordPatterns.py文件。
计算单词模式的代码是 makeWordPatterns.py

理论步骤

1.找出密文里的每个密词的单词模式
2.找出每个密词可以解密成哪些英文单词
3.使用密词的候选单词列表为每个密词创建一个密字映射
4.计算所有密字映射的交集,得到一个交集密字映射
5.从交集密字映射移除任何已经破译的字母

密文消息越长,越可能破译

makeWordPatterns.py

import pprint

def getWordPattern(word):
    # 计算单词模式
    # 例如 输入'DUSTBUSTER' 返回'0.1.2.3.4.1.2.3.5.6'  
    word = word.upper()
    nextNum = 0
    letterNums = {}
    wordPattern = []

    for letter in word:
        # 处理单个字符, 如果字符已经存在则用对应的值,否则值往上叠加
        if letter not in letterNums:
            letterNums[letter] = str(nextNum)
            nextNum += 1
        wordPattern.append(letterNums[letter])
    return '.'.join(wordPattern)


def main():
    allPatterns = {}

    fo = open('dictionary.txt')
    wordList = fo.read().split('\n')
    fo.close()

    for word in wordList:
       
        pattern = getWordPattern(word)
        # 将所有同一个模式的单词归类在一起
        if pattern not in allPatterns:
            allPatterns[pattern] = [word]
        else:
            allPatterns[pattern].append(word)

    fo = open('wordPatterns.py', 'w')
    fo.write('allPatterns = ')
    fo.write(pprint.pformat(allPatterns))
    fo.close()


if __name__ == '__main__':
    main()

破解实例

import os, re, copy, pprint, simpleSubCipher, makeWordPatterns

if not os.path.exists('wordPatterns.py'):
    makeWordPatterns.main() # 如果目录下没有wordPatterns.py文件则调用创建
import wordPatterns

LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
nonLettersOrSpacePattern = re.compile('[^A-Z\s]') # 正则匹配任何不适A到Z的字母也不是空白字符的字符


def getBlankCipherletterMapping():
    # 返回密字映射字典,值是单个大写字母字符串的列表
    return {'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': []}


def addLettersToMapping(letterMapping, cipherword, candidate):
    # 将每个单词拆分成单个字符添加到映射字典里
    letterMapping = copy.deepcopy(letterMapping) # 深度复制 防止误操作数据 创建一个临时映射字典
    for i in range(len(cipherword)):
        # 将每个单词对应的映射字符放到一个临时的映射字典里
        if candidate[i] not in letterMapping[cipherword[i]]:
            letterMapping[cipherword[i]].append(candidate[i])
    return letterMapping


def intersectMappings(mapA, mapB):
    # 将临时映射字典汇总到最终的映射字典里
    intersectedMapping = getBlankCipherletterMapping()
    for letter in LETTERS:
        # 如果总字典是空,则直接复制当前字典;如果临时字典是空,则总字典复制其本身;
        if mapA[letter] == []:
            intersectedMapping[letter] = copy.deepcopy(mapB[letter])
        elif mapB[letter] == []:
            intersectedMapping[letter] = copy.deepcopy(mapA[letter])
        else:
            # 如果都不为空,则将临时字典里的数据添加到总字典里
            for mappedLetter in mapA[letter]:
                if mappedLetter in mapB[letter]:
                    intersectedMapping[letter].append(mappedLetter)
    return intersectedMapping


def removeSolvedLettersFromMapping(letterMapping):
    # 剔除映射字典里已经破译的数据
    letterMapping = copy.deepcopy(letterMapping)
    loopAgain = True
    while loopAgain:
        # 由于剔除需要循环剔除,如果没有剔除完全则会继续循环,先关闭下面判断再进行开启
        loopAgain = False
        # 已经破解出的字符放入到solvedletters里面
        solvedLetters = []
        for cipherletter in LETTERS:
            if len(letterMapping[cipherletter]) == 1:
                # 已经是当个对应的字符则是已破译
                solvedLetters.append(letterMapping[cipherletter][0])
        # 判断,如果映射字典里的值不是一个,并且已破译也在当中,则将映射字典值剔除此破译字符
        for cipherletter in LETTERS:
            for s in solvedLetters:
                if len(letterMapping[cipherletter]) != 1 and s in letterMapping[cipherletter]:
                    letterMapping[cipherletter].remove(s)
                    if len(letterMapping[cipherletter]) == 1:
                        # 如果当前值已经等于1个则进行剔除这个破译字符
                        loopAgain = True
    return letterMapping


def hackSimpleSub(message):
    intersectedMap = getBlankCipherletterMapping()
    cipherwordList = nonLettersOrSpacePattern.sub('', message.upper()).split()
    for cipherword in cipherwordList:
        # 对密文列表进行处理,计算单词模式,获取对应模式的单词
        newMap = getBlankCipherletterMapping()
        wordPattern = makeWordPatterns.getWordPattern(cipherword)
        if wordPattern not in wordPatterns.allPatterns:
            continue # 如果计算出的模式在单词里没有找到则下一组密文
        # 如果找到对应的单词,将其拆分添加到映射字典里
        for candidate in wordPatterns.allPatterns[wordPattern]:
            newMap = addLettersToMapping(newMap, cipherword, candidate)
        # 将所有临时映射字典汇总到总的映射字典里
        intersectedMap = intersectMappings(intersectedMap, newMap)

    # 剔除已经破译的映射字符
    return removeSolvedLettersFromMapping(intersectedMap)


def decryptWithCipherletterMapping(ciphertext, letterMapping):
    # 用已解得的密字映射字典翻译密文
    key = ['x'] * len(LETTERS) 
    for cipherletter in LETTERS:
        if len(letterMapping[cipherletter]) == 1:
            # 如果映射字典的值是一个,那么就加入到密钥中
            keyIndex = LETTERS.find(letterMapping[cipherletter][0])
            key[keyIndex] = cipherletter
        else:
            # 如果映射值不只一个或没有,那么算是未破解,用下划线代替加入到密钥中
            ciphertext = ciphertext.replace(cipherletter.lower(), '_')
            ciphertext = ciphertext.replace(cipherletter.upper(), '_')
    key = ''.join(key)
    # 调用简单替代法解密方法来翻译密文
    return simpleSubCipher.decryptMessage(key, ciphertext)

def main():
    message = 'Sy l nlx sr pyyacao l ylwj eiswi upar lulsxrj isr sxrjsxwjr, ia esmm rwctjsxsza sj wmpramh, lxo txmarr jia aqsoaxwa sr pqaceiamnsxu, ia esmm caytra jp famsaqa sj. Sy, px jia pjiac ilxo, ia sr pyyacao rpnajisxu eiswi lyypcor l calrpx ypc lwjsxu sx lwwpcolxwa jp isr sxrjsxwjr, ia esmm lwwabj sj aqax px jia rmsuijarj aqsoaxwa. Jia pcsusx py nhjir sr agbmlsxao sx jisr elh. -Facjclxo Ctrramm'
    print('Hacking...')
    # 解密映射字典
    letterMapping = hackSimpleSub(message)
    print('Mapping:')
    # 输出映射字典
    pprint.pprint(letterMapping)
    print()
    print('Original ciphertext:')
    print(message)
    print()
    # 翻译密文成明文
    hackedMessage = decryptWithCipherletterMapping(message, letterMapping)
    print(hackedMessage)



if __name__ == '__main__':
    main()

运行结果

运行结果

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章