原理&簡介
四方密碼是一種對稱式加密法,由法國人Felix Delastelle發明。這種方法將字母兩個一組,然後採用多字母替換密碼。四方密碼用4個5×5的矩陣來加密。每個矩陣都有25個字母。
英文中有26個字母,所以一般是去掉其中的Q或者將i和j當做一樣。
四方密碼有4個矩陣(有兩個祕鑰矩陣,兩個順序矩陣)。
加密
可以選取兩個英文作爲兩個祕鑰,例如hello和world,去除其中相同的字母,於是祕鑰變成了helo和world。
將第一個祕鑰矩陣放在右上角,第二個祕鑰矩陣放在左下角,兩個順序矩陣分別放在左上角和右下角,如下圖:
例如我們要對字符串“I am not a drug god”進行加密,首先將明文分組,分爲“ia m not ad rug g od”,找出分組中第一個字母在左上角矩陣的位置i(二行四列),第二個字母在右下角矩陣的位置a(一行一列),第一個密文爲第一個字母的行號和第二個字母的列號B(二行一列),第二個密文爲第一個字母的列號和第二個字母的行號L(一行四列),如下圖所示,正好是個四方的形狀:
使用python編寫加密腳本如下:
#coding:utf-8 import collections import re matrix = "ABCDEFGHIJKLMNOPRSTUVWXYZ" pla = "abcdefghijklmnoprstuvwxyz" key1 = "[HELLO]" key2 = "[WORLD]" key1 = ''.join(collections.OrderedDict.fromkeys(key1)) key2 = ''.join(collections.OrderedDict.fromkeys(key2)) matrix1 = re.sub('[\[\]]','',key1) + re.sub(key1,'',matrix) matrix2 = re.sub('[\[\]]','',key2) + re.sub(key2,'',matrix) matrix_list1 = [] matrix_list2 = [] pla_list = [] for i in range(0,len(matrix1),5): matrix_list1.append(list(matrix1[i:i+5])) #print matrix_list1 for i in range(0,len(matrix2),5): matrix_list2.append(list(matrix2[i:i+5])) #print matrix_list2 for i in range(0,len(pla),5): pla_list.append(list(pla[i:i+5])) #print pla_list #查詢明文字母位置 def find_index(x): for i in range(len(pla_list)): for j in range(len(pla_list[i])): if pla_list[i][j] == x: return i,j def gen_cip(letter): #兩個子母中第一個字母位置 first = find_index(letter[0]) #兩個子母中第二個字母位置 second = find_index(letter[1]) cip = "" cip += matrix_list1[first[0]][second[1]] cip += matrix_list2[second[0]][first[1]] return cip def encrypt(pla): #pla = "whereismysecretkey" cip = "" for i in range(0,len(pla),2): cip += gen_cip(pla[i:i+2]) return cip def main(): pla = "i am not a drug god" pla = pla.replace(' ','') print encrypt(pla) if __name__ == "__main__": main()
運行結果如下:
解密:
同樣是將密文分組,找出分組中第一個字母在右上角矩陣的位置B(二行一列),第二個字母在左下角矩陣的位置L(一行四列),第一個明文爲第一個字母的行號和第二個字母的列號i(二行四列),第二個明文爲第一個字母的列號和第二個字母的行號a(一行一列),如下圖所示:
使用python編寫解密腳本如下:
#coding:utf-8 import collections import re matrix = "ABCDEFGHIJKLMNOPRSTUVWXYZ" pla = "abcdefghijklmnoprstuvwxyz" key1 = "[HELLO]" key2 = "[WORLD]" key1 = ''.join(collections.OrderedDict.fromkeys(key1)) key2 = ''.join(collections.OrderedDict.fromkeys(key2)) matrix1 = re.sub('[\[\]]','',key1) + re.sub(key1,'',matrix) matrix2 = re.sub('[\[\]]','',key2) + re.sub(key2,'',matrix) matrix_list1 = [] matrix_list2 = [] pla_list = [] for i in range(0,len(matrix1),5): matrix_list1.append(list(matrix1[i:i+5])) #print matrix_list1 for i in range(0,len(matrix2),5): matrix_list2.append(list(matrix2[i:i+5])) #print matrix_list2 for i in range(0,len(pla),5): pla_list.append(list(pla[i:i+5])) #print pla_list #查詢兩個密文字母位置 def find_index1(x): for i in range(len(matrix_list1)): for j in range(len(matrix_list1[i])): if matrix_list1[i][j] == x: return i,j def find_index2(y): for k in range(len(matrix_list2)): for l in range(len(matrix_list2[k])): if matrix_list2[k][l] == y: return k,l def gen_pla(letter): #兩個子母中第一個字母位置 first = find_index1(letter[0]) #兩個子母中第二個字母位置 second = find_index2(letter[1]) pla = "" pla += pla_list[first[0]][second[1]] pla += pla_list[second[0]][first[1]] return pla def main(): cip = "BLMIMTOWUNCBMD" pla = "" for i in range(0,len(cip),2): pla += gen_pla(cip[i:i+2]) print pla if __name__ == "__main__": main()
運行結果如下:
安恆杯10月月賽“四四方方一座城”解析:
題目:
分析可知:
祕鑰又被加密了,Offset未知,但是我們可以遍歷大小寫字母的ascii碼值經過異或和按位與運算之後的最大值、最小值(192,255),還有遍歷enc_key的ascii碼值的最大值和最小值(76,106),可以大概推算Offset的值,肯定爲負數,範圍可以暫時定在(-179,-86),在遍歷過程中可以再做調整,由此可以遍歷出正確的Offset值。
代碼:
enc_key1 = "VXYjj" key1 = "" for Offset in range(90,150): for i in enc_key1: key1 += chr((ord(i) + Offset) ^ 0xff & 0xaf) print key1 key1 = ""
結果:
經過遍歷,Offset值爲-149,從而推算出key值。
key1爲:DBAPP
Key2爲:LINKEDBYX
題目標題爲“四四方方一座城”,有一個密碼叫四方密碼,正好是有兩個祕鑰,通過四個矩陣(兩個祕鑰矩陣,兩個順序矩陣)來加密一些信息。
對於本題中的祕鑰,矩陣是這樣的,如下圖所示:
前兩個密文字母爲“XB”,解出明文爲“wh”:對應矩陣如下:
根據上述解密原理,可以算出flag,利用上邊的腳本,將密文和祕鑰替換,運行得到flag
最後將得到的字符串進行md5加密提交即可