Pular para o conteúdo
Todos os conceitos

Pix copia e cola (BR Code)

O código do Pix é uma fila de campos, cada um com ID, tamanho e valor. A chave que recebe o dinheiro fica dentro do campo 26.

O texto de um QR code do Pix (o "copia e cola") parece uma sopa de letras:

00020126430014br.gov.bcb.pix0121pedidos@cucadavo.test520400005303986540525.005802BR5910CUCA DA VO6013CERRO MINUANO62120508PEDIDO426304AF8F

Mas ele segue um formato chamado TLV (tipo, tamanho, valor): cada campo é um ID de 2 dígitos, um tamanho de 2 dígitos e um valor com exatamente esse número de caracteres. Para ler, pegue 2 dígitos (ID), mais 2 (tamanho), conte os caracteres do valor e recomece logo depois:

ID Tamanho Valor O que é
00 02 01 versão do formato
26 43 [email protected] conta que recebe (tem campos dentro)
52 04 0000 categoria do comerciante
53 03 986 moeda: real
54 05 25.00 valor (opcional)
58 02 BR país
59 10 CUCA DA VO nome de quem recebe
60 13 CERRO MINUANO cidade
62 12 0508PEDIDO42 dados extras (tem campos dentro)
63 04 AF8F CRC16, a conferência do texto

O campo 26 é ele mesmo uma fila TLV: 00 14 br.gov.bcb.pix diz que é Pix, e 01 21 [email protected] é a chave, para onde o dinheiro vai. A chave pode ser um e-mail, um telefone, um CPF ou CNPJ, ou uma chave aleatória com cara de 123e4567-e89b-42d3-a456-426614174000. Pode aparecer ainda o campo 01 de fora, que diz se o QR é estático (11) ou de uso único (12).

cada bloco: ID, tamanho e valor 000201 2643… 52 … 58 5910CUCA DA VO 6304AF8F versão conta que recebe nome: texto livre CRC16 0014br.gov.bcb.pix 0121[email protected] diz que é Pix a chave: quem recebe o dinheiro o bloco 26 se abre em outros blocos
O código se lê em blocos de ID, tamanho e valor; o bloco 26 se abre em outros blocos, e o subcampo 01 dele é a chave que recebe o dinheiro.

Em Python:

def tlv(s):
    i, campos = 0, {}
    while i < len(s):
        tam = int(s[i + 2:i + 4])
        campos[s[i:i + 2]] = s[i + 4:i + 4 + tam]
        i += 4 + tam
    return campos

c = tlv(codigo)
print(c["59"], tlv(c["26"])["01"])

O CRC16 do campo 63 (na variante chamada CCITT-FALSE: polinômio 0x1021, começando em 0xFFFF) é calculado sobre todo o texto antes dele, incluindo o 6304:

def crc16(texto):
    crc = 0xFFFF
    for byte in texto.encode():
        crc ^= byte << 8
        for _ in range(8):
            crc = (crc << 1) ^ 0x1021 if crc & 0x8000 else crc << 1
            crc &= 0xFFFF
    return f"{crc:04X}"

print(crc16(codigo[:-4]) == codigo[-4:])

Ele pega um código corrompido ou editado à mão. Não pega golpe: quem gera um código novo, com a chave dele, gera também um CRC certo. E o nome do campo 59 é texto livre, escrito por quem gerou o código. Na hora de pagar, o aplicativo consulta a chave no diretório do Pix e mostra o nome do dono da chave e a instituição: é esse nome que você confere, não o do código nem o do cartaz.

Aparece nestes desafios