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

b(c0×s0+c1×s1++cn1×sn1)mod2

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

位置 字节数 值/类型 描述
1-4 4 “RIFF” 表示文件”RIFF”文件
5-8 4 Uint32 文件长度-8
9-12 4 “WAVE” 文件类型头,表示一个”WAVE”文件
13-16 4 “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

新的state=b0s0s1sn2,我们继续有
b1=(c0×b0+c1×s0++cn1×sn2)mod2

新的state=b1b0s0s1sn3,我们可以继续计算得到很多和c(就是key)有关的计算式,写成矩阵形式:
(s0s1s2sn1b0s0s1sn2bn2bn3bn4s0)(c0c1cn1)(b0b1bn1)mod2

根据前16字节的密钥流我们可以知道sibi的值,因此解出这个方程组,就可以得到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解方程

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

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

抵扣说明:

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

余额充值