Level II Challenges AES MRZ

mysterytwisterc3 的一道 LVII 的题, 很是麻烦, 趁热记一波

题目地址

AES_MRZ

背景介绍

题目首先给了背景
ePassports
还没出过国, 并不知道这是啥, 好在 PDF 里给了参考文献
然而坑爹的是, 这个链接是 GG 的
经过一番艰难寻找, 找到了英文版的文献, 看得快吐血的时候, 发现了中文版文献...
Doc 9303
一共 12 个 PDF

结合 challenge 的 PDF 里的题意, 意思大概是这样的:
key 部分已知, 有 C, 求 M
而这个 key 是所谓 ePassports 的一串码(我就叫做 MRZ 好了)

这个 MRZ 是怎么来的呢? 每位都有什么含义呢?
这 12 个 PDF 里都有, 要按照规(ji)定(ben)的(fa), 去产生

还原 MRZ

又经过一番艰难寻找, 发现在 p7 中有介绍
p7 的第 53 页介绍了 A 型机读签证机读区的结构, 这个型号是与我们题目一致的。
仔细看, 你会注意到所谓的"校验码". 再仔细看, 你会发现 MRZ 里缺少的那一位正好是到期日校验数位
p11 的 28 页, 详细的介绍了校验数位的计算方法, 59 页还给了一个例子:

731 循环使用, 那么来个 py 吧?

1
2
3
4
5
a = [7, 3, 1] * 2
b = [1,1,1,1,1,6]
print sum([a[i] * b[i] for i in range(6)]) % 10

# 输出 7

所以, MRZ 就是 12345678<8<<<1110182<1111167<<<<<<<<<<<<<<<4

获取 Key

MRZ 是有了, 但是这个并不是解密用的 Key
参考文档亲切地指出, key 依然要按照规(ji)定(ben)的(fa), 去产生

又经过一番艰难寻找, 在 p11 中 69 页发现了计算方法
仔细看 D.1 与 D.2, 实际上 D.2 是先于 D.1 计算的

都说了些啥呢, 算法如下

  1. TD2 机读区(TD2 中第二个例子看起来最像题目给的 MRZ), 获取 MRZ(这步应该是给机器视觉识别卡上的 MRZ 用的, 我们跳过~)

  2. 根据 MRZ 创建"MRZ 信息"
    证件号 = 'L898902C<' 校验数位 = 3
    出生日期 = '690806' 校验数位 = 1
    截止日期 = '940623' 校验数位 = 6
    机读区信息 = 'L898902C<369080619406236'
    机读区信息 = 证件号 + 校验数位 + 出生日期 + 校验数位 + 截止日期 + 校验数位 + 机读区信息

  3. 计算"机读区信息"的 SHA-1 散列
    HSHA-1(机读区信息) = '239AB9CB282DAF66231DC5A4DF6BFBAEDF477565'

  4. 获取 Kseed
    取第三步结果的前 32 个
    Kseed = HSHA-1[:32]
    Kseed = '239AB9CB282DAF66231DC5A4DF6BFBAE'

  5. 计算 key
    c = '00000001'
    连接 Kseed 和 c
    D = '239AB9CB282DAF66231DC5A4DF6BFBAE00000001'
    计算 D 的 SHA-1 散列
    HSHA-1(D) = 'AB94FCEDF2664EDFB9B291F85D7F77F27F2F4A9D'
    对半分为
    Ka = AB94FCEDF2664EDF
    Kb = B9B291F85D7F77F2
    调整奇偶校验位
    Ka = 'AB94FDECF2674FDF'
    Kb = 'B9B391F85D7F76F2'
    Key = Ka + Kb

  6. 有些问题
    做到这, 你一定会有地方没懂
    -> MRZ 第一行没用么?
    计算机读区信息的时候的确没用到
    -> 为什么 D.2 中第一个例子的证件号后面要加是 734?
    看 MRZ, 我觉得这是在碰到校验位是'<'的时候就要加 734, 这里我也不太明白, 猜测的, 文档看的有点累, 你加油~
    -> 计算 D 的 SHA-1 散列的时候, sha1 我算出来的不是 PDF 里给的, 但是计算"机读区信息"的 SHA-1 散列的时候却和 PDF 一样
    这个你要注意, sha1 传入的是字符串, 不是 16 进制数~而 D 是 16 进制数~
    -> 调整奇偶校验位怎么调整?
    看代码注释

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
from Crypto.Cipher import AES
from Crypto.Hash import SHA
import re, string, base64

def Odd_Even(ka):
'''
bin(int('30',16)) bin(int('ea',16))
-> 110000 -> 11101010
-> 11000 -> 1110101
-> count('1') -> count('1')
-> even -> odd
-> 110001 -> 11101010
'''
k = []
for i in ka:
if bin(int(i,16)>>1).count('1') %2 == 0:
k += [hex(1+(int(i,16)>>1<<1))[2:].zfill(2)]
else:
k += [hex((int(i,16)>>1<<1))[2:].zfill(2)]
return ''.join(k)

def GetSHA1(D):
h = SHA.new()
h.update(D)
return h.hexdigest()[:32]


C = '9MgYwmuPrjiecPMx61O6zIuy3MtIXQQ0E59T3xB6u0Gyf1gYs2i3K9Jxaa0zj4gTMazJuApwd6+jdyeI5iGHvhQyDHGVlAuYTgJrbFDrfB22Fpil2NfNnWFBTXyf7SDI'
C = base64.b64decode(C)

Visa = '12345678<8<<<1110182<1111167<<<<<<<<<<<<<<<4'
VisaNo = Visa[:9]
VVisa = Visa[9]
Nationality = Visa[10:13]
Birthday = Visa[13:19]
VBir = Visa[19]
Sex = Visa[20]
VisaEnd = Visa[21:27]
VVisaEnd = Visa[27]
Others = Visa[28:]

Info = VisaNo + VVisa + Birthday + VBir + VisaEnd + VVisaEnd
print Info

K_seed = GetSHA1(Info)

D = (K_seed + '0' * 7 + '1').decode('hex')

key = GetSHA1(D)

k1 = Odd_Even(re.findall('.{2}',key[:16]))
k2 = Odd_Even(re.findall('.{2}',key[16:]))

key = k1 + k2
print 'The key is:', key

cipher = AES.new(key.decode('hex'), AES.MODE_CBC, ('0'*32).decode('hex'))
print 'The M is:', cipher.decrypt(C)

M

是一句德语
Herzlichen Glueckwunsch. Sie haben die Nuss geknackt. Das Codewort lautet: Kryptographie!
意思是
生日快乐。他们已经破解了。密码:密码!

睡了睡了~


来呀快活呀


Level II Challenges AES MRZ
https://www.tr0y.wang/2017/10/02/Crypto0/
作者
Tr0y
发布于
2017年10月2日
更新于
2024年4月19日
许可协议