周六作了两个N1CTF感觉很难就没做,有些东西只是不懂,不是很难。
这个题就是其一
题目会给出一道2乘幂的题
POW: 2^(2^168650911) mod 14410422756791856006977221261653848398173123908149127966358804284026606184669 = ?
一开始想最后是取模,根据费小有a**(p-1)=1 (mod p),然后用公式求解
- powmod(2,pow(2,bit,p-1),p)
- #4661732238801194169405982400350387428895918512377690837157075128714991112731
但是这个事有点麻烦,p不是素数,如果乘幂又太大了,后来看别人作的,用了bit_set这个函数,原来都没听说过,因为底是2,直接置bit位就行了
所以正确的解法是
- powmod(2,bit_set(0,bit),p)
- #36808033546212382710607382805842490500296061506256519355047811358611503260
不过只是当时卡在这了,不有另外一个方法,不用这个函数一样
- powmod(2,1<
- #36808033546212382710607382805842490500296061506256519355047811358611503260
baby_N1ES
这个题都没看到,其实这个题很简单,而且还有更简单的解法。
原题
- from N1ES import N1ES
- import base64
- key = "wxy191iss00000000000cute"
- n1es = N1ES(key)
- flag = "N1CTF{*****************************************}"
- cipher = n1es.encrypt(flag)
- print base64.b64encode(cipher) # HRlgC2ReHW1/WRk2DikfNBo1dl1XZBJrRR9qECMNOjNHDktBJSxcI1hZIz07YjVx
和一个N1ES.py的库
- # -*- 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
先读题,就是个分段加密,每次原来的左与Kn异或然后左右互换,作32轮。由于Kn是固定的,而且加密是异或,所以round_add并不需要处理,只要反过来作个decrypt就行了
这有个小坑,python 2的程序需要改一下
- # -*- coding: utf-8 -*-
- def round_add(a, b): #xor
- f = lambda x, y: x + y - 2 * (x & y)
- res = b''
- for i in range(len(a)):
- #res += chr(f(ord(a[i]), ord(b[i])))
- res += bytes([f(a[i], 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]
- data = [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]])
- o = string_to_bits([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]))
- self.Kn.append(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 = b''
- 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
-
- def decrypt(self, plaintext):
- #if (len(plaintext) % 16 != 0 or isinstance(plaintext, bytes) == False):
- # raise Exception("plaintext must be a multiple of 16 in length")
- res = b''
- 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 = (round_add(R, self.Kn[round_cnt])), L
- L, R = R, L
- res += L + R
- return res
-
然后直接解密
- from N1ES import N1ES
- import base64
-
- key = b"wxy191iss00000000000cute"
- n1es = N1ES(key)
- t = base64.b64decode('HRlgC2ReHW1/WRk2DikfNBo1dl1XZBJrRR9qECMNOjNHDktBJSxcI1hZIz07YjVx')
- print(n1es.decrypt(t))
- #b'N1CTF{F3istel_n3tw0rk_c4n_b3_ea5i1y_s0lv3d_/--/}'
不过今天看了个WP,还有更简单的方法,这个东西是个循环,直接再加密,而且3次就循环,太容易了
- for i in range(3):
- t = n1es.encrypt(t)
- print(t)
没作,也没保存确实可惜了,只是那个checkin没作出来。