#!/usr/bin/env python3
import binascii
import hashlib
import base64
import re
import asn1tools
from ecpy.curves import Curve
from ecpy.ecdsa import ECDSA
from ecpy.eddsa import EDDSA
from ecpy.keys import ECPublicKey
from asn1crypto import x509 as asn1_x509

# --- DADOS LIDOS DOS QRCODES DO BU urna 2015 ---
# campo_HASH_do_qrcode_BU = "2B7FC981A3CC47BE34A59C13059833EF9AEA00DD84B8BE68410EA61FD7E30E418080BA0C797F29BA4D32EFCB39C944F8A9CC8FD4C588C13171C8CD28B35BD63C"
# campo_ASSI_do_qrcode_bu = (
#     "3081880242016CE423DF937CA703BB39B6C3CBBEDBE59A49D662984A1325997E479DC3A7E54458EC774CE3CE0C9F9B9212A65A4A1075EE4DCEBA250CCE6A6AD9E6914EEA52A4490242014080FE1B76F94C149B586BD0DA4232142110E544B7DEE741D751CECD5F3BFDD6B032B731A65FE0ACD9A9B413E33955FED185B1EF4B881AA1A804BB0BF8ED6A0835"
# )
# campo_CERT_do_qrcode1 = (
#     "308203AE3082030FA00302010202032BF29C300A06082A8648CE3D040304307D3110300E0603550403130741432055524E41310B3009060355040813024446310B30090603550406130242523120301E06092A864886F70D0109011611616375726E61407473652E6A75732E6272310C300A060355040A1303545345310C300A060355040B13035354493111300F0603550407130842726173696C6961301E170D3136303631353030353831325A170D3330303232323030353831325A303F311530130603550403130C756561643031373630343536310B3009060355040813024446310B3009060355040613024252310C300A060355040A130354534530819B301006072A8648CE3D020106052B810400230381860004018AEE8E71C0E9984A64A739DD5471052D98064A9C748DB02B4AD71EA860B4A271DEF550C48F21A9A5987CD80472011B4B71B6B025D1A9A0D207917FF944325EDEEF008E3BFE49F5DBB7E9F7FFACF1F24A2ADEFF1FE526D8A1A45BC5BF68BBA94E7F8F5A108BE58775366896383A233A29AFB9B0D9F2438D376F3B0265DB69D5DC1B79DFA38201773082017330090603551D13040230003081AF0603551D230481A73081A48014CDAAF4B29701B3F0DEB2B54258594A6D34ADA48AA18188A48185"
# )
# campo_CERT_do_qrcode2 = (
#     "308182310B3009060355040613024252310C300A060355040A1303545345310C300A060355040B1303535449311330110603550403130A4143205241495A205545310B30090603550408130244463111300F0603550407130842726173696C69613122302006092A864886F70D010901161361637261697A7565407473652E6A75732E6272820103301D0603551D0E04160414A65F512297C5075E07416B094527844CFEB2566F300B0603551D0F0404030204B030380603551D1F0431302F302DA02BA0298627687474703A2F2F6C63722E616375726E612E7473652E6A75732E62722F616375726E612E63726C304E0603551D200447304530430603000000303C303A06082B06010505070201162E687474703A2F2F6470632E616375726E612E7473652E6A75732E62722F4450432D50432D414355524E412E504446300A06082A8648CE3D04030403818C00308188024200ECA824D4388BF640A68862EAC822F4B1CBE7A92D04F5ABCF793F0236A3BE51C34491DAE6A82497DAF2A566E8FA1A24B86C68C1F742DEAA1D1A1B44538ACD62F9970242009CC8E79239D8F3DCB9FB9EFAAB4D31B0FCB327EB5F724E898542E97BB00343819A64D9936DE6C91CDFE4AA497DDA7B51A321713F0CACA00E0D5758A177532D51F7"
# )

# --- DADOS LIDOS DOS QRCODES DO BU urna 2020 ---
campo_HASH_do_qrcode_BU = "777EF9A01B133942791B416171DDE075BBB7C329738528DBDF06C3E0A8FD753543ADCDACB659606B34F8E16B8D6833D6F01B762908CD2BF98E89ECB9DB5C4C23"
campo_ASSI_do_qrcode_bu = (
    "E4CA5F7281E5715F014BD99C97755926E71F7B441106B4F4566DE92C331003AC49E91729A5E84A85AC077CC01CD861C4EB24213BBD6E0F8B6B0A58F38324887784001CBBED88C0CD54F286C285BBD8D7B93A37BD165E151FDD692955B1ECDAA94011A7D4BCA1D4EC700402E90037C3454F2AD75933B772553DFD5D3A3BA5ED61DDEE5600"
)
campo_CERT_do_qrcode1 = (
    "2D2D2D2D2D424547494E2043455254494649434154452D2D2D2D2D0A4D4949437A544343416A4F6741774942416749425144414D42676F724267454541594C634C4149424D4947424D524977454159445651514444416C42517942560A525449774D6A4178437A414A42674E564241674D416B52474D517377435159445651514745774A43556A45694D43414743537147534962334451454A415259540A59574E315A5449774D6A424164484E6C4C6D703163793569636A454D4D416F47413155454367774456464E464D517777436759445651514C44414E5456456B780A4554415042674E564241634D43454A7959584E7062476C684D423458445449794D4451774D5449794D5445784D6C6F5844544D314D5449774F5449794D5445780A4D6C6F774D6A45564D424D47413155454177774D56555642524441794D444D784D5463794D517377435159445651514745774A43556A454D4D416F47413155450A4367774456464E464D464D774441594B4B775942424147433343774341514E44414371726A6736766E794A62786441326D68796D6E6A375563304632534E46340A2B4578346E556A425869764D6D4C30314D613150654F786A5930714A495A57325A55784F69377961584B3853596B414D3261424B5450695867614F42375443420A366A414A42674E5648524D45416A41414D4173474131556444775145417749457344"
)
campo_CERT_do_qrcode2 = (
    "416442674E5648513445466751557A774A716B57446F304E4454716257750A54704F6C6C4C475356375977487759445652306A42426777466F4155764C4E555865377151793465677936424B4479347270534F5141737750415944565230660A424455774D7A41786F432B674C5959726148523063446F764C32786A636935685933566C4D6A41794D43353063325575616E567A4C6D4A794C32466A645755790A4D4449774C6D4E796244425342674E5648534145537A424A4D45634741774141414442414D443447434373474151554642774942466A4A6F644852774F6938760A5A48426A4C6D466A645755794D4449774C6E527A5A53357164584D75596E4976524642444C5642444C554644565555794D4449774C6C4245526A414D42676F720A4267454541594C634C4149424134474641494C473132624D4A654450673778714266684B7956467759626D6D3873564A564A4F7573396247774366382F376B580A6E57544979563645335479776F3534546C346F4C78504E53464C365233426738487A68396E5334536758537759486B4E443479656D69446F54723444786944530A6534515A5358324D5A4B6663715A4E68326C5A73676D56477458335056594A4D33677456366350453249556B756859534E41374C4441656348353556394D5A6F0A41413D3D0A2D2D2D2D2D454E442043455254494649434154452D2D2D2D2D0A"
)
# -------------------------------------

# ASN.1 para leitura de SubjectPublicKeyInfo (com bloco DEFINITIONS)
_SUBJECT_PUBLIC_KEY_INFO_ASN1 = """
SubjectPublicKeyInfo DEFINITIONS ::= BEGIN
SubjectPublicKeyInfo ::= SEQUENCE {
    algorithm           AlgorithmIdentifier,
    subjectPublicKey    BIT STRING
}
AlgorithmIdentifier ::= SEQUENCE {
    algorithm   OBJECT IDENTIFIER,
    parameters  ANY OPTIONAL
}
END
"""
_SUBJECT_PUBLIC_KEY_INFO_DECODER = asn1tools.compile_string(_SUBJECT_PUBLIC_KEY_INFO_ASN1, codec="der")

def extrai_chave_publica_der(cert_der):
    try:
        cert = asn1_x509.Certificate.load(cert_der)
        spki_bytes = cert['tbs_certificate']['subject_public_key_info'].dump()
        spki = _SUBJECT_PUBLIC_KEY_INFO_DECODER.decode('SubjectPublicKeyInfo', spki_bytes)
        algo = spki['algorithm']['algorithm']
        pubkey_bytes = spki['subjectPublicKey'][0]
        if algo == "1.2.840.10045.2.1":  # ecPublicKey
            curve = Curve.get_curve('secp521r1')
            pubkey = ECPublicKey(curve.decode_point(pubkey_bytes))
            return pubkey, ECDSA(), algo
        elif algo == "1.3.6.1.4.1.44588.2.1": # Ed521
            curve = Curve.get_curve('Ed521')
            pubkey = ECPublicKey(curve.decode_point(pubkey_bytes))
            return pubkey, EDDSA(hashlib.shake_256, hash_len=132), algo
        else:
            raise RuntimeError(f"Algoritmo de chave pública não suportado: {algo}")
    except Exception as e:
        print(f"Falha ao extrair chave pública: {e}")
        raise

def verificar_assinatura(cert_der, assinatura, dados_hash_qr):
    try:
        pubkey, verifier, _ = extrai_chave_publica_der(cert_der)
        mensagem = hashlib.sha512(dados_hash_qr).digest()
        if verifier.verify(mensagem, assinatura, pubkey):
            print("Assinatura VÁLIDA!")
            return True
        else:
            print("Assinatura INVÁLIDA! (ecpy.verify retornou False)")
            return False
    except Exception as e:
        print(f"Assinatura INVÁLIDA: {e}")
        return False

def extrai_certificado_der(cert_bytes):
    asn1_x509.Certificate.load(cert_bytes)
    return cert_bytes

def extrai_certificado_pem(cert_bytes):
    cert_ascii = cert_bytes.decode("ascii")
    pem_body = "".join(re.findall(r"-----BEGIN CERTIFICATE-----(.*)-----END CERTIFICATE-----", cert_ascii, re.DOTALL)).replace("\n", "")
    cert_der = base64.b64decode(pem_body)
    asn1_x509.Certificate.load(cert_der)
    return cert_der

def extrai_certificado(campo_cert1, campo_cert2):
    cert_bytes = binascii.unhexlify(campo_cert1.strip() + campo_cert2.strip())
    try:
        return extrai_certificado_der(cert_bytes)
    except Exception:
        return extrai_certificado_pem(cert_bytes)

if __name__ == "__main__":
    cert_bytes = extrai_certificado(campo_CERT_do_qrcode1, campo_CERT_do_qrcode2)
    assinatura_bytes = binascii.unhexlify(campo_ASSI_do_qrcode_bu)
    hash_bytes = binascii.unhexlify(campo_HASH_do_qrcode_BU)

    verificar_assinatura(cert_bytes, assinatura_bytes, hash_bytes)