类维吉尼亚密码分析自动化脚本

详见CTF_Crypto-all-in-one/tools.py at main · DuanYuFi/CTF_Crypto-all-in-one (github.com)中solve_classical函数,其可以自动化分析类似维吉尼亚密码加密算法的密钥,从而解出明文。成功率不保证100%,但是非常高。其相对于网上现有工具的优点是可以对密文包含不可见字符的算法进行解密,并且易于扩展。

使用方法如下:

函数参数介绍:

text,即bytes类型的古典加密后密文

decode_function,即正常情况下该古典算法的解密函数,需要其满足形式为:def decode_function(cipher, key),返回值为通过key解密的明文,类型都是bytes

min_lengthmax_length: 密钥长度区间

key_char: 密钥可能包含的字符,bytearray类型

使用案例:

例如上周的某个比赛,其加密采用的是类似维吉尼亚密码,不过其字符集不是小写字母而是全体单字节,加法采用异或加,因此网上常见的脚本不方便进行破解。然而使用这里的脚本,再进行一些微调,就能够完成该攻击。

exp如下

# -*- coding: utf-8 -*-

import string

IC = 0.065
charset = string.ascii_letters
charset = charset.encode()
naturalLanguageP = [0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015, 0.06094, 0.06966, 0.00153, 0.00772, 0.04025, 0.02406, 0.06749, 0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09056,0.02758, 0.00978, 0.02360, 0.00150, 0.01974, 0.00074]
cc2 = b'*\x11^XD]\x17QPQ\x14T\x1b\x17\x0c\x0cG\x0bCQL\r\tW\x18BV\x16\x16\rQACFYK^\\\x10J\x11SQJ\x16^\x13\x03]N\x17QV\x00FMPCJ\x16\x0f\x1c\x18^\nWS\x19ZYD\x19SPQWBU\t\x07B\x11RT\x16Dl|YDUOB\x0cV\x12\x17YS\x19VYN\x19XA\x14N\x03DE\x15Y\x0bD@]\x16\x03]\x18BQW\x16EOWCB^VGTS\x19BT]UB^\x0bBPBU_Y\x10J\x19WXUOB\x11P]\x16\x11WWV\x18~\x15\x11TZ]BY\x00\x14T\x10\x17Q\x18\x17\tLT\x16PXB\x11PWCFYK^\\\x17N^@X]B\\\x0b\rFBXV\x18\x10\x0ePK\x16VC\x10EH[\x0fVDP_YP\\\x11A[\x19\x0cXE\x01^\x17YDJ\x1dFXVR\x19B\rEV]CTX]\x1c2~W\x11A\\\\BZ\x00\x03_\x15_YT\x01Fp\x18ET_\x0e\x00\x18S\rU\x16p\x12K^WV\x15UU\x0e\x17\x04\x0e^\x0cR\x1e\x18-\x08\x19L^\\\x16\x0f\x00Y\\\x14Y_UW\x18CQT\x15UP\x10\x17\x0c\x11\x11\x04^\\T\r\x08^\x18APB\nELZ\x06\x11F\\@^BTT\x15[_BG\x17\r\\\x0bDU\x16n2Q]\x16M_\x0f\x00\x18F\x0bPB\x19_A\x17S^@FW\x07NE\x16P\tRC\x18\r\x15\x19TYWQB\x04VVCE^\\\x12OV@\x11ZR\x19\x0bCE\x0e^\x0cP\x1eqD\x05XUS\x19Y\x17\x11\x18]\r\x11BQW\x18TQPG]V\x16\x17\n\x04\x11\x16_U\x18\x02\x0fKKB\x19Q\x0e\x00Y_C^P\x19^QPQE\x19\x14X\x0cSE\x12D\x10DE]\x00FTA\x16OY\x1b\x04_WCE^K]MPQ\x11A\\\\B@\x0c\x0eU\x07E^]\x17\x15\\K\x16VPB\x12W@\x0fUE\x19^]VOX[S\x19\x0fNE\x16C\x03T[\x18\x0b\x08\x19UWWOB\x04\x18A\x17PD\x19SVS\x19AYUW\x07CK'

def count_p(text, charset):
    count = {}
    for each in text:
        if each not in count:
            count[each] = 1
        else:
            count[each] += 1
    return count

def get_ic(text):
    count = count_p(text)
    length = len(text)
    ic = 0
    for each in count:
        ic = ic + (count[each] - 1) * count[each]

    return ic / (length * (length - 1))

def split_text(text, length):
    strings = []
    len_text = len(text)
    for i in range(length):
        this = []
        for j in range(i, len_text, length):
            this.append(text[j])
        strings.append(bytes(this))

    return strings


def break_key(text, length, decode_function, key_char, charset = (string.ascii_lowercase).encode()):
    strings = split_text(text, length)
    key = []
    for i in range(length):
        maxx = 0
        this_char = ''
        for each_char in key_char:
            plain_text = decode_function(strings[i], each_char)
            count = count_p(plain_text, charset)
            total = len(plain_text)
            this_p = []
            for each in charset:
                if each not in count:
                    this_p.append(0)
                else:
                    this_p.append(count[each] / total)

            tmp = 0
            for j in range(26):
                tmp += this_p[j] * naturalLanguageP[j]
            if tmp > maxx:
                (maxx, this_char) = (tmp, each_char)

        key.append(this_char)
    return bytes(key)

def f(a, b):
    ret = []
    for each in a:
        ret.append(each ^ b)
    return bytes(ret)

key = break_key(cc2, 32, f, (string.ascii_letters + string.digits).encode())
print(key)

import itertools
key = itertools.cycle(key)
print(bytes([next(key) ^ each for each in cc2]).decode())

然后根据明文的语法微调一下key就能解出

发表评论

您的电子邮箱地址不会被公开。 必填项已用 * 标注