仿射加密

仿射密码为单表加密的一种,字母系统中所有字母都藉一简单数学方程加密,对应至数值,或转回字母。  ——百度百科

辗转相除法 与 寻找模逆:

 1 # Cryptomath Module
 2 # http://inventwithpython.com/hacking (BSD Licensed)
 3 
 4 def gcd(a, b):
 5     # Return the GCD of a and b using Euclid's Algorithm
 6     while a != 0:
 7         a, b = b % a, a
 8     return b
 9 
10 
11 def findModInverse(a, m):
12     # Returns the modular inverse of a % m, which is
13     # the number x such that a*x % m = 1
14 
15     if gcd(a, m) != 1:
16         return None # no mod inverse if a & m aren't relatively prime
17 
18     # Calculate using the Extended Euclidean Algorithm:
19     u1, u2, u3 = 1, 0, a
20     v1, v2, v3 = 0, 1, m
21     while v3 != 0:
22         q = u3 // v3 # // is the integer division operator
23         v1, v2, v3, u1, u2, u3 = (u1 - q * v1), (u2 - q * v2), (u3 - q * v3), v1, v2, v3
24     return u1 % m
cryptMath

仿射密码是一种替换密码。它是一个字母对一个字母的。它的加密函数是 ,其中a和m互质,m是字母的数目。

乘法加密的缺点是字母a总是加密到字母a,应为0乘以任何数都是0。可以再对其使用凯撒密码进行二次加密。

注意: 在仿射加密里,密钥a数字与字符集大小必须互质。即 gcd(密钥, 符号集的大小)== 1.

加解密步骤:

  1. 输入密钥并进行判断
  2. 得到字符在字符集里的位置,并对其计算得到密文
 1 # Affine Cipher
 2 # http://inventwithpython.com/hacking (BSD Licensed)
 3 
 4 import sys, pyperclip, cryptomath, random
 5 SYMBOLS = """ !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~""" # note the space at the front
 6 
 7 
 8 def main():
 9     myMessage = """"A computer would deserve to be called intelligent if it could deceive a human into believing that it was human." -Alan Turing"""
10     myKey = 2023
11     myMode = 'encrypt' # set to 'encrypt' or 'decrypt'
12 
13     if myMode == 'encrypt':
14         translated = encryptMessage(myKey, myMessage)
15     elif myMode == 'decrypt':
16         translated = decryptMessage(myKey, myMessage)
17     print('Key: %s' % (myKey))
18     print('%sed text:' % (myMode.title()))
19     print(translated)
20     pyperclip.copy(translated)
21     print('Full %sed text copied to clipboard.' % (myMode))
22 
23 
24 def getKeyParts(key):
25     keyA = key // len(SYMBOLS)
26     keyB = key % len(SYMBOLS)
27     return (keyA, keyB)
28 
29 
30 def checkKeys(keyA, keyB, mode):
31     if keyA == 1 and mode == 'encrypt':
32         sys.exit('The affine cipher becomes incredibly weak when key A is set to 1. Choose a different key.')
33     if keyB == 0 and mode == 'encrypt':
34         sys.exit('The affine cipher becomes incredibly weak when key B is set to 0. Choose a different key.')
35     if keyA < 0 or keyB < 0 or keyB > len(SYMBOLS) - 1:
36         sys.exit('Key A must be greater than 0 and Key B must be between 0 and %s.' % (len(SYMBOLS) - 1))
37     if cryptomath.gcd(keyA, len(SYMBOLS)) != 1:
38         sys.exit('Key A (%s) and the symbol set size (%s) are not relatively prime. Choose a different key.' % (keyA, len(SYMBOLS)))
39 
40 
41 def encryptMessage(key, message):
42     keyA, keyB = getKeyParts(key)
43     checkKeys(keyA, keyB, 'encrypt')
44     ciphertext = ''
45     for symbol in message:
46         if symbol in SYMBOLS:
47             # encrypt this symbol
48             symIndex = SYMBOLS.find(symbol)
49             ciphertext += SYMBOLS[(symIndex * keyA + keyB) % len(SYMBOLS)]
50         else:
51             ciphertext += symbol # just append this symbol unencrypted
52     return ciphertext
53 
54 
55 def decryptMessage(key, message):
56     keyA, keyB = getKeyParts(key)
57     checkKeys(keyA, keyB, 'decrypt')
58     plaintext = ''
59     modInverseOfKeyA = cryptomath.findModInverse(keyA, len(SYMBOLS))
60 
61     for symbol in message:
62         if symbol in SYMBOLS:
63             # decrypt this symbol
64             symIndex = SYMBOLS.find(symbol)
65             plaintext += SYMBOLS[(symIndex - keyB) * modInverseOfKeyA % len(SYMBOLS)]
66         else:
67             plaintext += symbol # just append this symbol undecrypted
68     return plaintext
69 
70 
71 def getRandomKey():
72     while True:
73         keyA = random.randint(2, len(SYMBOLS))
74         keyB = random.randint(2, len(SYMBOLS))
75         if cryptomath.gcd(keyA, len(SYMBOLS)) == 1:
76             return keyA * len(SYMBOLS) + keyB
77 
78 
79 # If affineCipher.py is run (instead of imported as a module) call
80 # the main() function.
81 if __name__ == '__main__':
82     main()
affineCipher

测试其有多少密钥:

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

其大约有几千个密码,可暴力:

 1 # Affine Cipher Hacker
 2 # http://inventwithpython.com/hacking (BSD Licensed)
 3 
 4 import pyperclip, affineCipher, detectEnglish, cryptomath
 5 
 6 SILENT_MODE = False
 7 
 8 def main():
 9     # You might want to copy & paste this text from the source code at
10     # http://invpy.com/affineHacker.py
11     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"""
12 
13     hackedMessage = hackAffine(myMessage)
14 
15     if hackedMessage != None:
16         # The plaintext is displayed on the screen. For the convenience of
17         # the user, we copy the text of the code to the clipboard.
18         print('Copying hacked message to clipboard:')
19         print(hackedMessage)
20         pyperclip.copy(hackedMessage)
21     else:
22         print('Failed to hack encryption.')
23 
24 
25 def hackAffine(message):
26     print('Hacking...')
27 
28     # Python programs can be stopped at any time by pressing Ctrl-C (on
29     # Windows) or Ctrl-D (on Mac and Linux)
30     print('(Press Ctrl-C or Ctrl-D to quit at any time.)')
31 
32     # brute-force by looping through every possible key
33     for key in range(len(affineCipher.SYMBOLS) ** 2):
34         keyA = affineCipher.getKeyParts(key)[0]
35         if cryptomath.gcd(keyA, len(affineCipher.SYMBOLS)) != 1:
36             continue
37 
38         decryptedText = affineCipher.decryptMessage(key, message)
39         if not SILENT_MODE:
40             print('Tried Key %s... (%s)' % (key, decryptedText[:40]))
41 
42         if detectEnglish.isEnglish(decryptedText):
43             # Check with the user if the decrypted key has been found.
44             print()
45             print('Possible encryption hack:')
46             print('Key: %s' % (key))
47             print('Decrypted message: ' + decryptedText[:200])
48             print()
49             print('Enter D for done, or just press Enter to continue hacking:')
50             response = input('> ')
51 
52             if response.strip().upper().startswith('D'):
53                 return decryptedText
54     return None
55 
56 
57 # If affineHacker.py is run (instead of imported as a module) call
58 # the main() function.
59 if __name__ == '__main__':
60     main()
affineHacker
原文地址:https://www.cnblogs.com/zhangzixian/p/10482828.html