AES key -- encoded in the machine readable zone of a European ePassport

文章发布时间:

最后更新时间:

Description

  • An AES encrypted message has been forwarded to you (CBC mode with zero initialization vector and 01-00 padding). Additionally, you have received the corresponding key 一 unfortunately not quite complete -in a form like a machine readable zone (MRZ) on an identity document as it is used e.g. with ePassports in Europe
  • 这里呈现给你了一个通过AES加密的信息(加密模式为CBC,其中iv值为全0,通过01-00填充)。另外,你还收到了对应的密钥,可惜并不完整。这种传递形式一般出现在身份文件中机器可识别区域,例如欧洲护照
  • It is the objective to find the plaintext of the following base64-encoded message.9MgYwmuPrjiecPMx61O6zluy3MtlXQQ0E59T3xB6u0GyflgYs2i3K9Jx aa0zj4gTMazJuApwd6+jdyel5iGHvhQyDHGVIAuYTgJrbFDrfB22Fpil2N fNnWFBTXyRSDI
  • 我们的目标就是去解密下列经过base64编码的信息
  • For encryption a key Kenc based on the Basic Access Control (BAC) protocol has been generated and applied. For decryption the following characters have been transmitted from which Kenc can be derived (The kind of coding of these characters is described in [1]): 12345678<8<<<1110182<1111167<<<<<<<<<<<<<<<4
  • 在加密时所使用的密钥,我们基于基础访问协议来生成和使用。在解密时可以从下列传输的字符串中获得密钥(这种字符的编码描述在[1])
  • Unfortunately, during transmission a character was lost and has been highlighted with a "?". Nevertheless, you can make it visible again with the help of [2]. To be able to compute the key Kenc afterwards you can find an overview of the applied encoding protocols in [3], [4] and an example in [5].
  • 不幸的是,在传输字符串时有一个字符丢失了并被以?高亮标记。然而,通过[2]的帮助,可以恢复。之后,通过浏览对应的编码协议[3]、[4],便可以计算出密钥。在[5]中给出了一个例子

Solution

  • 翻译完感觉有些模糊,因为里面有很多引用。但是总体思路已经给出:首先恢复字符串中丢失的字符,接着计算出密钥,然后最后解密即可。

恢复字符

参考文章2

image.png

image.png

  • 这里就直接定位到了我们要求的?是到期日的校验位,并且<代表0
1
2
3
4
5
6
7
s = "111116"
q = [3,7,1]
result = 0

for i in range(len(s)):
result += int(s[i])*q[i%3]
print(result % 10)

得到答案为7

计算密钥key

先给出参考引用

image.png

这里首先通过证件号码、出生日期和到期日及其各自的校验位生成密钥种子

    1. 证件号码 12345678<8
    2. 出生日期1110182
    3. 到期日 1111167
  • 将其进行SHA-1哈希并取高16字节即可得到密钥种子

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    # coding=gbk

    from hashlib import sha1

    def hash(content):
    h = sha1(content).hexdigest()
    return h[:32]

    content = b'12345678<811101821111167'
    print(hash(content))

    # a095f0fdfe51e6ab3bf5c777302c473e

    继续看参考引用

    image.png

    还挺麻烦,也就是这里还要基于密钥种子生成两个DES密钥。有个计数器c需要利用,因为我们是要生成加密密钥,所以用第一个0x 00 00 00 01

    这里在最后还要计算一个奇偶校验位,也就是每八位都要加上一个校验位,最终形成密钥

    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
    # coding=gbk
    from hashlib import sha1
    from Crypto.Cipher import AES
    from base64 import b64decode

    def hash(content):
    return sha1(content).hexdigest()

    def correct(key):
    result = []
    a = bin(int(key, 16))[2:]
    for i in range(0, len(a), 8):
    if a[i:i+7].count("1") % 2 == 0:
    result.append(a[i:i+7])
    result.append("1")
    else:
    result.append(a[i:i+7])
    result.append("0")
    return hex(int("".join(result), 2))[2:]

    cipher = b"9MgYwmuPrjiecPMx61O6zIuy3MtIXQQ0E59T3xB6u0Gyf1gYs2i3K9Jxaa0zj4gTMazJuApwd6+jdyeI5iGHvhQyDHGVlAuYTgJrbFDrfB22Fpil2NfNnWFBTXyf7SDI"


    c = '00'*3 + '01'
    seed = 'a095f0fdfe51e6ab3bf5c777302c473e'
    D = seed + c
    # 这里要重新转换为字节数组,因为这里只是16进制表示str
    H = hash(bytes.fromhex(D))[:32]

    ka, kb = H[:16], H[16:]

    key = bytes.fromhex(correct(ka)) + bytes.fromhex(correct(kb))
    print(key)

    # b'\xea\x86E\xd9\x7f\xf7%\xa8\x98\x94*\xa2\x80\xc41y'

解密

  • 这里就没啥可说的了,AES-CBC解密即可。除了要注意iv的值为ascii码的0值,而不是数字0

    1
    2
    3
    mode = AES.new(key, AES.MODE_CBC, iv=b"\x00"*16)
    plain = mode.decrypt(b64decode(cipher))
    print(plain)

运行结果

image.png

总结

  • 题目整体不是很难,只要跟着说明一步步走即可。中间遇到了一些代码上的问题,比如说字节与16字符串之间的转换。也算是更加熟练了对python 密码相关库的使用
  • 写了这么多道题,也学到了很多基于分组密码加密模式的小trick