仿射加密法
乘数加密法 + 凯撒加密法 = 仿射加密法
在乘数加密之后执行凯撒加密,便是仿射加密。
这样确保字母A不总是加密到A,且密钥是乘数加密的26倍。
凯撒加密法:https://blog.csdn.net/youngdianfeng/article/details/104333494
乘数加密法:https://blog.csdn.net/youngdianfeng/article/details/104401000
算法大意
加密过程:明文 --> 乘以密钥A --> 加上密钥B --> 根据符号集的大小取模 --> 密文
解密过程:明文 <-- 根据符号集的大小取模 <-- 乘以密钥A的模逆 <-- 减去密钥B <-- 密文
弊端
密钥A不能使用任何数字,如果是8,字母C和P都加密成Q。
必须要满足的条件:密钥A数字和符号集的大小必须互质 及 gcd(密钥,符号集大小) ==1
仿射加密法的加密密钥和解密密钥是两个不同的数字。
什么是模逆
两个数字a和m的模逆i满足 (a*i) % m == 1
可以通过暴力运算出模逆,但是如果像8953851这种密钥就比较耗时,提供了欧几里得的扩展算法可以快速算出模逆。
代码实例
# 找出两个数字的最大公因数 如果是1则代表是互质
def gcd(a,b):
while a!=0:
a,b = b % a,a
return b
# 欧几里得的扩展算法 找出模逆算法
def findModInverse(a,m):
if gcd(a,m)!=1:
# 如果a和m不互质,则不存在模逆
return None
u1,u2,u3 = 1,0,a
v1,v2,v3 = 0,1,m
while v3!=0:
q = u3 // v3
v1,v2,v3,u1,u2,u3 = (u1 - q*v1),(u2 - q*v3),(u3 - q*v3),v1,v2,v3
return u1 % m
import sys, random
# 字典(符号集)
SYMBOLS = """ !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~""" # 第一个是空格字符
# 将一个密钥分成两个密钥及密钥A和密钥B,key = (keyA * 字典大小) + keyB
def getKeyParts(key):
keyA = key // len(SYMBOLS)
keyB = key % len(SYMBOLS)
return (keyA, keyB)
# 验证密钥是否可用
def checkKeys(keyA, keyB, mode):
# 如果keyA是1的话 或者 KeyB是0的话 那密钥是个弱密钥(如果KeyA是1,keyB是0,那么就没有加密)
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.')
# keyA和keyB不能是负数
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))
# keyA和字典总数互质
if 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:
# 加密单个字符
symIndex = SYMBOLS.find(symbol)
ciphertext += SYMBOLS[(symIndex * keyA + keyB) % len(SYMBOLS)]
else:
ciphertext += symbol # 如果不在字符集里就在密文里直接加入这个字符
return ciphertext
# 解密算法
def decryptMessage(key, message):
keyA, keyB = getKeyParts(key)
checkKeys(keyA, keyB, 'decrypt')
plaintext = ''
modInverseOfKeyA = findModInverse(keyA, len(SYMBOLS))
for symbol in message:
if symbol in SYMBOLS:
# 解密单个字符
symIndex = SYMBOLS.find(symbol)
plaintext += SYMBOLS[(symIndex - keyB) * modInverseOfKeyA % len(SYMBOLS)]
else:
plaintext += symbol # 如果不在字符集里就在密文里直接加入这个字符
return plaintext
# 随机出一个可用密钥
def getRandomKey():
while True:
keyA = random.randint(2, len(SYMBOLS))
keyB = random.randint(2, len(SYMBOLS))
if gcd(keyA, len(SYMBOLS)) == 1:
return keyA * len(SYMBOLS) + keyB
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 = getRandomKey() # 例如 2023
# 加密
translated = encryptMessage(myKey, myMessage)
print('Key: %s' % (myKey))
print('ciphertext : %s' %(translated))
print()
# 解密
print('decrypt hte ciphertext....')
translated = decryptMessage(myKey, translated)
print('plaintext : %s' %(translated))
if __name__ == '__main__':
main()
运行结果
Key: 3764
ciphertext : J0[,%6LQz;[@%QnS[Szbz;xz[%[dz[,=nnzS[X]znnXiz][XB[X*[,%QnS[Sz,zXxz[=[1Q6=][X]%[dznXzxX]i[1=[X[@=b[1Q6=]CJ[{0n=][|Q;X]i
decrypt hte ciphertext…
plaintext : “A computer would deserve to be called intelligent if it could deceive a human into believing that it was human.” -Alan Turing