N1es.py
challenge.py
题中有两个文件,一个是封装好的N1ES.py,另一个是challenge.py,通过调用n1se实现加密操作。
逐步分析其加密生成方式:

1.首先给出了key

key=“wxy191iss00000000000cute”

先调用的是string_to_bits函数

o = string_to_bits(self.key)

def string_to_bits(data):data = [ord(c) for c in data]l = len(data) * 8result = [0] * lpos = 0for ch in data:for i in range(0,8):result[(pos<<3)+i] = (ch>>i) & 1pos += 1return result
  • ord()函数是chr()的配对函数,以一个字符为参数返回ASCII数值.data是key的情况下,遍历其中的每个字符将其转化为ASCII码
  • 要将其转化为二进制,每个字符是要占据八个位置。
  • <<左移操作符 >> 右移操作符,例:a=60=0011 1100,a<<2=1111 0000=240。二进位全部左移两位,低位用0补齐。
  • result[(pos<<3)+i] = (ch>>i) & 1,是将字符的二进制逐个填入result的操作,例:
    ch=w(119,0111 0111),i=3,pos=0,pos<<3+3=3,ch>>3=0000 1110&1=0,最后得出result。
    前八位为1110 1110,正好是w字符二进制的翻转,每八位代表着一个字符,这就完成了字符串到二进制的转换。

2.在循环中用到了generate()

o = generate(o)#此处o是之前经过处理的result

def permutate(table, block):return list(map(lambda x: block[x], table))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 = 0x = 0for j in b[i]:x += (j<<pos)pos += 1c.append((0x10001**x) % (0x7f))return c
  • permutate从字面来看是置换的意思,这个函数的作用在与重新打乱之前得到的result结果,按照s_box列表中给出的顺序进行重新排序。如第一个数字是54,意味着o[54]排在第一个位置。将重排后的列表命名为k。
  • 第一个for循环含义在于将列表k每7个一组分开,每组都在后面添上一个数1,构成一个八个数字的数组。将其组合在一起形成b。
    b=[[1, 1, 0, 0, 1, 0, 0, 1], ……,[0, 1, 0, 0, 1, 1, 0, 1]]
  • b中有32组元素,第二个嵌套循环便是在这32组,每组分别进行操作,每组中有八个元素,按位置进行左移操作,第一个左移0位,第二个左移1位,……一直到第八个左移七位。
  • 整组全部元素位移操作的结果进行累加得到x,再进行运算
    (0x10001**x) % (0x7f),将其结果放入c中
  • 再对第二组重复操作,将结果放入c中,直到32组结果都运算完成。generate()函数运算结果:
> o=[126L, 119L, 89L, 107L, 107L, 2L, 5L, 5L, 119L, 100L, 125L, 20L, 63L, 19L, 4L, 87L, 108L, 54L, 8L, 4L, 19L, 51L, 25L, 16L, 8L, 80L, 50L, 2L, 47L, 87L, 47L, 87L]

3.N1ES.gen_subkey

3.1gen_subkey中第一个for
for i in range(8):o = generate(o)k.extend(o)o = string_to_bits([chr(c) for c in o[0:24]])
  • 对o进行generate
  • 将得到的结果添加到k中
  • 将o中的前24个元素都变成字符,这个24是按照key的字符个数来的。
['~', 'w', 'Y', 'k', 'k', '\x02', '\x05', '\x05', 'w', 'd', '}', '\x14', '?', '\x13', '\x04', 'W', 'l', '6', '\x08', '\x04', '\x13', '3', '\x19', '\x10']
  • 将这些字符都转为二进制,重新赋值给o
  • 重复以上操作八次。
    每次输入32个长整型数,八次后,k中一共有32*8=256个数。
3.2 gen_subkey中第二个for
self.Kn = []
for i in range(32):self.Kn.append(map(chr, k[i * 8: i * 8 + 8]))
  • 将整个k分成了32个组来进行加密,每次都把八个值转化为字符串,最后得到self.kn:

4.N1ES.encrypt

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
  • 定义一个函数 f(x,y)=x+y-2*(x&y)
  • 以第一个参数长度为限进行循环,将a[i],b[i]转换为ascii码带入f进行运算,再转换为字符串
  • 循环完毕这些字符串组合起来就是res。
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, Lres += L + R

明文flag的长度一定要是16的倍数,每16个字符为一组分区,这16个中,前八个分为L(left),后八个R(right)。

  • 第一次循环,L1=R,R1=E1,E1代表经过一次编码后的字符串。
  • 第二次循环,L2=E1,R2=E2.
  • 32次循环后,L32=E31,R32=E32.
  • 循环结束后得到res=E32+E31。

发现只有这段才是真正的加密过程(Feistel加密结构),之前的所有都是为了产生self.Kn,为这次加密助力。

最后一次加密是在challenge.py文件中的base64加密。

至此全部的加密过程已经明晰,接下来就是解密了。

真正的加密只在这一个公式:
f = lambda x, y: x + y - 2 * (x & y)
而Feistel解密只要将循环式改为:

for round_cnt in range(32):L, R = R, (round_add(L, self.Kn[31-round_cnt]))

利用原式就能进行解密,举个实例演示一下加密和解密:

  • 假设这是最后一次加密循环

假设L31=110(0110 1110),Kn[31]=126(0111 1110)
R32=E32=L31+Kn[31]-2*(L31&Kn[31])=110+126-2*(110&126)=16(0001 0000)
(其中L31=E30)
加密后得L32=R31=E31,R32=E32

  • 这是第一次解密循环

L0=E32,R0=E31(因为之前加密后还有一次互换的操作)
L1=R0=E31
R1=L0+Kn[31]-2*(L0&Kn[31])
现在已知的是Kn[31]=126,因为整个Kn表都可得出。以及L0,这里L0是flag加密后的左边部分,题目已给出。L0=E32=16.
R1=16+126-2*(16&126)=110
解密后的结果正好就是L31,即E30
这次解密后得到
L1=E31,R1=E30

由结果可看出,只要逆一下加密的kn顺序就变成了解密的kn顺序,这是feistel神奇的地方。
最后修改一下challenge.py变成decode.py

from N1ES import N1ES
import base64
key = "wxy191iss00000000000cute"
n1es = N1ES(key)
cipher = "HRlgC2ReHW1/WRk2DikfNBo1dl1XZBJrRR9qECMNOjNHDktBJSxcI1hZIz07YjVx"
cipher =base64.b64decode(cipher)
flag =n1es.decrypt(cipher)#这个decrypt只是把之前文件里的encrypt改变后改的名字
print flag

得到flag
N1CTF{F3istel_n3tw0rk_c4n_b3_ea5i1y_s0lv3d_/–/}

刚开始分析的时候一步步搞清楚了每个函数是干嘛的,然而根本没什么用,只是浪费了时间,真正加密过程只在encrypt函数中,这是经验不足的原因,以后看到类似的题绝对先找encrypt函数。
之后虽然搞清楚了加密原理,但之前没有接触过feistel加密结构,还想着用穷举法把它解出来,穷举法应该也是能做的,但是我并没有做成功,py2版本只在虚拟机上有,上面没有调试工具,没找到错误原因。后来看了一下别的writeup才发现如此简单。所以基本的密码学加密模式要去了解一下,因为前辈已经给出了解密方法,就不用自己的笨办法去想了。

python(N1CTF) 100详解相关推荐

  1. python20191031_20191031:Python取反运算详解

    20191031:Python取反运算详解 取反运算:~3 == 4 1.对于数字 3 =======>转换为二进制表示为011 2.对011取反为100 3.为什么表示-4 a.计算机用补码表 ...

  2. python变量类型-Python 变量类型详解

    变量存储在内存中的值.这就意味着在创建变量时会在内存中开辟一个空间. 基于变量的数据类型,解释器会分配指定内存,并决定什么数据可以被存储在内存中. 因此,变量可以指定不同的数据类型,这些变量可以存储整 ...

  3. python语言编程基础-Python语言入门详解!快速学成Python!

    原标题:Python语言入门详解!快速学成Python! 很多技能是被职场所需要的,但很可惜... 这些技能在大学中并学习不到. 大学和职场现实存在的横沟对大部分同学来说难以跨越或碰得头破血流... ...

  4. Python 装饰器详解(下)

    Python 装饰器详解(下) 转自:https://blog.csdn.net/qq_27825451/article/details/84627016,博主仅对其中 demo 实现中不适合pyth ...

  5. Python 装饰器详解(中)

    Python 装饰器详解(中) 转自:https://blog.csdn.net/qq_27825451/article/details/84581272,博主仅对其中 demo 实现中不适合pyth ...

  6. 7、【转载】python yield generator 详解

    7.[转载]python yield generator 详解 目录 generator基础 generator应用 generator基础应用 generator高级应用 注意事项: 正文 本文将由 ...

  7. python语言入门-Python语言入门详解!快速学成Python!

    原标题:Python语言入门详解!快速学成Python! 很多技能是被职场所需要的,但很可惜... 这些技能在大学中并学习不到. 大学和职场现实存在的横沟对大部分同学来说难以跨越或碰得头破血流... ...

  8. python六大数据类型详解

    python 六大数据类型详解 文章目录 python 六大数据类型详解 数据类型简介 Number(数值) String(字符串) Python字符串的45个方法详解 一.大小写转换 01.capi ...

  9. python re库 详解(正则表达式)

    python re库 详解(正则表达式) 说明 则表达式(英文名称:regular expression,regex,RE)是用来简洁表达一组字符串特征的表达式.最主要应用在字符串匹配中. 1).re ...

最新文章

  1. python检查目录是否存在,如果不存在则创建
  2. Hadoop HDFS概念学习系列之熟练掌握HDFS的Shell访问(十五)
  3. java线程概念_《Java基础知识》Java线程的概念
  4. Linux内核crypto子系统的调用逻辑
  5. nginx学习笔记-01nginx入门,环境搭建,常见命令
  6. 小白学习使用gitee问题产生汇总(持续更新)
  7. 大白菜U盘启动制作工具怎么用?
  8. MYSQL8.0 OCP考试题库(如需完整版请留言)
  9. java中文转换为拼音的pinyin4j学习笔记
  10. 微信小程序识别图片并提取文字_微信小程序图片上传(文字识别)
  11. Python3 网络爬虫. 4
  12. 使用第三方应用友盟实现网站访问量统计功能
  13. flush-hosts
  14. 电大php考试,电大考试搜题神器免费
  15. intern()详解
  16. 安卓开发——android8.0应用崩溃,报错: Only fullscreen opaque activities can request orientation
  17. Iframe简单的嵌套用法
  18. JSP基本语法、3个编译指令、7个动作指令、9个内置对象
  19. 什么专业的人适合学嵌入式?
  20. 地震学类毕业论文文献都有哪些?

热门文章

  1. 常用API、String、StringBuilder、集合和客户信息管理系统
  2. 微服务中常用的限流算法(一)
  3. 处理EBS采购申请单无法审批的问题
  4. virtio split ctrl virtqueue
  5. 惠普服务器机柜性能,ibm服务器机柜基本配置 和惠普机架有什么区别?
  6. 如何为三星active2手表安装自己DIY的表盘
  7. 计算机的性能指标完全有CPU决定,计算机的性能主要由CPU的哪些指标决定
  8. android应用测试报告,Android 7.0应用兼容性测试报告,你get到多少姿势?
  9. CSSJavaScript讲解
  10. 主板bios恢复默认