古典密码(部分合集)


古典密码

  • 一. 移位密码
    • 1. 简单移位密码
    • 2. 曲路密码
    • 3. 云影密码
    • 4. 栅栏密码
  • 二. 代替密码
    • 单表代替密码
      • 1.凯撒密码
      • 2.ROT13
      • 3.埃特巴什密码
      • 4.经典单表替代密码
      • 5.摩斯密码
      • 6.培根密码
      • 7.图形替换密码
        • 猪圈密码
        • 圣堂武士密码
        • 标准银河密码
      • 8.仿射密码
    • 多表代替密码
      • 1.棋盘密码
        • Playfair
        • Polybius
        • ADFGX
        • ADFGVX
      • 2.维吉尼亚密码

古典密码在形式上可分为移位密码和替换密码两类,其中代替密码又可分为单表替换和多表替换。
一. 移位密码 1. 简单移位密码 可以理解为明文根据密钥进行了位置的变换而得到的密文。
例如:
? 明文:m = flag{easy_easy_crypto}
? 密钥:k = 3124
? 则明文将以k的长度进行分割,得到如下
? flag {eas y_ea sy_c rypt o}
? 然后按照密钥3124的顺序进行替换。得到如下
? lafg ea{s _eya y_sc yprt }o
? 所以密文为lafgea{s_eyay_scyprt}o
脚本如下:
#加密txt=input('明文:').strip() key=input('密钥:').strip() t=len(key) mi='' for i in range(0,len(txt),t): if i+t>len(txt): temp=txt[i:] else: temp=txt[i:i+t] '''#法一 pd=dict(zip(key,temp)) pd=dict(sorted(pd.items(),key=lambda x:x[0]))#根据关键字的大小进行排序 for j in range(1,t+1): if str(j) in pd: mi+=pd.get(str(j)) '''#法二 c = ['']*t for j in range(len(temp)): c[int(key[j])-1] = temp[j] mi += ''.join(c) print(mi)#解密 txt=input('密文:').strip() key=input('密钥:').strip() t=len(key) m=''for i in range(0,len(txt),t): c = ['']*t if i+t>len(txt): temp=txt[i:] use = [] for j in range(len(temp)): use.append(int(key[j]) - 1) use.sort()#相当于压缩掉空的位置,但字母排列的相对顺序不变 for j in range(len(temp)): c[j] = temp[use.index(int(key[j])-1)]#字符原排列所在的位置相当于sort之后所在的位置 else: temp=txt[i:i+t] for j in range(len(temp)): c[j] = temp[int(key[j]) - 1] m += ''.join(c)print(m)

2. 曲路密码 将明文填入一个表中,并按照一定的曲路遍历。
例如:this is a test text
古典密码(部分合集)
文章图片

得到密文“istxettsthiseta”
3. 云影密码 云影密码仅包含01248五个数字,其中0用于分割,其余数字用于做加和操作之后转换为明文。
例如:
? 8842101220480224404014224202480122
? 去除0之后为:88421 122 48 2244 4 142242 248 122
? 每组累加之后为: 23 5 12 12 4 15 14 5
? 根据密码表“abcdefghijklmnopqrstuvwxyz”,数字即为字符下标。
解密脚本:
def c01248_decode(c): txt = c.split('0') temp = 'abcdefghijklmnopqrstuvwxyz' m = '' for i in txt: pd = 0 for j in i: pd += int(j) m += temp[pd-1] return mm = input().strip() print(c01246_decode(m))

4. 栅栏密码 ? 把明文分成n个一组,然后把每组的第一个字符连起来,形成一段无规律的字符。
? 例:明文为‘wearefamily’,密钥为4,先用密钥’4’将明文每4个字符分为一组’wear||efam||ily’,然后依次取出每组第1,2,3个字符,组为’wei|efl||aay||rm’,再连接起来就可以得到密文’weieflaarm’。
? 加密解密脚本:
? 如果知道密钥(n)和密文(长度m),其中m%n==0,那么明文就为密文按照密钥为m/n进行栅栏加密的结果。
#均分的 txt = input().strip() m = len(txt) for i in range(2,m): if m%i == 0: print(f'{ i}栏加密/解密:',end = '') for j in range(i): for k in range(j,m,i): print(txt[k],end = '') print()#不均分的 txt = input().strip() m = len(txt) for i in range(2,m): print(f'{ i}栏加密/解密:',end = '') for j in range(i): for k in range(j,m,i): print(txt[k],end = '') print()

[栅栏密码加解密](栅栏加密/解密 - Bugku CTF)
二. 代替密码 单表代替密码 1.凯撒密码
? 典型的替换密码。加密原理是把明文中所有的英文字母都在字母表中向后(或向前)按照一个固定 数目进行移位后替换成密文,而数字和非字母字符则保持不变。凯撒密码只有25种可能的密钥。
? 公式: x代表明文,y代表密文,k代表密钥
? 加密:(x+k)%26
? 解密:(y-k)%26
? [凯撒加解密](凯撒(Caesar)加密/解密 - Bugku CTF)
? 加密脚本:
txt = input('请输入明文:').strip() n = int(input('请输入密钥(正为右移,负为左移):')) miwen = '' for i in txt: if i.islower(): miwen += chr((ord(i) - 97 + n)%26 + 97) elif i.isupper() : miwen += chr((ord(i) - 65 + n)%26 + 65) else: miwen += i print('密文:'+miwen)

?
? 解密脚本:
? 方法1:
txt = input().strip() table = ('is','ok','flag','the','ctf','to','no','for','good','key') for i in range(1,26): plain = '' for j in txt: if j.islower(): plain += chr((ord(j) - 97 + i)%26 + 97) elif j.isupper(): plain += chr((ord(j) - 65 + i)%26 + 65) else: plain += j for k in table: if k in plain: print('明文可能是:',end = '') break print(plain) print()

? 方法2:
txt = input().strip() big = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' low = 'abcdefghijklmnopqrstuvwxyz' table = ('is','ok','flag','the','ctf','to','no','for','good','key') for i in range(1,26): xiao = low[i:] + low[:i]# da = big[i:] + big[:i]#根据密钥往前移位,做出替换表 tran = ''.maketrans(da + xiao,big + low) plain = '' for j in txt: plain += j.translate(tran) for k in table: if k in plain: print('明文可能是:',end = '') break print(plain) print()

2.ROT13
? 移位数固定为13,即明文中的每个字母在字母表中向后移动13位,数字和非字母字符保持不变。
? 解密脚本:
txt = input().strip() big = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' low = 'abcdefghijklmnopqrstuvwxyz' xiao = low[13:] + low[:13] da = big[13:] + big[:13] tran = ''.maketrans(da + xiao,big + low) plain = '' for i in txt: plain += i.translate(tran) print(plain)

3.埃特巴什密码
? 替换表:
? ABCDEFGHIJKLMNOPQRSTUVWXYZ
? ZYXWVUTSRQPONMLKJIHGFEDCBA
txt = input().strip().lower()L1 = 'abcdefghijklmnopqrstuvwxyz' L2 = 'zyxwvutsrqponmlkjihgfedcba' tran = ''.maketrans(L1,L2) m = '' for i in txt: if i.isalpha() == True: m += i.translate(tran) else: m += i print(m)

4.经典单表替代密码
? 经典的单表代替密码就是用一个代替表对每一个位置的字符进行查表替换。
? 例如:
? abcdefghijklmnopqrstuvwxyz
? zugxjitlrkywdhfbnvosepmacq
? 若替换表没给出,但密文足够长,可以使用[词频分析](quipqiup - cryptoquip and cryptogram solver);若给出替换表,可写脚本破译。
5.摩斯密码
? 由 . - 构成密码表( . - 也可以由其他字母或数字所替换,例:0 1)
? 但由于密码表中只存放了一些基本字母,一般解出的明文并不是正确的。可以通过编写脚本扩展密码表。
? 脚本:
txt = input().strip()if '.' in txt: table = ''.maketrans('.-','01')#映射表'.'->'0','-'->'1' txt = txt.translate(table)#替换txt中的'.','-' #table = ''.maketrans('.-','10') #txt = translate(table) if ' ' in txt:#以空格或/为分隔符,转化成列表 txt = txt.split() elif '/' in txt: txt = txt.split('/')key = { '01':'A','1000':'B','1010':'C','100':'D','0':'E','0010':'F', '110':'G','0000':'H','00':'I','0111':'J','101':'K','0100':'L', '11':'M','10':'N','111':'O','0110':'P','1101':'Q','010':'R', '000':'S','1':'T','001':'U','0001':'V','011':'W','1001':'X', '1011':'Y','1100':'Z','01111':'1','00111':'2','00011':'3','00001':'4', '00000':'5','10000':'6','11000':'7','11100':'8','11110':'9','11111':'0', '001100':'?','10010':'/','101101':'()','100001':'-','010101':'.','110011':',' ,'011010':'@','111000':':','101010':'; ','10001':'=','011110':"'",'101011':'!', '001101':'_','010010':'"','10110':'(','101101':')','1111011':'{','1111101':'}'}for i in txt: print(key.get(i),end = '')#用key[i]的话,若在字典中没有找到则会报错,但key.get(i)会直接忽略 print()

6.培根密码
? 密文字符只有两个:a,b,每个明文都会被替换成由a和b所组成的长度为5的字符串。(密文字符也可以是任意两个其他字符,类似摩斯密码)
? 实际上密文可以改成由大小写字母组成,可以把A看成是大写字母,B是小写字母(或A是小写字母,B是大写字母)
? 古典密码(部分合集)
文章图片

古典密码(部分合集)
文章图片

加解密网站:
在线工具|培根密码加解密 (bugku.com)
Baconian Cipher (rumkin.com)
脚本:
? 1)只含a/A,b/B的密文
txt = input().strip().lower() #一 一对应 key = { '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'} #非一 一对应 ((ij) ,(uv)) ''' key = {'aaaaa':'a','aaaab':'b','aaaba':'c','aaabb':'d','aabaa':'e','aabab':'f', 'aabba':'g','aabbb':'h','abaaa':'(ij)','abaab':'k','ababa':'l','ababb':'m', 'abbaa':'n','abbab':'o','abbba':'p','abbbb':'q','baaaa':'r','baaab':'s', 'baaba':'t','baabb':'(uv)','babaa':'w','babab':'x','babba':'y','babbb':'z'} ''' for i in range(0,len(txt),5):#划分,每5个字母对应一个明文 print(key.get(txt[i:i + 5]),end = '') print()

? 2)语句胡乱大小写的
txt = input().replace(' ','').strip() ming = '' for i in txt: if i .islower(): ming += 'a' elif i.isupper(): ming += 'b' #一 一对应 key = { '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'} #非一 一对应(ij ,uv) ''' key = {'aaaaa':'a','aaaab':'b','aaaba':'c','aaabb':'d','aabaa':'e','aabab':'f', 'aabba':'g','aabbb':'h','abaaa':'(ij)','abaab':'k','ababa':'l','ababb':'m', 'abbaa':'n','abbab':'o','abbba':'p','abbbb':'q','baaaa':'r','baaab':'s', 'baaba':'t','baabb':'(uv)','babaa':'w','babab':'x','babba':'y','babbb':'z'} ''' for i in range(0,len(ming),5):#划分,每5个字母对应一个明文 print(key.get(ming[i:i + 5]),end = '') print()table = ''.maketrans('ab','ba') ming = ming.translate(table)#大小写对应的字母交换 for i in range(0,len(ming),5): print(key.get(ming[i:i + 5]),end = '') print()

7.图形替换密码
猪圈密码 古典密码(部分合集)
文章图片

圣堂武士密码 古典密码(部分合集)
文章图片

标准银河密码 古典密码(部分合集)
文章图片

8.仿射密码
? 仿射密码是将明文与密钥的一部分相乘,然后再加上密钥的另一部分。
  • ? 为便于计算,将26个英文字母用数字表示:a=0,b=1,…,z=25。
  • ? 仿射加密的密钥有两个:a和b,取值范围都是[0,25]。
  • 【古典密码(部分合集)】? a要求与26互质(两个数的公因数只有1)。
  • ? x是明文,y是密文
    ? 加密公式:y=(a*x+b)%26
    ? 解密:x=(y-b)/a%26=(y-b)*****a^(-1)%26=(y-b)*m%26
    ? 其中m是a的逆元,即m*****a=a^(-1)*a =1
#y=(a*x+b)%26 a = int(input('请输入a:')) b = int(input('请输入b:')) txt = input('请输入密文:').strip() m = 1#m是a的逆元,即m*a=1 while True: if m*a%26 == 1: break; m += 1 for i in txt: if i.islower(): print(chr( 97 + ( ord(i) - 97 - b ) * m % 26 ),end = '') elif i.isupper(): print(chr( 65 + ( ord(i) - 65 - b ) * m % 26 ),end = '') else: print(i,end = '') print()

多表代替密码 1.棋盘密码
Playfair ? 密码表共5行5列,第一行(或第一列)是密钥,其余按照字母顺序。密钥中若有重复字母,则可将后面重复的字母去掉。同时i和j会被当作一个字母。
? 首先将明文字母两两一组进行切分,并按照如下规则进行加密:
? 1)若两个字母不同行也不同列,则需要在矩阵中找到另外两个字母(第一个字母对应行优先)。使这四个字母成为一个长方形的四个角。
? 2)若两个字母同行,则取这两个字母右方的字母(若字母在最右方则取最左方的字母)。
? 3)若两个字母同列,则取这两个字母下方的字母(若字母在最下方则取最上方的字母)。
解密时则方向反过来。
解密脚本
加解密网站:[Playfair](Playfair Cipher (rumkin.com))
Polybius ? 利用Polybius棋盘进行明文加密,加密结果为每个字母所在方阵中的坐标。
?
古典密码(部分合集)
文章图片

?
import itertoolstxt = input('密文:').strip() key = input('密钥:').strip()sumkey = [] result = []for i in itertools.permutations(key,5):#密钥的全排序 sumkey.append(''.join(i))for i in sumkey: temp = '' for j in txt: temp += str(i.index(j)) result.append(temp)for i in result: ming = '' for j in range(0,len(i),2): x = (int(i[j]))*5 + int(i[j+1]) + 1 + 96 if x > ord('i'): x += 1 ming += chr(x) print(ming)

ADFGX ? 古典密码(部分合集)
文章图片

ADFGVX 古典密码(部分合集)
文章图片

?
2.维吉尼亚密码
? 利用一个密钥,将密钥的每一位转换为数字(一般转化为字母表对应顺序的数字),再分别以这一数字为密钥加密明文的每一位字母。
[维吉尼亚加解密](维吉尼亚加密/解密 - Bugku CTF)
txt = input('密文:').strip() key = input('密钥:').strip()replace(' ','') table = '' m = len(key) for i in key:#将密钥中的字母转换成数字字符串 if i.islower(): table += str(ord(i) - 97) elif i.isupper(): table += str(ord(i) - 65) else: table += i#i为数字字符 t = 0#方便密钥循环 for i in txt: if i.islower(): print(chr(97 + ( ord(i) - 97 - int( table[t % m]) ) % 26 ),end = '') t+=1 elif i.isupper(): print(chr(65 + ( ord(i) - 65 - int( table[t % m] ) ) % 26 ),end = '') t += 1 else: print(i,end = '') print()

    推荐阅读