2018 NSEC crypto leak writeup

1.题目分析

题目可以在此处下载。下载并解压后会得到一个加密python脚本和一个加密后的wav文件。
这里写图片描述
题目描述

A recent transcript suspected to contain incriminating conversations between the officials in charge of the Mars colonization plan has leaked but is encrypted with the latest top-secret encryption algorithm: RC8! You’ve recovered the source code to their new encryption algorithm, but the key and seed value are missing. Find a weakness in the scheme and recover the transcript.

大概意思就是说希望我们在没有key和seed的情况下去解密文件。为此,我们先来看看RC8_Encrypt.py中的代码了解其是如何进行加密的。

#!/usr/bin/env python3
import sys

def rc8(state, key, n):
    '''
    Top Secret RC8 Stream Cipher
    '''
    while (n > 0):
        yield state & 0xff
        for _ in range(8):
            c, s = key, state
            b = 0
            while c:
                b ^= c & 1 * s & 1
                c >>= 1 ; s >>= 1
            state = state >> 1 | b << 63
        n -= 1

def main():
    seed, key = ?, ? # Missing

    with open(sys.argv[1], 'rb') as fin:
        data = bytearray(fin.read())

    for i,x in enumerate(rc8(seed, key, len(data))):
        data[i] ^= x

    with open(sys.argv[1] + '.enc', 'wb') as fout:
        fout.write(data)

if __name__ == "__main__":
    main()

我们可以很容易看出这是一种流加密,密钥流生成函数是rc8(),也很容易看出密钥流每次取得是state的最低八位,下面主要分析一下state是如何变化的,变化的代码如下

for _ in range(8):
            c, s = key, state
            b = 0
            while c:
                b ^= c & 1 * s & 1
                c >>= 1 ; s >>= 1
            state = state >> 1 | b << 63

c=c0c1cn1 c = c 0 c 1 ⋯ c n − 1 s=s0s1sn1 s = s 0 s 1 ⋯ s n − 1 分别是c和s的二进制表示,根据对上面代码的分析我们不难得到下面式子:
b=(c0 b = ( c 0 & s0) s 0 ) ^ (c1 ( c 1 & s1) s 1 ) ^ ^ (cn1 ( c n − 1 & sn1) s n − 1 )
我们知道 ci c i si s i 只能是0或1,对于0和1的与运算其实也可以看成乘法运算,因为都是只有当两个数都为1时,结果才为1;另外对于0和1的异或运算我们也可以看成是模2的加法运算,因为都是只有当两个数不等时结果才为1。因此,b的计算公式可以如下表示(知道这一点对我们接下来解决这个问题很关键):

b(c0×s0+c1×s1++cn1×sn1)mod2 b ≡ ( c 0 × s 0 + c 1 × s 1 + ⋯ + c n − 1 × s n − 1 ) m o d 2

大致了解了加密算法后,我们再来看看加密后的文件能给我们什么信息。打开一看,全是乱码,没有什么参考价值,当然这也是我们意料之中的事。
这里写图片描述
我们看到这道题目的名字是crypto leak,那么到底leak(泄露)了什么呢?我们知道我们加密的文件是wav格式的,而每种格式的文件都是有其特定的文件头的,我们来看看wav文件头是什么样的。

位置字节数值/类型描述
1-44“RIFF”表示文件”RIFF”文件
5-84Uint32文件长度-8
9-124“WAVE”文件类型头,表示一个”WAVE”文件
13-164“fmt “格式表示符

我们知道加密前的文件是wav格式的文件,因此文件的前16字节我们就都可以得到了,其中文件长度加密后的长度和加密前是一样的,我们可以直接得到

>>>import os
>>>hex(os.path.getsize("transcript.wav.enc")-8)
>>>'0x55030L'

注意Uint32类型的文件大小值在计算机中一般是小端保存的,因此这四个字节应该是30 50 05 00。加密前文件的前16字节是:
52 49 46 46 30 50 05 00 57 41 56 45 66 6D 74 20
同时我们也可以通过010editor打开加密后的文件查看前16字节的密文:
81 A3 7B 2C CD 36 EB A0 08 B5 74 DB AF B4 74 E6
用那么将它们异或就可以得到前16次加密的密钥流了:
D3 EA 3D 6A FD 66 EE 30 5F F4 22 9E C9 D9 00 C6

2.破解加密

我们已经得到泄露的前16次加密的密钥流了:
D3 EA 3D 6A FD 66 EE 30 5F F4 22 9E C9 D9 00 C6
我们根据代码不难分析出前8次加密的秘钥流就是seed的值,因此seed=B6F2E93D1C6F3A08。那么接下来我们应该想想如何把key求出来,我们根据前面的分析,知道state每次向右移一位,而新的最高位的计算公式是:

b0=(c0×s0+c1×s1++cn1×sn1)mod2 b 0 = ( c 0 × s 0 + c 1 × s 1 + ⋯ + c n − 1 × s n − 1 ) m o d 2

新的 state=b0s0s1sn2 s t a t e = b 0 s 0 s 1 ⋯ s n − 2 ,我们继续有
b1=(c0×b0+c1×s0++cn1×sn2)mod2 b 1 = ( c 0 × b 0 + c 1 × s 0 + ⋯ + c n − 1 × s n − 2 ) m o d 2

新的 state=b1b0s0s1sn3 s t a t e = b 1 b 0 s 0 s 1 ⋯ s n − 3 ,我们可以继续计算得到很多和c(就是key)有关的计算式,写成矩阵形式:
s0b0bn2s1s0bn3s2s1bn4sn1sn2s0c0c1cn1b0b1bn1mod2 ( s 0 s 1 s 2 ⋯ s n − 1 b 0 s 0 s 1 ⋯ s n − 2 ⋮ ⋮ ⋮ ⋯ ⋮ b n − 2 b n − 3 b n − 4 ⋯ s 0 ) ( c 0 c 1 ⋮ c n − 1 ) ≡ ( b 0 b 1 ⋮ b n − 1 ) m o d 2

根据前16字节的密钥流我们可以知道 si s i bi b i 的值,因此解出这个方程组,就可以得到c的值,即key。利用sage编程不难得到解( 代码下载),
sage$ sage sol_rc8.sage
[+] Seed: 3525868796872878803
[+] Key: 36028806108921863

由于流加密加密过程和解密过程完全类似,因此我们可以直接使用原来的加密脚本进行解密即可。解密后得到wav文件进行试听会得到提示:well done, you can check the file metadata for your flag. 那么我们右键属性查看元数据就可以看到flag了: 这里写图片描述

3.总结

解出这个问题关键有三点:

  • 了解将0和1的与运算及异或运算变为乘法和模加运算
  • 知道wav格式的文件头知识
  • 分析代码得到方程后,知道如何利用强大的数学软件sage解方程

其中第一点在其他的密码学分析题中可能也会经常用到。

  • 1
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值