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

发布时间 2023-10-09 21:19:35作者: FlyingLight

AES key

— encoded in the machine readable zone of a European ePassport

题目地址

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

解题过程

第一步:补全给出的密钥

通过查阅题目附录里提到的文档,可以找到校验位的具体机制,依据解释可求出初始密钥"?"处的取值
image

def pre(k):
    k = list(k)
    weights = [7, 3, 1, 7, 3, 1]
    sum = 0
    for i in range(21, 27):
        sum += int(k[i]) * weights[i - 21]
    sum %= 10
    k[27] = str(sum)
    return ''.join(k)

第二步:根据文档对\(K_{seed}\)的描述还原MRZ_information和\(K_{seed}\)

image

def getK_seed(k):
    mrz_imt = k[:10] + k[13:20] + k[21:28]
    H_SHA1 = sha1(mrz_imt.encode()).hexdigest()
    return H_SHA1[:32]

第三步:根据附录五求出\(K_{ENC}\),也就是Key

image
由于我们只需要求出\(K_{ENC}\),所以只需要令c='00000001'即可

def getKab(k):
    kab = []
    k = '{:064b}'.format(int(k, 16))
    for i in range(0, len(k), 8):
        kab.append(k[i:i + 7])
        if k[i:i + 7].count('1') % 2 == 0:
            kab.append('1')
        else:
            kab.append('0')
    return hex(int(''.join(kab), 2))[2:]


def getKey(k):
    k = k + '00000001'
    H = sha1(bytes.fromhex(k)).hexdigest()
    return getKab(H[:16]) + getKab(H[16:32])

第四步:利用求得的Key求出明文

用CBC模式下的AES加密即可直接求出密文

def getP(C, k):
    C = b64decode(C)
    aes =  AES.new(bytes.fromhex(k), AES.MODE_CBC, bytes.fromhex('0'*32))
    return aes.decrypt(C).decode()

运行结果

image

完整代码

from hashlib import sha1
from base64 import b64decode
from Crypto.Cipher import AES

C = '9MgYwmuPrjiecPMx61O6zIuy3MtIXQQ0E59T3xB6u0Gyf1gYs2i3K9Jxaa0zj4gTMazJuApwd6+jdyeI5iGHvhQyDHGVlAuYTgJrbFDrfB22Fpil2NfNnWFBTXyf7SDI'
K = '12345678<8<<<1110182<111116?<<<<<<<<<<<<<<<4'


def pre(k):
    k = list(k)
    weights = [7, 3, 1, 7, 3, 1]
    sum = 0
    for i in range(21, 27):
        sum = (sum + int(k[i]) * weights[i - 21]) % 10
    k[27] = str(sum)
    return ''.join(k)


def getK_seed(k):
    mrz_imt = k[:10] + k[13:20] + k[21:28]
    H_SHA1 = sha1(mrz_imt.encode()).hexdigest()
    return H_SHA1[:32]


def getKab(k):
    kab = []
    k = '{:064b}'.format(int(k, 16))
    for i in range(0, len(k), 8):
        kab.append(k[i:i + 7])
        if k[i:i + 7].count('1') % 2 == 0:
            kab.append('1')
        else:
            kab.append('0')
    return hex(int(''.join(kab), 2))[2:]


def getKey(k):
    k = k + '00000001'
    H = sha1(bytes.fromhex(k)).hexdigest()
    return getKab(H[:16]) + getKab(H[16:32])

def getP(C, k):
    C = b64decode(C)
    aes =  AES.new(bytes.fromhex(k), AES.MODE_CBC, bytes.fromhex('0'*32))
    return aes.decrypt(C).decode()

if __name__ == '__main__':
    K = pre(K)
    K_seed = getK_seed(K)
    Key = getKey(K_seed)
    P = getP(C, Key)
    print(P)

感想

对加密方式有了更新的认识,通过设置多个且校验方式不同的校验位进行检验的方式很有趣,这次试验更是实现了从校验位出发破解加密方式的过程。