Python 仿射密码破解

最近在学信息安全技术这门课,老师布置了一个课程作业,作业大概如下:


已知一段仿射密码加密的密文(空格标点等没有加密):

Pu yfo of oin hvy ufa hrpkpyb, jlar ph hopkk py oin hvy oinan, svo jnjpkk klvbi rfan zfyupgnyo zlkr; pu ovayng of ufvyg iph fjy hilgfj, lmmafmaplon nhzlmn, oin hvy jpkk sn oiafvbi oin inlao,jlar nlzi mklzn snipyg oin zfayna; pu ly fvohoanozing mlkr zlyyfo ulkk svoonaukx, oiny zknyzing jlcpyb larh, bpcny mfjna; pu P zly'o ilcn sapbio hrpkn, po jpkk ulzn of oin hvyhipyn, lyg hvyhipyn hrpkn ofbnoina, py uvkk skffr.

试根据所学知识,对其进行破解。


看到题目,当然没有懵啦,因为上课是认真听了滴(呵呵)。马上将老师PPT找出来看,研究了一下午,终于完成了。

破解思路

人们在用英语表示信息时,字母的出现是有规律的。美国密码学家W.F.Friedman在调查了大量英文资料后,得出英文字母的普遍使用规律。


Python 仿射密码破解_第1张图片
字母规律

我们可以根据这个规律来破解仿射密码。我们先统计出密文的字母出现频率:

{'a': 18, 'c': 3, 'b': 7, 'g': 8, 'f': 19, 'i': 23, 'h': 17, 'k': 22, 'j': 10, 'm': 7, 'l': 21, 'o': 30, 'n': 37, 'p': 26, 's': 6, 'r': 10, 'u': 11, 'v': 13, 'y': 27, 'x': 1, 'z': 12}
['n', 'o', 'y', 'p', 'i', 'k', 'l', 'f', 'a', 'h', 'v', 'z', 'u', 'r', 'j', 'g', 'm', 'b', 's', 'c', 'x']

由上表可以看到字母n出现次数最多:37次,其次是字母o出现次数30。根据规律呢,字母n是字母e加密后的可能性很大,字母o是字母t加密后的可能性很大,我们根据这个规律算出k1,k2。具体加解密方式看各种百科。(C= Ek(m)=(k1m+k2) mod n)
如果 gcd(k1,26)等于1,那么表示当前假设下,k1,k2是一个合法的密钥。此时,只是可用的密钥。
需要根据k1,k2解出明文,如果刚好明文表示是有意义,那么破解就成功了。

破解过程

其实就是Python代码,因为写起方便

# coding:utf8

# 密文
Cs = r"Pu yfo of oin hvy ufa hrpkpyb, jlar ph hopkk py oin hvy oinan, svo jnjpkk klvbi rfan zfyupgnyo zlkr; pu ovayng of ufvyg iph fjy hilgfj, lmmafmaplon nhzlmn, oin hvy jpkk sn oiafvbi oin inlao,jlar nlzi mklzn snipyg oin zfayna; pu ly fvohoanozing mlkr zlyyfo ulkk svoonaukx, oiny zknyzing jlcpyb larh, bpcny mfjna; pu P zly'o ilcn sapbio hrpkn, po jpkk ulzn of oin hvyhipyn, lyg hvyhipyn hrpkn ofbnoina, py uvkk skffr."

charTable = [ chr(c) for c in range(97,123)]
frequencyTable = [4, 19, 14, 0, 13, 8, 17, 18, 7, 3, 11, 2, 20, 12, 15, 24, 22, 6, 1, 21, 10, 23, 9, 16, 25]

# 删除预留的标点
def del_point(c):
    if c in [' ', ',', '.', ';', '\'', '?', '!']:
        return False
    return True

def get_int_by_char(c):
    return charTable.index(c)

def get_char_by_int(i):
    return charTable[i]    

# 最大公约数
def gcd(a, b):
    if a < b:
        a, b = b, a
    while b != 0:
        temp = a % b
        a = b
        b = temp
    return a

# 排序
def sort_by_value(d):
    items = d.items()
    backitems = [ [v[1],v[0]] for v in items ]
    backitems = sorted(backitems, reverse = True)
    return [ backitems[i][1] for i in range(0,len(backitems))]

# 获取k3
def get_k3(k1, k2):
    for k3 in range(0,26):
        if k3 * k1 % 26 == 1:
            return k3

# 判断一个数是否是整数
def is_int(n):
    int_n = int(n)
    return n * n == int_n * int_n

# 仿射解密过程
def FsJM(c, k1, k2):
    k3 = get_k3(k1, k2)
    Ms = ""
    for x in c:
        Ms = Ms + get_char_by_int( k3 * (get_int_by_char(x) - k2) % 26 )
    return Ms

# 根据a,b,c,d获取密钥K1
def get_k1(a, b, c, d):
    i = 0
    while True:
        k1 = ( float(a - d - 26 * i) / float(b - c) )
        if k1 < -26 or k1 > 26:
            return None
        if is_int(k1):
            return int(k1)
        i = i + 1

Cs = filter( del_point, Cs.lower() )
count = {}

for v in Cs:
    count[v] = count[v] + 1 if count.has_key(v) else 1

sortCs = map(get_int_by_char,sort_by_value(count))

# 精度
prec = 4
result = []
for a in sortCs[0:len(sortCs)/prec]:
    for b in frequencyTable[0:len(frequencyTable)/prec]:
        for c in frequencyTable[frequencyTable.index(b) + 1:len(frequencyTable)/prec]:
            for d in sortCs[sortCs.index(a)+1:len(sortCs)/prec]:
                k1 = get_k1(a, b, c, d)
                if k1 is None or gcd(k1, 26) != 1:
                    break
                k2 = int(d - c * k1) % 26
                result.append( (k1, k2, FsJM(Cs, k1, k2)) )

for val in result:
    print val

最后输出:

(7, 11, 'ifnottothesunforsmilingwarmisstillinthesuntherebutwewilllaughmoreconfidentcalmifturnedtofoundhisownshadowappropriateescapethesunwillbethroughtheheartwarmeachplacebehindthecornerifanoutstretchedpalmcannotfallbutterflythenclenchedwavingarmsgivenpowerificanthavebrightsmileitwillfacetothesunshineandsunshinesmiletogetherinfullbloom')
(25, 17, 'cxtmddmdjekwtxmrkachctqigrackkdchhctdjekwtdjerezwdieichhhgwqjamresmtxcletdsghacxdwrteldmxmwtljckmitkjglmigffrmfrcgdeeksgfedjekwtichhzedjrmwqjdjejegrdigraegsjfhgsezejctldjesmrtercxgtmwdkdredsjelfghasgttmdxghhzwdderxhudjetshetsjeligpctqgrakqcpetfmiercxcsgtdjgpezrcqjdkachecdichhxgsedmdjekwtkjctegtlkwtkjctekachedmqedjerctxwhhzhmma')
(3, 1, 'wpzknnknlecyzpkrcowdwzaumrowccnwddwznlecyznlerexynueuwdddmyalokreikzpwteznimdowpnyrzetnkpkyztlwckuzclmtkumvvrkvrwmneecimvenlecyzuwddxenlrkyalnlelemrnumroemilvdmiexelwztnleikrzerwpmzkyncnreniletvmdoimzzknpmddxynnerpdqnlezideziletumjwzamrocawjezvkuerwpwimznlmjexrwalncowdewnuwddpmienknlecyzclwzemztcyzclwzecowdenkaenlerwzpyddxdkko')
(7, 11, 'ifnottothesunforsmilingwarmisstillinthesuntherebutwewilllaughmoreconfidentcalmifturnedtofoundhisownshadowappropriateescapethesunwillbethroughtheheartwarmeachplacebehindthecornerifanoutstretchedpalmcannotfallbutterflythenclenchedwavingarmsgivenpowerificanthavebrightsmileitwillfacetothesunshineandsunshinesmiletogetherinfullbloom')
(9, 4, 'hwideedembjziwdojnhshirpvonhjjehsshiembjziembobqzepbphsssvzrmndobldiwhgbielvsnhwezoibgedwdzigmhjdpijmvgdpvyyodyohvebbjlvybembjziphssqbemodzrmembmbvoepvonbvlmysvlbqbmhigembldoibohwvidzejeobelmbgyvsnlviidewvssqzeebowsfembilsbilmbgpvuhirvonjrhubiydpbohwhlviemvubqohrmejnhsbhephsswvlbedembjzijmhibvigjzijmhibjnhsbedrbembohiwzssqsddn')
(11, 14, 'tkilaalaqhxdikluxftctinjvuftxxatcctiaqhxdiaqhuhydajhjtcccvdnqfluhbliktehiabvcftkaduihealkldieqtxljixqveljvoouloutvahhxbvohaqhxdijtccyhaquldnqaqhqhvuajvufhvbqocvbhyhqtieaqhbluihutkvildaxauhabqheovcfbviilakvccydaahukcpaqhibchibqhejvgtinvufxntghioljhutktbviaqvghyutnqaxftchtajtcckvbhalaqhxdixqtihviexdixqtihxftchalnhaqhutikdccycllf')
(15, 16, 'tcebmmbmwfpjecbsphtktezdrshtppmtkktemwfpjemwfsfojmdfdtkkkrjzwhbsflbectifemlrkhtcmjsefimbcbjeiwtpbdepwribdryysbystrmffplryfmwfpjedtkkofmwsbjzwmwfwfrsmdrshfrlwykrlfofwteimwflbsefstcrebjmpmsfmlwfiyrkhlreebmcrkkojmmfsckxmwfelkfelwfidrgtezrshpztgfeybdfstctlremwrgfostzwmphtkftmdtkkcrlfmbmwfpjepwtefreipjepwtefphtkfmbzfmwfstecjkkokbbh')
(9, 2, 'ncojkkjkshpfocjuptnynoxvbutnppknyynokshpfokshuhwfkvhvnyyybfxstjuhrjocnmhokrbytnckfuohmkjcjfomsnpjvopsbmjvbeeujeunbkhhprbehkshpfovnyywhksujfxskshshbukvbuthbrseybrhwhsnomkshrjuohuncbojfkpkuhkrshmebytrboojkcbyywfkkhucylkshoryhorshmvbanoxbutpxnahoejvhuncnrboksbahwunxskptnyhnkvnyycbrhkjkshpfopsnohbompfopsnohptnyhkjxhkshunocfyywyjjt')
(3, 3, 'exhsvvsvtmkghxszkwelehicuzwekkvellehvtmkghvtmzmfgvcmcelllugitwszmqshxebmhvqulwexvgzhmbvsxsghbtekschktubscuddzsdzeuvmmkqudmvtmkghcellfmvtzsgitvtmtmuzvcuzwmuqtdluqmfmtehbvtmqszhmzexuhsgvkvzmvqtmbdulwquhhsvxullfgvvmzxlyvtmhqlmhqtmbcurehiuzwkiermhdscmzexequhvturmfzeitvkwelmevcellxuqmvsvtmkghktehmuhbkghktehmkwelmvsimvtmzehxgllflssw')
(5, 21, 'eflcjjcjnosalfcbsuedelwiybuessjeddeljnosaljnobopajioiedddyawnucbogclfexoljgyduefjabloxjcfcalxnescilsnyxciyttbctbeyjoosgytojnosalieddpojnbcawnjnonoybjiybuoygntdygoponelxjnogcblobefylcajsjbojgnoxtydugyllcjfyddpajjobfdqjnolgdolgnoxiyrelwybusweroltciobefegyljnyropbewnjsuedoejieddfygojcjnosalsneloylxsalsnelosuedojcwojnobelfaddpdccu')
(7, 21, 'oltuzzuznkyatluxysorotmcgxsoyyzorrotznkyatznkxkhazckcorrrgamnsuxkiutlojktzigrsolzaxtkjzuluatjnoyuctyngjucgvvxuvxogzkkyigvkznkyatcorrhkznxuamnznknkgxzcgxskginvrgikhknotjznkiuxtkxolgtuazyzxkzinkjvgrsigttuzlgrrhazzkxlreznktirktinkjcgbotmgxsymobktvuckxoloigtzngbkhxomnzysorkozcorrlgikzuznkyatynotkgtjyatynotkysorkzumkznkxotlarrhruus')

可以看到:

(7, 11, 'ifnottothesunforsmilingwarmisstillinthesuntherebutwewilllaughmoreconfidentcalmifturnedtofoundhisownshadowappropriateescapethesunwillbethroughtheheartwarmeachplacebehindthecornerifanoutstretchedpalmcannotfallbutterflythenclenchedwavingarmsgivenpowerificanthavebrightsmileitwillfacetothesunshineandsunshinesmiletogetherinfullbloom')

这段字符有意义,所以应该是原文。

翻译原文

翻译过来就是(网上找的):

如果不向太阳索取微笑,温暖仍在太阳那里,但我们会笑得更加自信从容;如果转过身去发现了自己的影子,适当的躲让,阳光便可穿越心灵,温暖每一处身后的角落;如果摊开的掌心不能点落蝴蝶,那就紧握成拳挥动臂膀,给予力量;如果我不能够微笑得灿烂,那就将脸投向灿烂的阳光,与阳光一起微笑,烂漫.

还是一段温暖的句子呢!

你可能感兴趣的:(Python 仿射密码破解)