如何反向改造荷兰新冠证书Base45解码Python代码实现编码功能
荷兰NL2格式新冠证书编码工具实现
前置依赖
你需要先安装以下Python依赖包:
- pyasn1、pyasn1-modules:用于ASN.1格式数据的序列化与校验
- base45:用于Base45标准编解码
安装命令:pip install pyasn1 pyasn1-modules base45
编码逻辑说明
对应原解码流程的逆向步骤如下:
- 按照荷兰官方NL2证书的ASN.1结构定义,构造对应的ASN对象模板
- 将输入的结构化参数(证书版本、公钥校验值、isSpecimen标识、validFrom生效时间、有效期、个人信息等)填入模板对应字段
- 序列化ASN对象得到二进制原始数据
- 对二进制数据进行Base45编码
- 拼接
NL2:前缀,得到最终可生成二维码的编码字符串
完整实现代码
from pyasn1.type import univ, char, namedtype, useful from pyasn1.codec.der.encoder import encode as der_encode import base45 from datetime import datetime # 对应NL2证书的ASN.1结构定义,需和原解码逻辑完全匹配 class NL2Certificate(univ.Sequence): componentType = namedtype.NamedTypes( namedtype.NamedType('version', univ.Integer()), namedtype.NamedType('keyIdentifier', univ.OctetString()), namedtype.NamedType('isSpecimen', univ.Boolean()), namedtype.NamedType('validFrom', useful.GeneralizedTime()), namedtype.NamedType('validTo', useful.GeneralizedTime()), # 可根据原解码得到的其他字段继续扩展,比如接种/检测记录字段等 namedtype.OptionalNamedType('firstName', char.UTF8String()), namedtype.OptionalNamedType('lastName', char.UTF8String()), namedtype.OptionalNamedType('birthDate', char.UTF8String()), namedtype.OptionalNamedType('credentialType', univ.Integer()) ) def generate_nl2_cert(cert_params: dict) -> str: """ 输入结构化证书参数,生成NL2格式Base45编码字符串 :param cert_params: 参数字典,需包含version、keyIdentifier、isSpecimen、validFrom、validTo必填字段 可选填入firstName、lastName、birthDate、credentialType等扩展字段 :return: 带NL2:前缀的Base45编码字符串 """ # 初始化ASN证书对象 cert = NL2Certificate() # 填充必填字段 cert['version'] = cert_params['version'] cert['keyIdentifier'] = univ.OctetString.fromHexString(cert_params['keyIdentifier']) cert['isSpecimen'] = cert_params['isSpecimen'] # 转换时间格式为ASN.1标准GeneralizedTime格式 def time_to_asn_format(dt: datetime) -> useful.GeneralizedTime: return useful.GeneralizedTime(dt.strftime("%Y%m%d%H%M%SZ")) cert['validFrom'] = time_to_asn_format(cert_params['validFrom']) cert['validTo'] = time_to_asn_format(cert_params['validTo']) # 填充可选字段 optional_fields = ['firstName', 'lastName', 'birthDate', 'credentialType'] for field in optional_fields: if field in cert_params: cert[field] = cert_params[field] # DER序列化ASN对象为二进制 der_binary = der_encode(cert) # Base45编码二进制数据 base45_str = base45.b45encode(der_binary).decode('ascii') # 拼接NL2前缀返回 return f"NL2:{base45_str}"
使用示例
if __name__ == "__main__": # 示例参数,可根据实际需求替换字段值、新增自定义字段 test_params = { "version": 1, "keyIdentifier": "A1B2C3D4E5F67890", # 公钥标识的十六进制字符串 "isSpecimen": False, "validFrom": datetime(2023, 1, 1, 0, 0, 0), "validTo": datetime(2023, 12, 31, 23, 59, 59), "firstName": "张三", "lastName": "李", "birthDate": "1990-01-01", "credentialType": 2 # 1=接种证明 2=检测证明 3=康复证明,可根据官方规范调整 } final_code = generate_nl2_cert(test_params) print("生成的NL2编码字符串:", final_code)
注意事项
- 若你现有解码代码中的ASN.1结构和上述定义不一致,需根据解码时的字段顺序、类型调整
NL2Certificate类的componentType定义,结构完全匹配才能生成可正常解码的证书 keyIdentifier字段值需和签名用私钥对应的公钥哈希值一致,否则解码时公钥校验会失败- 本实现仅生成符合格式要求的编码字符串,如需可视化二维码,可配合qrcode等二维码生成库使用
内容的提问来源于stack exchange,提问作者MitchGamesNL
相关产品推荐
相关产品推荐

