• affineCipher and afineHacker


    乘数加密法

    在讲仿射加密法之前,我们先说乘数加密法

    凯撒加密法中,加密和解密符号涉及把他们转化成数字,加上或者减去密钥,再把新的数字换成符号

    如果我们不使用加而用乘法,可以吗?当然,只需要用mod运算把一个大的整数唯一映射到一个字符

    就好了

    乘数加密法的优势是,可以使用一个很大的key, 而不局限于凯撒加密法的密钥空间    0~25

    缺点是A总是映射到A,为了克服这种缺点,我们再使用一次凯撒加密法即可

    缺点是并不是所有key都能使用

    比如若选择key=8,则有

    A B C D E F G H I J K L M
    A I Q Y G O W E M U C K S
                             
    N O P Q R S T U V W X Y Z
    A I Q Y G O W E M U C K S

    这甚至不是一一映射!!没有用

    仿射加密法

    乘数加密法+凯撒加密法 = 仿射加密法

     keyA应当满足一定条件:

      密钥A数字和符号集的大小必须互质,也就是说gcd(密钥A, 符号集大小) = 1

    模算术运算   加法and乘法

    模b运算中,整数x的乘法逆元是y:使得(x × y)mod b = 1 

    模b运算中,整数x的加法逆元是y:使得(x + y)mod b = 0 

    一般来说,只有当一个整数与n互素的时候,他才会在Zn中存在一个乘法逆元

    使用扩展欧几里得算法可以方便地找到一个数字的模逆,python实现:

    def findModInverse(a, m):
        # Returns the modular inverse of a % m, which is
        # the number x such that a*x % m = 1
        # 如果a 和 m 不互质,则不存在模逆
        if gcd(a, m) != 1:
            return None # no mod inverse if a & m aren't relatively prime
    
        # Calculate using the Extended Euclidean Algorithm:
        u1, u2, u3 = 1, 0, a
        v1, v2, v3 = 0, 1, m
        while v3 != 0:
            q = u3 // v3 # // is the integer division operator
            v1, v2, v3, u1, u2, u3 = (u1 - q * v1), (u2 - q * v2), (u3 - q * v3), v1, v2, v3
        return u1 % m

    输出:

    >>> import cryptomath
    
    >>> cryptomath.findModInverse(7, 26) 
    15
    >>> cryptomath.findModInverse(37, 41) 
    10
    >>> cryptomath.findModInverse(8953851, 26)  
    17
    >>>

    前面是开胃菜,接下来要展示点真正下饭的东西了!

    仿射加密法

     我们要使用两个密钥,记住一个数是方便地。使用简单的数学技巧将一个数分解成两个key

      如使用key = 2023 则:

        keyA = key // len(密文符号集)                                   2023 // 95 = 21

        keyB = key % len(密文符号集)                                  2023 % 95 = 28

        显然 keyA * len(密文符号集) + keyB = key               (21 * 95) + 28 = 2023

    这两个密钥显然不能在程序中出差错,所以用元组保存是可取的。

    元组是python中的一种数据类型。可以通过索引和分片来访问,但是很重要的一点,元组里面的值不能被更改

    对于生成的密钥,我们要确认其可行性:

    • keyA不能为1
    • keyB不能为0
    • keyA、keyB必须大于0,keyB不大于ken(密文符号集) -1
    • 最重要的一点,满足keyA必须与密文符号集的大小互质,才能使得这是一个一一映射。
    仿射加密算法
    # Affine Cipher
    # http://inventwithpython.com/hacking (BSD Licensed)
    '''
    1.The affine cipher can be thought of as the combination of which two other ciphers?
    2.What is a tuple?
    3.How is a tuple different from a list?
    4.Why does having Key A be 1 make the affine cipher weak?
    5.Why does having Key B be 0 make the affine cipher weak?
    
    answer
    
    1.The shift and multiplicative ciphers.
    2.A data type in Python similar to lists, except immutable.
    3.Tuples are immutable, meaning they cannot have their items changed.
    4.Because multiplying the symbol's number by 1 does not change it.
    5.Because adding 0 to the symbol's number does not change it.
    '''
    import sys, pyperclip, cryptomath, random
    SYMBOLS = """ !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~""" # note the space at the front
    
    
    def main():
        myMessage = """"A computer would deserve to be called intelligent if it could deceive a human into believing that it was human." -Alan Turing"""
        myKey = 2023
        myMode = 'encrypt' # set to 'encrypt' or 'decrypt'
    
        if myMode == 'encrypt':
            translated = encryptMessage(myKey, myMessage)
        elif myMode == 'decrypt':
            translated = decryptMessage(myKey, myMessage)
        print('Key: %s' % (myKey))
        print('%sed text:' % (myMode.title()))
        print(translated)
        pyperclip.copy(translated)
        print('Full %sed text copied to clipboard.' % (myMode))
    
    
    def getKeyParts(key):
        keyA = key // len(SYMBOLS)
        keyB = key % len(SYMBOLS)
        return (keyA, keyB)
    
    
    def checkKeys(keyA, keyB, mode):
        if keyA == 1 and mode == 'encrypt':
            sys.exit('The affine cipher becomes incredibly weak when key A is set to 1. Choose a different key.')
        if keyB == 0 and mode == 'encrypt':
            sys.exit('The affine cipher becomes incredibly weak when key B is set to 0. Choose a different key.')
        if keyA < 0 or keyB < 0 or keyB > len(SYMBOLS) - 1:
            sys.exit('Key A must be greater than 0 and Key B must be between 0 and %s.' % (len(SYMBOLS) - 1))
        if cryptomath.gcd(keyA, len(SYMBOLS)) != 1:
            sys.exit('Key A (%s) and the symbol set size (%s) are not relatively prime. Choose a different key.' % (keyA, len(SYMBOLS)))
    
    
    def encryptMessage(key, message):
        keyA, keyB = getKeyParts(key)
        checkKeys(keyA, keyB, 'encrypt')
        ciphertext = ''
        for symbol in message:
            if symbol in SYMBOLS:
                # encrypt this symbol
                symIndex = SYMBOLS.find(symbol)
                # 乘数加密 + 凯撒加密 = 仿射加密方法
                ciphertext += SYMBOLS[(symIndex * keyA + keyB) % len(SYMBOLS)]
            else:
                #如果在符号集中没有这个特殊符号,不能舍弃,保留,保证密文和明文等长
                ciphertext += symbol # just append this symbol unencrypted
        return ciphertext
    
    
    def decryptMessage(key, message):
        keyA, keyB = getKeyParts(key)
        checkKeys(keyA, keyB, 'decrypt')
        plaintext = ''
        #需要找到keyA的乘法模逆
        modInverseOfKeyA = cryptomath.findModInverse(keyA, len(SYMBOLS))
    
        for symbol in message:
            if symbol in SYMBOLS:
                # decrypt this symbol
                symIndex = SYMBOLS.find(symbol)
                plaintext += SYMBOLS[(symIndex - keyB) * modInverseOfKeyA % len(SYMBOLS)]
            else:
                plaintext += symbol # just append this symbol undecrypted
        return plaintext
    
    
    def getRandomKey():
        while True:
            keyA = random.randint(2, len(SYMBOLS))
            keyB = random.randint(2, len(SYMBOLS))
            if cryptomath.gcd(keyA, len(SYMBOLS)) == 1:
                return keyA * len(SYMBOLS) + keyB
    
    
    # If affineCipher.py is run (instead of imported as a module) call
    # the main() function.
    if __name__ == '__main__':
        main()

    输出:

    Key: 2023
    Encrypted text:
    fX<*h>}(rTH<Rh()?<?T]TH=T<rh<tT<*_))T?<ISrT))I~TSr<Ii<Ir<*h()?<?T*TI=T<_<4(>_S<ISrh<tT)IT=IS~<r4_r<Ir<R_]<4(>_SEf<0X)_S<k(HIS~
    Full encrypted text copied to clipboard.
    PS D:PiaYiejczhang密码学py密码学编程教学代码> 

    暴力破译仿射密码

    那么,暴力破译的话,就必须明白仿射加密法有多少个密钥?

    keyB:   “回调”受限:1  ~  len(密文符号集)

    keyA: 与len(密文符号集)互质的数,是否也会出现“回调”的情况?

    SYMBOLS = """ !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~""" # note the space at the front
    len(SYMBOLS) = 95

    测试一下

    # This program proves that the keyspace of the affine cipher is limited
    # to len(SYMBOLS) ^ 2.
    
    import affineCipher, cryptomath
    
    message = 'Make things as simple as possible, but not simpler.'
    for keyA in range(2, 100):
        key = keyA * len(affineCipher.SYMBOLS) + 1
    
        if cryptomath.gcd(keyA, len(affineCipher.SYMBOLS)) == 1:
            print(keyA, affineCipher.encryptMessage(key, message))

    输出:

    n-2020.7.96456pythonFileslibpythondebugpylauncher' '49271' '--' 'd:PiaYiejczhangSJTU密码学py密码学编程教学代码affineKeyTest.py'
    2 {DXL!jRT^Ph!Dh!hTZL!Dh!b`hhTFZL9!Flj!^`j!hTZLf=
    3 I&D2!_;>M8!&!>JSG2!&!SP\>)G2E!)b_!MP_!>JSG2YK
    4 vg0w!T$(< P!gP!P(8D4w!gP!D@PP(k4wQ!kXT!<@T!P(8D4wLY
    6 q+gC!>U[yO8!+8!8[s&mC!+8!& 88[1mCi!1D>!y >!8[s&mC2u
    7 ?lS)!3>Eh7,!l,!,EavZ)!l,!vo,,EsZ)u!s:3!ho3!,EavZ)%$
    8 lN?n!('/W~ !N ! /OgGn!N !g_  /VGn"!V0(!W_(! /OgGnw2
    9 :0+T!|oxFfs!0s!sx=X4T!0s!XOssx94T.!9&|!FO|!sx=X4Tj@
    11 5Sb !fAL$6[!S[![Lx:m !S[!:/[[L^m F!^qf!$/f![Lx:m P
    12 b5Ne![*6r}O!5O!O6f+Ze!5O!+~OO6AZeR!Ag[!r~[!O6f+ZeCj
    13 0v:K!Pr aeC!vC!C T{GK!vC!{nCC $GK^!$]P!anP!C T{GK6x
    14 ]X&1!E[iPM7!X7!7iBl41!X7!l^77if41j!fSE!P^E!7iBl41)'
    16 X{]!/-=.|~!{~!~=}Nm!{~!N>~~=,m#!,?/!.>/!~=}Nm
    C
    17 &]IB!$u'|dr!]r!r'k?ZB!]r!?.rr'nZB/!n5$!|.$!r'k?ZBaQ
    18 S?5(!x^pkLf!?f!fpY0G(!?f!0}ffpQG(;!Q+x!k}x!fpY0G(T_
    21 {DX9!Wx.8cB!DB!B.#bm9!DB!bMBB.Ym9_!YlW!8MW!B.#bm9-*
    22 I&D~!Law'K6!&6!6wpSZ~!&6!S=66w<Z~k!<bL!'=L!6wpSZ~ 8
    23 vg0d!AJau3*!g*!*a^DGd!g*!D-**a~Gdw!~XA!u-A!*a^DGdrF
    24 DI{J!63Kdz}!I}!}KL54J!I}!5|}}Ka4J$!aN6!d|6!}KL54JeT
    26 ?lSu! d~BJe!le!e~(vmu!le!vee~'mu<!': !B !e~(vmuKp
    27 lN?[!tMh12Y!NY!YhugZ[!NY!gLYYhiZ[H!i0t!1Lt!YhugZ[>~
    28 :0+A!i6R yM!0M!MRcXGA!0M!X<MMRLGAT!L&i! <i!MRcXGA1-
    29 gqv'!^~<naA!qA!A<QI4'!qA!I,AA</4'`!/{^!n,^!A<QI4'$;
    31 b5NR!HPoL1)!5)!)o-+mR!5)!+k))oTmRx!TgH!LkH!)o-+mRiW
    32 0v:8!=9Y;x|!v|!|Yz{Z8!v|!{[||Y7Z8%!7]=!;[=!|Yz{Z8e
    33 ]X&}!2"C*`p!Xp!pChlG}!Xp!lKppCyG}1!yS2!*K2!pChlG}Os
    34 +:qc!'j-xHd!:d!d-V]4c!:d!];dd-4c=!I'!x;'!d-V]4cB"
    36 &]I/!p<`VwL!]L!L`2?m/!]L!?zLL`"m/U!"5p!Vzp!L`2?m/(>
    37 S?5t!e%JE_@!?@!@J 0Zt!?@!0j@@JdZta!d+e!Eje!@J 0ZtzL
    39 Nbl@!OV}#/(!b(!(}[q4@!b(!qJ((}*4@y!*vO!#JO!(}[q4@`h
    41 I&Dk!9(Q`^o!&o!oQ7Smk!&o!S*ooQOmk2!Ob9!`*9!oQ7SmkF%
    42 vg0Q!.p;OFc!gc!c;%DZQ!gc!Dycc;2ZQ>!2X.!Oy.!c;%DZQ93
    43 DI{7!#Y%>.W!IW!W%r5G7!IW!5iWW%tG7J!tN#!>i#!W%r5G7,A
    44 q+g|!wBn-uK!+K!Kn`&4|!+K!&YKKnW4|V!WDw!-Yw!Kn`&4|~O
    46 lN?H!asBjE3!N3!3B<gmH!N3!g933B|mHn!|0a!j9a!3B<gmHdk
    47 :0+.!V\,Y-'!0'!',*XZ.!0'!X)'',_Z.z!_&V!Y)V!',*XZ.Wy
    48 gqvs!KEuHtz!qz!zuwIGs!qz!IxzzuBGs'!B{K!HxK!zuwIGsJ(
    49 5SbY!@._7
    !Sn!n_e:4Y!Sn!:hnn_%4Y3!%q@!7h@!n_e:4Y=6
    51 0v:%!*_3t,V!vV!V3A{m%!vV!{HVV3Jm%K!J]*!tH*!V3A{m%#R
    52 ]X&j!~H|csJ!XJ!J|/lZj!XJ!l8JJ|-ZjW!-S~!c8~!J|/lZju`
    53 +:qP!s1fR[>!:>!>f|]GP!:>!](>>foGPc!oIs!R(s!>f|]GPhn
    54 X{]6!hyPAC2!{2!2PjN46!{2!Nw22PR46o!R?h!Awh!2PjN46[|
    56 S?5a!RK$~ry!?y!y$F0ma!?y!0Wyy$wma(!w+R!~WR!y$F0maA9
    58 Nbl-!<|WBa!ba!aW"qG-!ba!q7aaW=G-@!=v<!7<!aW"qG-'U
    59 {DXr!1eAK*U!DU!UAob4r!DU!b'UUA 4rL! l1!K'1!UAob4ryc
    61 vg0>!z7t)Y=!g=!=tKDm>!g=!Df==tEm>d!EXz!)fz!=tKDm>_
    62 DI{$!o ^wA1!I1!1^95Z$!I1!5V11^(Z$p!(No!wVo!1^95Z$R.
    63 q+gi!dhHf)%!+%!%H'&Gi!+%!&F%%HjGi|!jDd!fFd!%H'&GiE<
    64 ?lSO!YQ2Upx!lx!x2tv4O!lx!v6xx2M4O)!M:Y!U6Y!x2tv4O8J
    66 :0+z!C#e3@`!0`!`ePXmz!0`!Xu``ermzA!r&C!3uC!`ePXmz}f
    67 gqv`!8kO"(T!qT!TO>IZ`!qT!IeTTOUZ`M!U{8!"e8!TO>IZ`pt
    68 5SbF!-T9poH!SH!H9,:GF!SH!:UHH98GFY!8q-!pU-!H9,:GFc#
    69 b5N,!"=#_W<!5<!<#y+4,!5<!+E<<#z4,e!zg"!_E"!<#y+4,V1
    71 ]X&W!knV='$!X$!$VUlmW!X$!l%$$V@mW}!@Sk!=%k!$VUlmW<M
    72 +:q=!`W@,nw!:w!w@C]Z=!:w!]tww@#Z=*!#I`!,t`!w@C]Z=/[
    73 X{]#!U@*zVk!{k!k*1NG#!{k!Ndkk*eG#6!e?U!zdU!k*1NG#"i
    74 &]Ih!J)si>_!]_!_s~?4h!]_!?T__sH4hB!H5J!iTJ!_s~?4htw
    77 Nbly!)C16U;!b;!;1HqZy!b;!q$;;1PZyf!Pv)!6$)!;1HqZyMB
    78 {DX_!},z%=/!D/!/z6bG_!D/!bs//z3G_r!3l}!%s}!/z6bG_@P
    79 I&DE!rtds%#!&#!#d$S4E!&#!Sc##du4E~!ubr!scr!#d$S4E3^
    81 DI{p!F8QTj!Ij!j8_5mp!Ij!5Cjj8;mp7!;N!QC!j8_5mpxz
    82 q+gV!Q/"@<^!+^!^"M&ZV!+^!&3^^"}ZVC!}DQ!@3Q!^"M&ZVk)
    83 ?lS<!Fwk/$R!lR!Rk;vG<!lR!v#RRk`G<O!`:F!/#F!Rk;vG<^7
    84 lN?"!;`U}kF!NF!FU)g4"!NF!grFFUC4"[!C0;!}r;!FU)g4"QE
    86 gqvM!%2)[;.!q.!.)dImM!q.!IR..)hmMs!h{%![R%!.)dImM7a
    87 5Sb3!yzrJ#"!S"!"rR:Z3!S"!:B""rKZ3 !Kqy!JBy!"rR:Z3*o
    88 b5Nx!nc9ju!5u!u@+Gx!5u!+2uu.Gx,!.gn!92n!u@+Gx|}
    89 0v:^!cLF(Ri!vi!iF.{4^!vi!{"iiFp4^8!p]c!("c!iF.{4^o,
    91 +:q*!M}ye"Q!:Q!Qyi]m*!:Q!]aQQy6m*P!6IM!eaM!Qyi]m*UH
    92 X{]o!BfcTiE!{E!EcWNZo!{E!NQEEcxZo!x?B!TQB!EcWNZoHV
    93 &]IU!7OMCQ9!]9!9ME?GU!]9!?A99M[GUh![57!CA7!9ME?GU;d
    94 S?5;!,8729-!?-!-7304;!?-!01--7>4;t!>+,!21,!-7304;.r
    96 Nblf!uijoht!bt!tjnqmf!bt!qpttjcmf-!cvu!opu!tjnqmfs/
    97 {DXL!jRT^Ph!Dh!hTZL!Dh!b`hhTFZL9!Flj!^`j!hTZLf=
    98 I&D2!_;>M8!&!>JSG2!&!SP\>)G2E!)b_!MP_!>JSG2YK
    99 vg0w!T$(< P!gP!P(8D4w!gP!D@PP(k4wQ!kXT!<@T!P(8D4wLY

    我们发现,使用2和使用97得到的密文是相同的,使用3和使用98得到的密文是相同的,使用4和使用99得到的密文是相同的,

    显然仿射加密法的keyA和keyB都会出现“回调”现象,他们都受限于秘文符号集的大小

    95 * 95 = 9025种 keyA和keyB组合,但是还要减去keyA中不能和len(密文符号集)互质的数,剩下的这些就是暴力破译要考虑的密钥集。

    破译仿射密码
    # Affine Cipher Hacker
    # http://inventwithpython.com/hacking (BSD Licensed)
    
    import pyperclip, affineCipher, detectEnglish, cryptomath
    
    SILENT_MODE = False
    #SILENT_MODE = True
    def main():
        # You might want to copy & paste this text from the source code at
        # http://invpy.com/affineHacker.py
        myMessage = """U&'<3dJ^Gjx'-3^MS'Sj0jxuj'G3'%j'<mMMjS'g{GjMMg9j{G'g"'gG'<3^MS'Sj<jguj'm'P^dm{'g{G3'%jMgjug{9'GPmG'gG'-m0'P^dm{LU'5&Mm{'_^xg{9"""
    
        hackedMessage = hackAffine(myMessage)
    
        if hackedMessage != None:
            # The plaintext is displayed on the screen. For the convenience of
            # the user, we copy the text of the code to the clipboard.
            print('Copying hacked message to clipboard:')
            print(hackedMessage)
            pyperclip.copy(hackedMessage)
        else:
            print('Failed to hack encryption.')
    
    
    def hackAffine(message):
        print('Hacking...')
    
        # Python programs can be stopped at any time by pressing Ctrl-C (on
        # Windows) or Ctrl-D (on Mac and Linux)
        print('(Press Ctrl-C or Ctrl-D to quit at any time.)')
    
        # brute-force by looping through every possible key
        # Python中的指数运算符号**  
        # 暴力破译所有可能的密钥是 0 到affineCipher.SYMBOLS) ** 2
        # getKeyParts(key)返的是一个元组  用下标.[0]访问ke'y
        for key in range(len(affineCipher.SYMBOLS) ** 2):
            keyA = affineCipher.getKeyParts(key)[0]
            if cryptomath.gcd(keyA, len(affineCipher.SYMBOLS)) != 1:
                # continue 跳过当前的循环中的操作继续下一轮操作,而不是跳出循环
                continue
    
            decryptedText = affineCipher.decryptMessage(key, message)
            if not SILENT_MODE:
                print('Tried Key %s... (%s)' % (key, decryptedText[:40]))
    
            # 每个key都做了detectEnglish.isEnglish(decryptedText),但是不一定近到了if代码块,
            # 只有isEnglish为True才得出可能的密文
            if detectEnglish.isEnglish(decryptedText):
                # Check with the user if the decrypted key has been found.
                print()
                print('Possible encryption hack:')
                print('Key: %s' % (key))
                print('Decrypted message: ' + decryptedText[:200])
                print()
                print('Enter D for done, or just press Enter to continue hacking:')
                response = input('> ')
    
                if response.strip().upper().startswith('D'):
                    return decryptedText
        return None
    
    
    # If affineHacker.py is run (instead of imported as a module) call
    # the main() function.
    if __name__ == '__main__':
        main()
  • 相关阅读:
    Array.sort源码
    Linkedlist源码
    最大公约数 2.7
    腾讯笔试题
    腾讯2014校园招聘笔试题
    指针问题
    JavaScript 日历
    QT 初阶 第二章 创建对话框(查找对话框实例)
    QT 初阶 1.3 节 控件的几何排列
    “项目中的问题”
  • 原文地址:https://www.cnblogs.com/PiaYie/p/13475052.html
Copyright © 2020-2023  润新知