1. 程式人生 > >Python乘法密碼

Python乘法密碼

blog 進行 arp nsf lock spa 完全 變換 方程

乘法密碼

屬於替換密碼技術的一種
乘法密碼技術的加密變換:\[ Ek(Ai)=Aj \]\[j=ik(mod n) ,gcd(k,n)=1\]

  • 0<k<n
  • kn互素,即要滿足gcd(k, n)=1,否則不存在模逆元,不能正確解密

設明文消息為M,消息元素為m元素下標為i;
則密文消息為C,密文元素為c元素下標為j; \[c=i*k mod n\]

乘法密碼的密碼空間大小,即小於n且與n互素的非負整數的個數,是\(φ(n)\)\(φ(n)\)是歐拉函數。
n26字母,則與26互素的數是\[{1、3、5、7、9、11、15、17、19、21、23、25}\]

,即\(φ(n)=12\)

因此乘法密碼的密鑰空間為12
註意:k=1時 加密變換為恒等變換(即無變化)
乘法密碼也稱采樣密碼,因為密文字母表是將明文字母按照下標每隔k位取出一個字母排列而成。
例如對26個字母生成密碼表(下標由0開始,0-25
k=9

  • 明文字母 \[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\]
  • 數組下標 \[0 ,1 ,2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 \]
  • 密文字母 \[a ,j, s, b, k, t, c, l, u, d, m, v, e, n, w, f, o, x, g, p, y, h, q, z, i, r, \]
  • 數組下標 \[0 ,9, 18, 1, 10, 19, 2, 11, 20, 3, 12, 21, 4, 13, 22, 5, 14, 23, 6, 15, 24, 7, 16, 25, 8, 17 \]

正如上所述,從下標0開始, 明文a: 0X9%26=0 -->[0]=a 明文b: 1X9%26=9 -->[9]=j
其實即是通過公式算出密文密碼表,其意義與明文表相一一對應。

乘法密碼技術的解密變換: \[Dk(Aj)=Ai\]
\[i=jX(mod n)\]

? \(X\)\(k\)的逆元(最小正整數)
對於正整數 kn,如果有\(kX≡1(mod n)\),那麽把這個同余方程中\(X\)

的最小正整數解叫做\(k模n\)的逆元。

由於\(k\)的取值是從\(φ(n)\) 密碼空間中獲得,則必定k 123 = 1*123+ 0*11

11 = 0*123+ 1*11 |11
2 = 1*123+ (-11)*11 |5
1 = (-5)*123+ 56*11
聰明的你, 一定看出來了吧. 對! 我們將123和11都表示成 x * 123 + y * 11 的 格式, 然後相減, 在最右側一欄寫上每次減去的被減數的倍數. 依次進行, 知道減數變為1為止. 然後我們取第三列的最下面的一個數, 再對123 取模 即得11 對123的模逆.

Python實現求逆元:

from math import floor


def inverseElement(k2, Z=26):
    '''
    to get the inverse element for k2 % Z
    '''
    a = [Z, 1, 0]
    b = [k2, 0, 1]

    while(1):

        if b[0] == 1:
            break

        temp = b

        q = floor(a[0] / b[0])
        b = [i * q for i in b]

        b = [a[i] - b[i] for i in range(len(b))]
        a = temp

    return b[-1] % Z

完整的加密解密代碼:

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

from math import floor


def gcd(x, y):
    if x < y:
        t = x
        x = y
        y = t

    if y == 0:
        return x

    if y != 0:
        return gcd(y, x % y)
    else:
        # print(x)
        return x


def str2num(str):
    '''
    TODO:transfermation between the unicode num and str
    '''
    strL = list(str)
    numL = [ord(i) - 97 for i in strL]

    return numL


def num2str(num):

    numL = [i + 97 for i in num]
    strL = ''.join([chr(int(i)) for i in numL])

    return strL


def inverseElement(k2, Z=26):
    '''
    to get the inverse element for k2 % Z
    '''
    a = [Z, 1, 0]
    b = [k2, 0, 1]

    while(1):

        if b[0] == 1:
            break

        temp = b

        q = floor(a[0] / b[0])
        b = [i * q for i in b]

        b = [a[i] - b[i] for i in range(len(b))]
        a = temp

    return b[-1] % Z


def encrypted(m, k2, Z=26):
    if m not in range(26):
        return m
    else:
        return (k2 * m) % Z


def decrypted(c, k2, Z=26):
    if c not in range(26):
        return c
    else:
        return (inverseElement(k2, Z) * (c)) % Z


if __name__ == '__main__':

    # 加密部分
    str0 = 'hello the cruel world!'
    num0 = str2num(str0.lower())
    num1 = [encrypted(i, 11) for i in num0]
    str1 = num2str(num1)
    print('密文 %s' % str1)

    # 解密部分
    str0 = str1
    num0 = str2num(str0.lower())
    num1 = [decrypted(i, 11) for i in num1]
    str1 = num2str(num1)
    print('明文 %s' % str1)

Python乘法密碼