python(N1CTF)
本题要点: Feistel加密结构、 DES算法、AES算法
代码如下:
1 from N1ES import N1ES 2 import base64 3 key = "wxy191iss00000000000cute" 4 n1es = N1ES(key) 5 flag = "N1CTF{*****************************************}" 6 cipher = n1es.encrypt(flag) 7 print base64.b64encode(cipher) # HRlgC2ReHW1/WRk2DikfNBo1dl1XZBJrRR9qECMNOjNHDktBJSxcI1hZIz07YjVx
代码如下:
# -*- coding: utf-8 -*- def round_add(a, b): f = lambda x, y: x + y - 2 * (x & y) res = '' for i in range(len(a)): res += chr(f(ord(a[i]), ord(b[i]))) return res def permutate(table, block): return list(map(lambda x: block[x], table)) def string_to_bits(data): data = [ord(c) for c in data] l = len(data) * 8 result = [0] * l pos = 0 for ch in data: for i in range(0,8): result[(pos<<3)+i] = (ch>>i) & 1 pos += 1 return result s_box = [54, 132, 138, 83, 16, 73, 187, 84, 146, 30, 95, 21, 148, 63, 65, 189, 188, 151, 72, 161, 116, 63, 161, 91, 37, 24, 126, 107, 87, 30, 117, 185, 98, 90, 0, 42, 140, 70, 86, 0, 42, 150, 54, 22, 144, 153, 36, 90, 149, 54, 156, 8, 59, 40, 110, 56,1, 84, 103, 22, 65, 17, 190, 41, 99, 151, 119, 124, 68, 17, 166, 125, 95, 65, 105, 133, 49, 19, 138, 29, 110, 7, 81, 134, 70, 87, 180, 78, 175, 108, 26, 121, 74, 29, 68, 162, 142, 177, 143, 86, 129, 101, 117, 41, 57, 34, 177, 103, 61, 135, 191, 74, 69, 147, 90, 49, 135, 124, 106, 19, 89, 38, 21, 41, 17, 155, 83, 38, 159, 179, 19, 157, 68, 105, 151, 166, 171, 122, 179, 114, 52, 183, 89, 107, 113, 65, 161, 141, 18, 121, 95, 4, 95, 101, 81, 156, 17, 190, 38, 84, 9, 171, 180, 59, 45, 15, 34, 89, 75, 164, 190, 140, 6, 41, 188, 77, 165, 105, 5, 107, 31, 183, 107, 141, 66, 63, 10, 9, 125, 50, 2, 153, 156, 162, 186, 76, 158, 153, 117, 9, 77, 156, 11, 145, 12, 169, 52, 57, 161, 7, 158, 110, 191, 43, 82, 186, 49, 102, 166, 31, 41, 5, 189, 27] def generate(o): k = permutate(s_box,o) b = [] for i in range(0, len(k), 7): b.append(k[i:i+7] + [1]) c = [] for i in range(32): pos = 0 x = 0 for j in b[i]: x += (j<<pos) pos += 1 c.append((0x10001**x) % (0x7f)) return c class N1ES: def __init__(self, key): if (len(key) != 24 or isinstance(key, bytes) == False ): raise Exception("key must be 24 bytes long") self.key = key self.gen_subkey() def gen_subkey(self): o = string_to_bits(self.key) k = [] for i in range(8): o = generate(o) k.extend(o) o = string_to_bits([chr(c) for c in o[0:24]]) self.Kn = [] for i in range(32): self.Kn.append(map(chr, k[i * 8: i * 8 + 8])) return def encrypt(self, plaintext): if (len(plaintext) % 16 != 0 or isinstance(plaintext, bytes) == False): raise Exception("plaintext must be a multiple of 16 in length") res = '' for i in range(len(plaintext) / 16): block = plaintext[i * 16:(i + 1) * 16] L = block[:8] R = block[8:] for round_cnt in range(32): L, R = R, (round_add(L, self.Kn[round_cnt])) L, R = R, L res += L + R return res
从两个文件的代码可以判断:
N1ES.py是封装好的类, challenge.py是定义的对象。
先来解释一下:
一、什么是Feistel加密结构?
构造过程:
令F 为轮函数;令K1,K2,……,Kn 分别为第1,2,……,n 轮的子密钥。那么基本构造过程如下:
(1)将明文信息均分为两块:(L0,R0);
(2)在每一轮中,进行如下运算(i 为当前轮数):
Li+1 = Ri;
Ri+1 = Li ⊕F (Ri,Ki)。(其中⊕为异或操作)
所得的结果即为:(Ri+1,Li+1)。
解密过程:
对于密文(Rn+1,Ln+1),我们将i 由n 向0 进行,即, i = n,n-1,……,0。然后对密文进行加密的逆向操作,如下:
(1)Ri = Li+1;
(2)Li = Ri+1⊕F (Li+1,Ki)。(其中⊕为异或操作)
所得结果为(L0,R0),即原来的明文信息。
(图片摘自百度百科)
Feistel 密码结构,在密码学研究中,Feistel 密码结构是用于分组密码中的一种对称结构。
Feistel 的优点:由于它是对称的密码结构,所以对信息的加密和解密的过程就极为相似,甚至完全一样。这就使得在实施的过程中,对编码量和线路传输的要求就减少了几乎一半。
二、什么是des算法?
DES(Data Encryption Standard)是目前最为流行的加密算法之一。
DES是对称的,也就是说它使用同一个密钥来加密和解密数据。
DES还是一种分组加密算法,该算法每次处理固定长度的数据段,称之为分组。
DES分组的大小是64位,如果加密的数据长度不是64位的倍数,可以按照某种具体的规则来填充位。
算法原理:
1.输入64位明文数据,并进行初始置换IP。
2.在初始置换IP后,明文数据再被分为左右两部分,每部分32位,以L0,R0表示。
3.在秘钥的控制下,经过16轮运算(f)。
4.16轮后,左、右两部分交换,并连接再一起,再进行逆置换。
5.输出64位密文。
三、什么是AES算法?
AES的全称是Advanced Encryption Standard,意思是高级加密标准。
AES的出现主要是为了取代DES加密算法的,因为我们都知道DES算法的密钥长度是56Bit,因此算法的理论安全强度是2的56次方。
算法流程:
介绍完成。
(密码学是真的难学! )
challenge.py中:
HRlgC2ReHW1/WRk2DikfNBo1dl1XZBJrRR9qECMNOjNHDktBJSxcI1hZIz07YjVx 为密文。
参考这位大佬的解密代码如下:
(本人太菜,写不出来,QAQ)
# -*- coding: utf-8 -*- import base64 def round_add(a,b): f = lambda x,y: x + y - 2 * (x & y) res = '' for i in range(len(a)): res += chr(f(ord(a[i]),ord(b[i]))) return res def permutate(table,block): return list(map(lambda x: block[x], table)) def string_to_bits(data): data = [ord(c) for c in data] l = len(data)*8 result = [0] * l pos = 0 for ch in data: for i in range(0,8): result[(pos<<3)+i] = (ch>>i) & 1 pos += 1 return result s_box = [54, 132, 138, 83, 16, 73, 187, 84, 146, 30, 95, 21, 148, 63, 65, 189, 188, 151, 72, 161, 116, 63, 161, 91, 37, 24, 126, 107, 87, 30, 117, 185, 98, 90, 0, 42, 140, 70, 86, 0, 42, 150, 54, 22, 144, 153, 36, 90, 149, 54, 156, 8, 59, 40, 110, 56,1, 84, 103, 22, 65, 17, 190, 41, 99, 151, 119, 124, 68, 17, 166, 125, 95, 65, 105, 133, 49, 19, 138, 29, 110, 7, 81, 134, 70, 87, 180, 78, 175, 108, 26, 121, 74, 29, 68, 162, 142, 177, 143, 86, 129, 101, 117, 41, 57, 34, 177, 103, 61, 135, 191, 74, 69, 147, 90, 49, 135, 124, 106, 19, 89, 38, 21, 41, 17, 155, 83, 38, 159, 179, 19, 157, 68, 105, 151, 166, 171, 122, 179, 114, 52, 183, 89, 107, 113, 65, 161, 141, 18, 121, 95, 4, 95, 101, 81, 156, 17, 190, 38, 84, 9, 171, 180, 59, 45, 15, 34, 89, 75, 164, 190, 140, 6, 41, 188, 77, 165, 105, 5, 107, 31, 183, 107, 141, 66, 63, 10, 9, 125, 50, 2, 153, 156, 162, 186, 76, 158, 153, 117, 9, 77, 156, 11, 145, 12, 169, 52, 57, 161, 7, 158, 110, 191, 43, 82, 186, 49, 102, 166, 31, 41, 5, 189, 27] def generate(o): k = permutate(s_box,o) b = [] for i in range(0,len(k),7): b.append(k[i:i+7]+[1]) c = [] for i in range(32): pos = 0 x = 0 for j in b[i]: x += (j<<pos) pos += 1 c.append((0x10001**x) % (0x7f)) return c class N1ES: def __init__(self,key): if (len(key) != 24 or isinstance(key,bytes) == False): raise Exception("key must be 24 bytes long") self.key = key self.gen_subkey() def gen_subkey(self): o = string_to_bits(self.key) k = [] for i in range(8): o = generate(o) k.extend(o) o = string_to_bits([chr(c) for c in o[0:24]]) self.Kn = [] for i in range(32): self.Kn.append(map(chr,k[i*8: i*8+8])) return def decrypt(self,plaintext): res = '' for i in range(len(plaintext)/16): block = plaintext[i*16:(i + 1)*16] L = block[:8] R = block[8:] for round_cnt in range(32): L,R = R, (round_add(L, self.Kn[31-round_cnt])) L,R = R,L res += L + R return res key = "wxy191iss00000000000cute" nles = N1ES(key) flag = base64.b64decode("HRlgC2ReHW1/WRk2DikfNBo1dl1XZBJrRR9qECMNOjNHDktBJSxcI1hZIz07YjVx") flag = nles.decrypt(flag) print flag
注:
这段代码的运行环境为py2哦~
py3运行会报错~
(然而突然发觉自己没装py2的环境.....假如你也没装,我们可以用菜鸟工具的python的在线运行网站运行啦~哈哈哈哈)
菜鸟工具的python的在线运行网站:
https://c.runoob.com/compile/6
如果你有py2的环境,你也可以这样操作:
解密的源码(参考自N1CTF baby_N1ES writeup):
import base64,string,N1ES key = "wxy191iss00000000000cute" c = base64.b64decode("HRlgC2ReHW1/WRk2DikfNBo1dl1XZBJrRR9qECMNOjNHDktBJSxcI1hZIz07YjVx") n1es = N1ES.N1ES(key) f="" for i in xrange(3): for j in xrange(16): for k in string.printable: s="x"*i*16+"x"*j+k+"x"*(48-i*16-j-1) e=n1es.encrypt(s) check=c[i*16+j+8]==e[i*16+j+8] if j<8 else c[i*16+j-8]==e[i*16+j-8] if check: f+=k break print f
把题目中给的两个py文件和解密的源码放在同一个文件夹下,然后运行cmd,就可以得到同样的答案啦~
提交:
N1CTF{F3istel_n3tw0rk_c4n_b3_ea5i1y_s0lv3d_/--/}
bingo~
参考资料:
https://bbs.pediy.com/thread-253884.htm
https://baike.baidu.com/item/des算法/10306073?fr=aladdin
https://blog.csdn.net/prowes5/article/details/85167667
https://findneo.github.io/180310N1CTFWP/