Pular para o conteúdo

5 min de leitura

O CRC do Pix quebra em metade das implementações. Este é o motivo.

O QR desenha, o banco lê e diz "QR Code inválido" sem dizer por quê. Quase sempre são os mesmos quatro caracteres deixados de fora da conta.

O sintoma, e por que ele não ajuda

O QR desenha bonito. A câmera do aplicativo do banco reconhece que há um código ali. E então aparece "QR Code inválido", ou "não foi possível ler o código", e nada mais. Nenhum banco diz qual campo está errado, porque do lado deles a única informação disponível é que a soma de verificação não fechou — e uma soma que não fecha não diz onde está o erro, só que existe um.

Isso empurra quem está integrando para o lugar errado: começa a mexer na chave, no valor, no nome do recebedor, no tamanho da cidade. Às vezes um desses é mesmo o problema. Na maioria das vezes o payload está inteiro e correto, e o que está errado são os últimos quatro caracteres.

O formato: TLV, e campo dentro de campo

O BR Code é EMV MPM, o mesmo padrão de QR de pagamento usado no mundo inteiro. A ideia é simples: cada campo se declara com identificador de dois dígitos, tamanho de dois dígitos e o valor. "5303986" é o campo 53, com três caracteres, valendo 986 — o código do real.

Campos podem conter outros campos, e é assim que a chave Pix mora dentro do campo 26: dentro dele vão o 00 com "br.gov.bcb.pix" e o 01 com a chave. O tamanho do campo 26 é o tamanho de tudo isso junto, e é o primeiro lugar onde uma concatenação feita à mão erra, porque é preciso montar o miolo antes de saber o tamanho da casca.

O txid vai no campo 62, também aninhado, no subcampo 05. Ele é o que amarra o QR ao pedido do seu sistema — sem ele você recebe o dinheiro e não sabe de quem, o que num sistema com mais de dez pedidos por dia é um problema maior que o do QR não abrir.

O erro: o "6304" entra na própria conta

O último campo é o 63, o CRC, sempre com quatro caracteres. Escrito como campo TLV, ele começa com "6304" — identificador 63, tamanho 04 — e termina com os quatro dígitos hexadecimais do resultado.

A regra que quase toda implementação caseira ignora: **o CRC é calculado sobre a cadeia inteira INCLUINDO esse "6304"**, e não sobre o payload que vem antes dele. Faz sentido quando se pensa em quem valida: o banco recebe a string toda, corta os quatro últimos caracteres, calcula o CRC do que sobrou — que ainda termina em "6304" — e compara. Se você calculou sem o "6304", os dois valores nunca vão bater.

É um erro de uma linha, invisível em revisão de código e impossível de deduzir a partir da mensagem do banco. É por isso que ele é tão comum.

A segunda armadilha: existem vários "CRC-16"

O padrão do Pix pede CRC-16/CCITT-FALSE: polinômio 0x1021, valor inicial 0xFFFF, sem reflexão de entrada nem de saída, sem XOR final. Cada um desses quatro parâmetros tem uma variante popular com outro valor, e existem pelo menos vinte algoritmos diferentes que se chamam "CRC-16" por aí.

Trocar qualquer um deles produz quatro dígitos plausíveis e errados — o QR continua desenhando, e o banco continua recusando. A biblioteca que você encontrou no gerenciador de pacotes pode estar implementando CRC-16/ARC, que é o mais comum, e ela não está errada: ela está respondendo outra pergunta.

Há um jeito de conferir em cinco segundos, e ele é o teste padrão da família: o CRC-16/CCITT-FALSE da string "123456789" é 0x29B1. Se a sua função não devolve 29B1 para essa entrada, ela não é a que o Pix pede — e você descobre isso antes de gerar o primeiro QR, e não depois do primeiro cliente reclamar.

Um detalhe que morde depois: acento

O nome do recebedor e a cidade têm limite de 25 e 15 caracteres, e o padrão aceita apenas o subconjunto imprimível do ASCII nesses campos. "São Paulo" precisa virar "Sao Paulo" antes de entrar, e o corte tem que acontecer DEPOIS da conversão — cortar "São Paulo" em 15 bytes com acento pode partir um caractere multibyte no meio e produzir uma sequência que nem é ASCII nem é UTF-8 válido.

Esse erro é mais raro e mais difícil de achar, porque ele só aparece com nomes específicos. Se o seu QR funciona para uns recebedores e não para outros, é o primeiro lugar para olhar.

Como conferir sem depender do banco

Antes de testar com o aplicativo, teste o algoritmo: "123456789" deve dar 0x29B1. Depois teste o payload: copie a string inteira do seu BR Code, remova os quatro últimos caracteres, calcule o CRC do que sobrou e compare com o que você removeu. Se bater, o problema não é o CRC — é campo, tamanho ou caractere.

E vale um cuidado que não é técnico: uma chave Pix de verdade num QR de demonstração é uma cobrança de verdade na tela de quem só queria ver o sistema funcionando. A demonstração deste site usa uma chave com formato válido que não resolve para conta nenhuma, de propósito.