仿射加密法

仿射加密法

乘数加密法 + 凯撒加密法 = 仿射加密法
在乘数加密之后执行凯撒加密,便是仿射加密。
这样确保字母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

发布了33 篇原创文章 · 获赞 3 · 访问量 1829

猜你喜欢

转载自blog.csdn.net/youngdianfeng/article/details/104400874