python3实现Vigenere加密、解密、破解

  • 2018-06-14
  • 230
  • 0
  • 0
# coding:utf-8
import math

def encryptionVirginia(plaintext, secret_key):
    '''加密'''
    table = [chr(x) for x in range(ord('a'), ord('z') + 1)]
    tmp = ''
    for x in plaintext:
        if x.lower() in table:
            tmp += x.lower()
    ciphertext = ''

    for index, value in enumerate(tmp):
        t = (table.index(value) + table.index(secret_key[index % len(secret_key)])) % 26
        ciphertext += table[t]
    return ciphertext


def decryptionVirginia(ciphertext, secret_key):
    '''解密'''
    ciphertext = ciphertext.lower()
    table = [chr(x) for x in range(ord('a'), ord('z') + 1)]

    plaintext = ''
    num = 0
    for index, value in enumerate(ciphertext):
        plaintext += table[(table.index(value) - table.index(secret_key[index % len(secret_key)])) % 26]
        num += 1
    return plaintext

class CrackVirginia:
    '''破解'''
    # 字母概率,从a到z
    LETTER_PROBILITY = {
        'a':0.08167, # a
        'b':0.01492, # b
        'c':0.02782, # c
        'd':0.04253, # d
        'e':0.12702, # e
        'f':0.02228, # f
        'g':0.02015, # g
        'h':0.06094, # h
        'i':0.06966, # i
        'j':0.00153, # j
        'k':0.00772, # k
        'l':0.04025, # l
        'm':0.02406, # m
        'n':0.06749, # n
        'o':0.07507, # o
        'p':0.01929, # p
        'q':0.00095, # q
        'r':0.05897, # r
        's':0.06327, # s
        't':0.09056, # t
        'u':0.02758, # u
        'v':0.00978, # v
        'w':0.02360, # w
        'x':0.00150, # x
        'y':0.01974, # y
        'z':0.00074, # z
    }
    def __getSubstring(self, key_length):
        '''分割为子串'''
        num = 0
        while num < key_length:
            yield self.ciphertext[num::key_length].upper()
            num += 1

    def __fangcha(self, average, li):
        '''方差计算'''
        tmp = 0
        for x in li:
            tmp += (x - average) ** 2
        return tmp / len(li)

    def __init__(self, ciphertext):
        self.ciphertext = ciphertext.upper()

    def __IC_calculate(self, string_str):
        '''无偏估计值计算'''
        dict_ = {}
        for x in string_str:
            try:
                dict_[x] += 1
            except KeyError:
                dict_[x] = 1
        tmp = 0
        for value in dict_.values():
            try:
                tmp += ((value * (value-1)) / (len(string_str) * (len(string_str) - 1)))
            except ZeroDivisionError:
                return 1
        return tmp

    def __calculate_Mj(self, text):
        '''拟重合指数法'''
        Mj = 0
        alpha = {}
        for x in text:
            try:
                alpha[x] += 1
            except KeyError:
                alpha[x] = 1
        for key, value in alpha.items():
            Mj += ((self.LETTER_PROBILITY[key.lower()] * value) / len(text))
        return Mj

    def __getKeyLength(self):
        '''破解密钥长度'''
        key_length_ic = {}
        key_length_fangcha = {}
        key_length = 1
        result = {}
        while key_length < len(self.ciphertext):
            substring = []
            for x in self.__getSubstring(key_length):
                substring.append(x)
            key_length += 1
            tmp = []
            for x in substring:
                ic = self.__IC_calculate(x)
                tmp.append(ic)
            if tmp:
                key_length_ic[str(key_length-1)] = math.fabs(sum(tmp) / len(tmp) - 0.065)
                key_length_fangcha[str(key_length-1)] = self.__fangcha(key_length_ic[str(key_length-1)], tmp)
        for key, value in key_length_ic.items():
            result[key] = key_length_fangcha[key] * 4 + value
        key_length = sorted(result.items(), key=lambda a:a[1])[0][0]
        return int(key_length)

    def crack(self):
        '''破解'''
        key_length = self.__getKeyLength()
        num = 0
        key_ic = []
        for x in self.__getSubstring(key_length):
            for t in range(1, 27):
                s = ''.join([chr(((ord(l)+t-65) % 26) + 65) for l in x])
                try:
                    key_ic[num].append(math.fabs(self.__calculate_Mj(s) - 0.065))
                except IndexError:
                    key_ic.append([math.fabs(self.__calculate_Mj(s) - 0.065)])
            num += 1
        key = ''
        for value in key_ic:
            key += chr(ord('z') - value.index(min(value)))
        return key

string = 'CHREEVOAHMAERATBIAXXWTNXBEEOPHBSBQMQEQERBWRVXUOAKXAOSXXWEAHBWGJMMQMNKGRFVGXWTRZXWIAKLXFPSKAUTEMNDCMGTSXMXBTUIADNGMGPSRELXNJELXVRVPRTULHDNQWTWDTYGBPHXTFALJHASVBFXNGLLCHRZBWELEKMSJIKNBHWRJGNMGJSGLXFEYPHAGNRBIEQJTAMRVLCRREMNDGLXRRIMGNSNRWCHRQHAEYEVTAQEBBIPEEWEVKAKOEWADREMXMTBHHCHRTKDNVRZCHRCLQOHPWQAIIWXNRMGWOIIFKEE'
a = CrackVirginia(string)
key = a.crack()
plaintext = decryptionVirginia(string, a.crack())
print('明文为:', plaintext, end='\n\n')
print('加密密钥:', key, end='\n\n')
print('加密后:', string, end='\n\n')
print('破解密钥:', key, end='\n\n')
print('破解明文:', plaintext, end='\n\n')

评论

还没有任何评论,你来说两句吧

发表评论