Python乘法密碼
阿新 • • 發佈:2017-11-30
blog 進行 arp nsf lock spa 完全 變換 方程 因此乘法密碼的密鑰空間為
註意:
乘法密碼也稱
例如對
取 的最小正整數解叫做\(k模n\)的逆元。
乘法密碼
屬於替換密碼
技術的一種
乘法密碼技術的加密變換:\[ Ek(Ai)=Aj \]\[j=ik(mod n) ,gcd(k,n)=1\]
0<k<n
k
與n
互素,即要滿足gcd(k, n)=1
,否則不存在模逆元,不能正確解密
設明文消息為M
,消息元素為m
元素下標為i
;
則密文消息為C
,密文元素為c
元素下標為j
; \[c=i*k mod n\]
乘法密碼的密碼空間大小,即小於n
且與n
互素的非負整數的個數,是\(φ(n)\),\(φ(n)\)是歐拉函數。
當n
為26
字母,則與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\)的逆元(最小正整數)
對於正整數 k
和n
,如果有\(kX≡1(mod n)\),那麽把這個同余方程中\(X\)
由於\(k\)的取值是從\(φ(n)\) 密碼空間中獲得,則必定k123 = 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乘法密碼