古典密码
文章目录
前言
系统的学习了一下古典密码,这里大概整理一下主要的加密方式以及实现加解密的python代码。
1.Affine(仿射加密)
单码加密法的另一种形式称为仿射加密法(affine cipher)。在仿射加密法中,字母表的字母被赋予一个数字,例如a=0,b=1,c=2…z=25。仿射加密法的密钥为0-25直接的数字对。
代码:
# 乘法逆元
def multiplicative_inverse(key_a, a_z=26):
inv = 1
while True:
if (key_a * inv) % a_z == 1:
break
inv = inv + 1
return inv
# 加密
def encipher(key_a, key_b, txt):
result = ""
if judge_a(key_a) == 0:
result = "key_a必须是1, 3, 5, 7, 9, 11, 15, 17, 19, 21, 23, 25"
else:
if isinstance(key_b, int):
for i in txt.lower():
if i.isalpha():
temp = ((ord(i) - 97) * key_a + key_b) % 26 + 97
result = result + chr(temp)
else:
result = result + i
else:
result = "key_b必须为整数"
return result
# 解密
def decipher(key_a, key_b, cipher):
result = ""
if judge_a(key_a) == 0:
result = "key_a必须是1, 3, 5, 7, 9, 11, 15, 17, 19, 21, 23, 25"
else:
if isinstance(key_b, int):
a_inv = multiplicative_inverse(key_a)
for i in cipher.lower():
if i.isalpha():
temp = (((ord(i) - 97) - key_b) * a_inv) % 26 + 97
result = result + chr(temp)
else:
result = result + i
else:
result = "key_b必须为整数"
return result
def judge_a(key_a):
range_a = (1, 3, 5, 7, 9, 11, 15, 17, 19, 21, 23, 25)
if key_a in range_a:
return key_a
else:
return 0
if __name__ == "__main__":
a = 3
b = -1
text = 'hello word'
print(encipher(a, b, text))
print(decipher(a, b, 'ulggp npyi'))
输出:
ulggp npyi
hello word
2.Bacon(培根加密)
培根密码,又名倍康尼密码(英语:Bacon’s cipher)是由法兰西斯·培根发明的一种隐写术。
加密时,明文中的每个字母都会转换成一组五个英文字母。
'A': 'aaaaa', 'B': 'aaaab', 'C': 'aaaba', 'D': 'aaabb', 'E': 'aabaa', 'F': 'aabab',
'G': 'aabba',
'H': 'aabbb', 'I': 'abaaa', 'J': 'abaab', 'K': 'ababa', 'L': 'ababb', 'M': 'abbaa',
'N': 'abbab',
'O': 'abbba', 'P': 'abbbb', 'Q': 'baaaa', 'R': 'baaab', 'S': 'baaba', 'T': 'baabb',
'U': 'babaa', 'V': 'babab', 'W': 'babba', 'X': 'babbb', 'Y': 'bbaaa', 'Z': 'bbaab'
培根密码实际上就是一种替换密码,根据所给表一一对应转换即可加密解密 。它的特殊之处在于:可以通过不明显的特征来隐藏密码信息,比如大小写、正斜体等,只要两个不同的属性,密码即可隐藏。
解密时,将上述方法倒转。所有字体一转回A,字体二转回B,以后再按上表拼回字母。
代码:
def encipher1(txt):
bacon_dict1 = {'A': 'aaaaa', 'B': 'aaaab', 'C': 'aaaba', 'D': 'aaabb', 'E': 'aabaa', 'F': 'aabab', 'G': 'aabba',
'H': 'aabbb', 'I': 'abaaa', 'J': 'abaab', 'K': 'ababa', 'L': 'ababb', 'M': 'abbaa', 'N': 'abbab',
'O': 'abbba', 'P': 'abbbb', 'Q': 'baaaa', 'R': 'baaab', 'S': 'baaba', 'T': 'baabb',
'U': 'babaa', 'V': 'babab', 'W': 'babba', 'X': 'babbb', 'Y': 'bbaaa', 'Z': 'bbaab'}
result = ""
txt = txt.upper()
for i in txt:
try:
result = result + bacon_dict1[i]
except KeyError:
result = result + i
return result
def encipher2(txt):
bacon_dict2 = {'a': 'AAAAA', 'b': 'AAAAB', 'c': 'AAABA', 'd': 'AAABB', 'e': 'AABAA', 'f': 'AABAB', 'g': 'AABBA',
'h': 'AABBB', 'i': 'ABAAA', 'j': 'ABAAA', 'k': 'ABAAB', 'l': 'ABABA', 'm': 'ABABB', 'n': 'ABBAA',
'o': 'ABBAB', 'p': 'ABBBA', 'q': 'ABBBB', 'r': 'BAAAA', 's': 'BAAAB', 't': 'BAABA',
'u': 'BAABB', 'v': 'BAABB', 'w': 'BABAA', 'x': 'BABAB', 'y': 'BABBA', 'z': 'BABBB'}
result = ""
txt = txt.lower()
for i in txt:
try:
result = result + bacon_dict2[i]
except KeyError:
result = result + i
return result
# 文本->bacon
def encipher(txt):
results = [encipher1(txt), encipher2(txt)]
return results
def decipher1(txt):
bacon_dict1_txt = {'aaaaa': 'A', 'aaaab': 'B', 'aaaba': 'C', 'aaabb': 'D', 'aabaa': 'E', 'aabab': 'F', 'aabba': 'G',
'aabbb': 'H', 'abaaa': 'I', 'abaab': 'J', 'ababa': 'K', 'ababb': 'L', 'abbaa': 'M', 'abbab': 'N',
'abbba': 'O', 'abbbb': 'P', 'baaaa': 'Q', 'baaab': 'R', 'baaba': 'S', 'baabb': 'T',
'babaa': 'U', 'babab': 'V', 'babba': 'W', 'babbb': 'X', 'bbaaa': 'Y', 'bbaab': 'Z'}
result = ""
txt = txt.lower()
for i in range(0, len(txt), 5):
try:
result = result + bacon_dict1_txt[txt[i:i + 5]]
except KeyError:
result = result + "?"
return result
def decipher2(txt):
bacon_dict2_txt = {'AAAAA': 'a', 'AAAAB': 'b', 'AAABA': 'c', 'AAABB': 'd', 'AABAA': 'e', 'AABAB': 'f', 'AABBA': 'g',
'AABBB': 'h', 'ABAAA': '(i/j)', 'ABAAB': 'k', 'ABABA': 'l', 'ABABB': 'm', 'ABBAA': 'n',
'ABBAB': 'o', 'ABBBA': 'p', 'ABBBB': 'q', 'BAAAA': 'r', 'BAAAB': 's', 'BAABA': 't',
'BAABB': '(u/v)', 'BABAA': 'w', 'BABAB': 'x', 'BABBA': 'y', 'BABBB': 'z'}
result = ""
txt = txt.upper()
for i in range(0, len(txt), 5):
try:
result = result + bacon_dict2_txt[txt[i:i + 5]]
except KeyError:
result = result + '?'
return result
# bacon->文本
def decipher(txt):
results = [decipher1(txt), decipher2(txt)]
return results
if __name__ == '__main__':
print(encipher("sfauh"))
print(decipher("abbaabbaaa"))
输出:
ulggp npyi
hello word
3.Brainfuck
是一种极小化的计算机语言,它是由Urban Müller在1993年创建的。由于fuck在英语中是脏话,这种语言有时被称为brainf*ck或brainf** k,甚至被简称为BF.
这种语言,是一种按照“Turing complete(图灵完备)”思想设计的语言,它的主要设计思路是:用最小的概念实现一种“简单”的语言,BrainF**k 语言只有八种符号,所有的操作都由这八种符号的组合来完成。
代码:
def brain_fuck(code):
data = [0 for i in range(1000)]
pc = 0
ptr = 0
skip_loop = False
bracket_count = 0
stack = []
result = ''
while pc < len(code):
c = code[pc]
if skip_loop:
if c == '[':
bracket_count += 1
elif c == ']':
bracket_count -= 1
if bracket_count == 0:
skip_loop = False
pc += 1
continue
if c == '>':
ptr += 1
pc += 1
elif c == '<':
ptr -= 1
pc += 1
elif c == '+':
data[ptr] += 1
pc += 1
elif c == '-':
data[ptr] -= 1
pc += 1
elif c == '.':
result = result + chr(data[ptr])
pc += 1
elif c == ',':
pc += 1
elif c == '[':
if data[ptr] == 0:
# nonlocal bracket_count,skip_loop
bracket_count = 1
skip_loop = True
pc += 1
else:
pc += 1
stack.append(pc)
elif c == ']':
if data[ptr] == 0:
pc += 1
stack.pop()
else:
pc = stack[len(stack) - 1]
return result
if __name__ == '__main__':
print(brain_fuck('++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.'))
输出:
Hello World!
4.Caesar(凯撒加密)
凯撒加密是古罗马恺撒大帝用来保护重要军情的加密系统。
“恺撒密码”它是一种替代密码,通过将字母按顺序推后3位起到加密作用,如将字母A换作字母D,将字母B换作字母E。据说恺撒是率先使用加密函的古代将领之一,因此这种加密方法被称为恺撒密码。
代码
# 判断密钥
def judge_key(k):
if 0 < k < 27 and isinstance(k, int):
return k
else:
return 0
def encipher(txt, k):
result = ""
if judge_key(k) == 0:
result = "密钥应为[1,26]的整数"
else:
result = result + str(k) + ':'
for i in txt:
if i.isupper():
result = result + chr(65 + (ord(i) - 65 + k) % 26)
elif i.islower():
result = result + chr(97 + (ord(i) - 97 + k) % 26)
else:
result = result + i
return result
# 返回所有偏移结果
def all_result(txt):
res = []
for n in range(1, 27):
res.append(encipher(txt, n))
return res
def rot13(txt):
res = "rot" + encipher(txt, 13)
return res
if __name__ == '__main__':
text=input("Please input the words : ")
results = all_result(text)
print(results)
输出:
Please input the words : Hello world
['1:Ifmmp xpsme', '2:Jgnnq yqtnf', '3:Khoor zruog', '4:Lipps asvph', '5:Mjqqt btwqi', '6:Nkrru cuxrj', '7:Olssv dvysk', '8:Pmttw ewztl', '9:Qnuux fxaum', '10:Rovvy gybvn', '11:Spwwz hzcwo', '12:Tqxxa iadxp', '13:Uryyb jbeyq',
'14:Vszzc kcfzr', '15:Wtaad ldgas', '16:Xubbe mehbt', '17:Yvccf nficu', '18:Zwddg ogjdv', '19:Axeeh phkew', '20:Byffi qilfx', '21:Czggj rjmgy', '22:Dahhk sknhz', '23:Ebiil tloia', '24:Fcjjm umpjb', '25:Gdkkn vnqkc', '26:Hello world']
5.Fence(栅栏加密)
所谓栅栏密码,就是把要加密的明文分成N个一组,然后把每组的第1个字连起来,形成一段无规律的话。 不过栅栏密码本身有一个潜规则,就是组成栅栏的字母一般不会太多。(一般不超过30个,也就是一、两句话)
代码:
# 栅栏范围
def get_field(txt):
field = []
for i in range(2, len(txt)):
if len(txt) % i == 0:
field.append(i)
return field
def encipher(txt, k):
field = get_field(txt)
txt_length = len(txt)
if k in field:
result = '' + str(k) + '栏:'
for m in range(k):
for n in range(m, txt_length, k):
result = result + txt[n]
else:
result = '密钥有误,应在范围'+str(field)
return result
# 输出所有可能的结果
def all_result(txt):
results = []
for k in get_field(txt):
results.append(encipher(txt, k))
return results
if __name__ == '__main__':
text = 'Helloworld'
print(encipher(text, 2))
print(all_result(text))
输出:
2栏:Hloolelwrd
['2栏:Hloolelwrd', '5栏:Hweolrllod']
6.Fenham(费纳姆加密)
费纳姆密码其实是一种由二进制产生的替换密码。
是双方约定一个数,明文加上这个数就是密文。这个数相当于密钥(可以是单词 词组 句子 几个字母也行)。
'A': '1000001', 'B': '1000010', 'C': '1000011', 'D': '1000100', 'E': '1000101', 'F': '1000110',
'G': '1000111', 'H': '1001000', 'I': '1001001', 'J': '1001010', 'K': '1001011', 'L': '1001100',
'M': '1001101', 'N': '1001110', 'O': '1001111', 'P': '1010000', 'Q': '1010001', 'R': '1010010',
'S': '1010011', 'T': '1010100', 'U': '1010101', 'V': '1010110', 'W': '1010111', 'X': '1011000',
'Y': '1011001', 'Z': '1011010'
例如:
明文: hello=1001000 1000101 1001100 1001100 1001111
密钥:crude=1000011 1010010 1010101 1000100 1000101
异或得到密文=0001011 0010111 0011001 0001000 0001010
代码:
char_num = {'A': '1000001', 'B': '1000010', 'C': '1000011', 'D': '1000100', 'E': '1000101', 'F': '1000110',
'G': '1000111', 'H': '1001000', 'I': '1001001', 'J': '1001010', 'K': '1001011', 'L': '1001100',
'M': '1001101', 'N': '1001110', 'O': '1001111', 'P': '1010000', 'Q': '1010001', 'R': '1010010',
'S': '1010011', 'T': '1010100', 'U': '1010101', 'V': '1010110', 'W': '1010111', 'X': '1011000',
'Y': '1011001', 'Z': '1011010'}
num_char = {'1000001': 'A', '1000010': 'B', '1000011': 'C', '1000100': 'D', '1000101': 'E', '1000110': 'F',
'1000111': 'G', '1001000': 'H', '1001001': 'I', '1001010': 'J', '1001011': 'K', '1001100': 'L',
'1001101': 'M', '1001110': 'N', '1001111': 'O', '1010000': 'P', '1010001': 'Q', '1010010': 'R',
'1010011': 'S', '1010100': 'T', '1010101': 'U', '1010110': 'V', '1010111': 'W', '1011000': 'X',
'1011001': 'Y', '1011010': 'Z'}
# 转换
def txt_num(txt):
txt = txt.upper()
result = ""
for i in txt:
result = result + char_num[i]
return result
# 最终数字转换为字母
def num_list(txt):
num = 0
s = []
while True:
s.append(txt[num:num + 7])
num += 7
if num > len(txt) - 7:
break
return s
# 加密 文本内容
def encipher(txt, k):
result = ''
if txt.isalpha() and k.isalpha():
txt = txt_num(txt)
k = txt_num(k)
j = len(k)
for i in range(0, len(txt)):
if txt[i] == k[i % j]:
result += '0'
else:
result += '1'
else:
result = "明文与密钥应为纯字母"
return result
# 解密 文本为数字格式
def decipher(txt, k):
result = ''
if k.isalpha():
k = txt_num(k)
j = len(k)
for i in range(0, len(txt)):
if txt[i] == k[i % j]:
result += '0'
else:
result += '1'
result = num_list(result)
result_char = ""
for i in result:
try:
result_char = result_char + num_char[i]
except KeyError:
result_char = result_char + '?'
result = result_char
else:
result = "密钥应为纯字母"
return result
if __name__ == '__main__':
# 加解密
text = '00010110010111001100100010000001010'
# 读文本文件
key = "crude"
text_2 = "hello"
print(encipher(text_2, key))
print(decipher(text, key))
输出:
00010110010111001100100010000001010
HELLO
7.Morse(摩斯密码)
摩尔斯电码是一种时通时断的信号代码,通过不同的排列顺序来表达不同的英文字母、数字和标点符号,是由美国人萨缪尔·摩尔斯在1836年发明。
每一个字符(字母或数字)对应不同的序列(由点和划组成)。
一般来说,任何一种能把书面字符用可变长度的信号表示的编码方式都可以称为摩尔斯电码。
'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': '----.',
'.': '.-.-.-', ':': '---...', ',': '--..--', ';': '-.-.-.', '?': '..--..',
'=': '-...-', "'": '.----.', '/': '-..-.', '!': '-.-.--', '-': '-....-',
'_': '..--.-', '"': '.-..-.', '(': '-.--.', ')': '-.--.-', '$': '...-..-',
'@': '.--.-.', '+': '.-.-.'
代码:
# "01"—>".-"
def translate_string(txt):
table = ''.maketrans('01', '.-')
txt = txt.translate(table)
return txt
# 文本->摩斯密码
def encipher(txt):
result = ""
morse_dict = {
'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': '----.',
'.': '.-.-.-', ':': '---...', ',': '--..--', ';': '-.-.-.', '?': '..--..',
'=': '-...-', "'": '.----.', '/': '-..-.', '!': '-.-.--', '-': '-....-',
'_': '..--.-', '"': '.-..-.', '(': '-.--.', ')': '-.--.-', '$': '...-..-',
'@': '.--.-.', '+': '.-.-.'
}
txt = txt.upper()
for i in txt:
try:
result = result + morse_dict[i] + '/'
except KeyError:
result = result + i + '/'
return result.strip('/')
# 摩斯密码—>文本
def decipher(txt, sign=" "):
result = ""
morse_dict = {
".-": "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",
".-.-.-": ".", "---...": ":", "--..--": ",", "-.-.-.": ";", "..--..": "?",
"-...-": "=", ".----.": "'", "-..-.": "/", "-.-.--": "!", "-....-": "-",
"..--.-": "_", ".-..-.": '"', "-.--.": "(", "-.--.-": ")", "...-..-": "$",
".--.-.": "@", ".-.-.": "+",
}
# "0/1"->"./-"
if '0' or '1' in txt:
txt = translate_string(txt)
# sign('/' or ' ')
if '/' in txt:
sign = '/'
# 分割,字符串string,分割标识符sign
lists = txt.split(sign)
for code in lists:
try:
result = result + morse_dict[code]
except KeyError:
result = result + "?"
return result
if __name__ == "__main__":
print(encipher("Hello world"))
print(decipher('...././.-../.-../---/ /.--/---/.-./.-../-..'))
输出:
...././.-../.-../---/ /.--/---/.-./.-../-..
HELLO?WORLD
8.Pigen(猪圈加密)
猪圈密码(亦称朱高密码、共济会暗号、共济会密码或共济会员密码),是一种以格子为基础的简单替代式密码。即使使用符号,也不会影响密码分析,亦可用在其它替代式的方法。
代码:
def encipher(txt):
pigpen_dict = {'a': 'j', 'b': 'k', 'c': 'l', 'd': 'm', 'e': 'n', 'f': 'o', 'g': 'p', 'h': 'q', 'i': 'r',
'j': 'a', 'k': 'b', 'l': 'c', 'm': 'd', 'n': 'e', 'o': 'f', 'p': 'g', 'q': 'h', 'r': 'i',
's': 'w', 't': 'x', 'u': 'y', 'v': 'z', 'w': 's', 'x': 't', 'y': 'u', 'z': 'v'}
result = ""
txt = txt.lower()
for i in txt:
try:
result = result + pigpen_dict[i]
except KeyError:
result = result + i
return result
if __name__ == '__main__':
x = encipher("hello world")
print(x)
输出:
qnccf sficm
9.Vigenere(维吉尼亚加密)
维吉尼亚密码(又译维热纳尔密码)是使用一系列凯撒密码组成密码字母表的加密算法,属于多表密码的一种简单形式。
在一个凯撒密码中,字母表中的每一字母都会作一定的偏移,例如偏移量为3时,A就转换为了D、B转换为了E……而维吉尼亚密码则是由一些偏移量不同的恺撒密码组成。
为了生成密码,需要使用表格法。这一表格(如图1所示)包括了26行字母表,每一行都由前一行向左偏移一位得到。具体使用哪一行字母表进行编译是基于密钥进行的,在过程中会不断地变换。
例如,假设明文为:
ATTACKATDAWN
选择某一关键词并重复而得到密钥,如关键词为LEMON时,密钥为:
LEMONLEMONLE
对于明文的第一个字母A,对应密钥的第一个字母L,于是使用表格中L行字母表进行加密,得到密文第一个字母L。类似地,明文第二个字母为T,在表格中使用对应的E行进行加密,得到密文第二个字母X。以此类推,可以得到:
明文:ATTACKATDAWN
密钥:LEMONLEMONLE
密文:LXFOPVEFRNHR
代码:
letter_list = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' # 字母表
# 根据输入的key生成key列表
def get_key_list(k):
k_list = []
for ch in k:
k_list.append(ord(ch.upper()) - 65)
return k_list
# 加密
def encipher(txt, k):
result = ""
k_list = get_key_list(k)
i = 0
for ch in txt: # 遍历明文
if 0 == i % len(k_list):
i = 0
if ch.isalpha(): # 明文是否为字母,如果是,则判断大小写,分别进行加密
if ch.isupper():
result += letter_list[(ord(ch) - 65 + k_list[i]) % 26]
i += 1
else:
result += letter_list[(ord(ch) - 97 + k_list[i]) % 26].lower()
i += 1
else: # 如果密文不为字母,直接添加到密文字符串里
result += ch
return result
# 解密
def decipher(txt, k):
result = ""
k_list = get_key_list(k)
i = 0
for ch in txt: # 遍历密文
if 0 == i % len(k_list):
i = 0
if ch.isalpha(): # 密文为否为字母,如果是,则判断大小写,分别进行解密
if ch.isupper():
result += letter_list[(ord(ch) - 65 - k_list[i]) % 26]
i += 1
else:
result += letter_list[(ord(ch) - 97 - k_list[i]) % 26].lower()
i += 1
else: # 如果密文不为字母,直接添加到明文字符串里
result += ch
return result
if __name__ == '__main__':
key = 'computer'
plaintext = "hello world"
ciphertext = encipher(plaintext, key)
print(ciphertext)
ciphertext = 'jsxai psinr'
plaintext = decipher(ciphertext, key)
print(plaintext)
输出:
jsxai psinr
hello world