Rafael Fidelis

I write about programming and random things

Chega De Gambeta: Como Validar CNPJ E CPF Corretamente

| Comments


Não sei se é só impressão minha, mas a maioria dos algoritmos e implementações de validação de CPF e CNPJ que eu vejo por ai nas interwebs são extremamente mal feitos! Alias não digo todos, porém os principais resultados no Google, com certeza!, porém um dos excelentes exemplos de implementação desses algoritmos é a gem do fnando.

Eu poderia utilizar essa gem, mas as vezes precisamos reinventar a rodar para aprendermos, reinventar a rodar com motivações didaticas. Nesse caso eu queria entender realmente como funciona o algoritmo de validação de dígitos verificadores de CNPJ e CPF, que é algo bem interessante, à propósito! Dessa forma além de adquirir mais conhecimento, eu também consigo melhorarar a qualidade dos softwares que eu desenvolvo, pois posso entender melhor como as coisas funcionam.

Pergunta: Você sabe pra que servem esses dígitos verificadores dos documentos?(cpf, cnpj, etc)?

Resposta curta:

Assegurar a validade e autenticidade de um valor numérico(ex: número do documento), assim evitando fraudes e erros comuns, como por exemplo erros de digitação ou transmissão.

Como você deve ter concluído, essa técnica é utilizada por questões de segurança, não tem muito segredo aqui! Agora para calcular os dígitos verificadores(DV daqui pra frente) de um número [de documento], basta definir-se uma máscara de pesos padronizada que será utilizada em uma equação com os números anteriores. Eita, acho que saquei, mas como assim?

Ok, sei que parece confuso quando explicado teoricamente, mas basicamente vamos utilizar um algoritmo para calcular os dígitos verificadores, utilizando o número raiz do documento.

PS: O número raiz é composto pelos números base da sequência, sem os dígitos verificadores (óbvio! Pois os DV serão calculados a partir desse números). Ex: Em um CPF com o número 112233445-17, o número raiz/base é 112233445 e os dígitos verificadores são 17.



Mostre que você é hackudão, tiozão!

Como desenvolvedor, eu dificilmente vou ficar feliz se eu receber a resposta de algo como: “Ah não sei, mas funciona assim! Usa e pronto!”

Eu quero entender como essa parada funciona!! E se você tá aqui, acredito que também tem o mesmo propósito! Se você continuar lendo esse post, não vai aprender somente como os dígitos verificadores de CPF e CNPJ são calculados, mas sim como calcular os DV de qualquer valor numérico!! Vamos aprender uma forma genérica(e como desenvolvedor você deve adorar isso!) de entender como aplicar esse conceito em todo e qualquer valor numérico, sabe como?

VAMOS CRIAR NOSSO DOCUMENTO DE IDENTIDADE PARA D3VS H4CkUd05

Vamos chamar esse documento de Carteira de Dev Hackudão

Nosso documento terá exatamente 16 dígitos + 3 dígitos verificadores(DV), sendo composto no total por 19 dígitos, no seguinte formato:

XXXX&&XXXX(0xZZ)||[YY]<MM>!DD-VVV;

XXXX&&XXXX = 2 números aleatórios(timestamp?)(formado de 4 dígitos binários cada - 4 bits)
0xZZ = Identificador da linguagem de programação favorita. (2 dígitos)
[YY]<MM>!DD = Data de filiação ao partidos dos devs putões, ops, h4ckud05.(6 dígitos)
VVV = Dígitos verificadores(3 dígitos)

Possíveis Valores de ZZ:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
01 - Ruby
02 - C#
03 - Javascript
04 - Lua
05 - Python
06 - Java
07 - C
08 - C++
09 - PHP
10 - Perl
11 - Go
12 - Objective-C
13 - Swift
14 - Cobol
15 - R


Estruturando nosso número de documento

Definido o padrão e formato desses números, vamos gerar um número aleatório para o nosso documento inicial, usando o formato já definido acima, se liga:

Formato: XXXX&&XXXX(0xZZ)||[YY]<MM>!DD-VVV;

Número: 0101&&1111(0x01)||[16]<07>!29

Fique atento pois vamos usar esse número de documento durante todo esse artigo. Agora, a primeira pergunta que me vem a cabeça é:

Beleusma, mas como calcular o dígito verificador dessa caralha

A primeira coisa a ser feita é remover toda a formatação do número, para obter-se assim um numero raiz/base:

Número formatado: 0101&&1111(0x01)||[16]<07>!29
Número base: 0101 1111 01 16 07 29

Como você pode observar, nosso número base possuim 16 dígitos, e vamos utilizar cada uma das unidades desse número para o calcúlo dos DV(dígitos verificadores);



Calculo dos dígitos verificadores sob o número base

0 1 0 1 1 1 1 1 0 1 1 6 0 7 2 9

Observe que na tabela acima somente relacionamos unidade por unidade, agora vamos criar o esquema para multiplicação, como o número do nosso documento é composto de 16 dígitos, vamos relacionar um número para cada um deles, veja:

0 1 0 1 1 1 1 1 0 1 1 6 0 7 2 9
17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2

E agora vamos multiplicar ça merda!

0 1 0 1 1 1 1 1 0 1 1 6 0 7 2 9
17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2
0 16 0 14 13 12 11 10 0 8 7 36 0 28 6 18

Após multiplicar todas as unidades, vamos somar cada um dos valores obtidos:

0 + 16 + 0 + 14 + 13 + 12 + 11 + 10 + 0 + 8 + 7 + 36 + 0 + 28 + 6 + 18 = 179

A soma total da multiplicação de cada unidade resultou no valor 179.

Eu tô perdido, #mimajuda!!

Primeiro, vamos recapitular o que rolou até agora, só pra você ficar ligado nos paranáuês:

1 - Definimos o padrão do nosso documento (incluindo a formatação, porém na equação de multiplicação toda a formatação é removida)

2 - Definimos o padrão dos números da máscara utilizada para o calculo dos dígitos.

3 - Definimos a equação (multiplicação das unidades) + soma dos resultados para obter um valor inteiro.

Beleza! Tranquilo? Se não, releia os pontos acimas, leia novamente o post até aqui e vamos que vamos!

Nesse momento temos o valor 179 que representa a soma dos resultados da equação que definimos, e será através desse número que definiremos o primeiro digito verificador dessa bagaça! Para SIMPLIFICAR E PADRONIZAR, vamos utilizar a rotina de Modulo 11 para calculo do dígito verificador.

Essa rotina é nada mais que dividir o nosso somatório pelo valor 11, obter o resto dessa divisão, e seguir a seguinte lógica:

- Se o valor restante for menor que 2, o dígito verificador será 0 - Caso contrário, subtrair a base 11 desse valor

O resultado da operação acima retornará o dígito verificador. Pronto para calcular? Então lets vamos!



Primeiro dígito verificador

OBS: O operador de modulo(%) retorna o valor restante de uma divisão.

1 - Obter o resto da divisão:

179 % 11 = 3

2 - Subtrair a base 11 do valor restante (resto > 2):

11 - 3 = 8

EITCHA LASQUEIRA! Temos nosso primeiro dígito verificador, agora nosso documento está como:

0101&&1111(0x01)||[16]<07>!29-8VV



Segundo dígito verificador

Ainda faltam 2 dígitos para serem obtidos, para identificar o próximo DV, vamos efetuar o mesmo processo(lembrando que o dígito verificador 8 agora é considerado parte do documento):

0 1 0 1 1 1 1 1 0 1 1 6 0 7 2 9 8
18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2
0 17 0 15 14 13 12 11 0 9 8 42 0 35 8 27 16

1: Obter soma

0 + 17 + 0 + 15 + 14 + 13 + 12 + 11 + 0 + 9 + 8 + 42 + 0 + 35 + 8 + 27 + 16 = 227

2: Obter resto da divisão por 11

227 % 11 = 7

3: Subtrair base 11 do restante da divisão

11 - 7 = 4

IRRRRÁAAAA! E lá vem o segundo dígito verificador*. Agora nosso documento está como:

0101&&1111(0x01)||[16]<07>!29-84V



Terceiro e último dígito verificador

Finalmente vamos obter o terceiro dígito verificador, vamos repetir o processo novamente:

0 1 0 1 1 1 1 1 0 1 1 6 0 7 2 9 8 4
19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2
0 18 0 16 15 14 13 12 0 10 9 48 0 42 10 36 24 8

1: Obter soma

0 + 18 + 0 + 16 + 15 + 14 + 13 + 12 + 0 + 10 + 9 + 48 + 0 + 42 + 10 + 36 + 24 + 8 = 275

2: Obter resto da divisão por 11 275 % 11 = 0

3: Definir o valor como 0, já que o valor restante é menor que 2 (< 2) 0

Portanto, o número completo do nossa identidade de dev h4ckud0 z1k4 é:

0101&&1111(0x01)||[16]<07>!29-840



Dígitos verificadores de CPF & CNPJ

Agora que você já entendeu como validar os dígitos verificadores de qualquer número de documento, vamos fazer o mesmo com um número de CNPJ e CPF, começando pelo CNPJ:

Eu poderia criar um CNPJ fake, mas vamos usar o CNPJ do Facebook Brasil para calcular os dígitos verificadores:

CNPJ Facebook Brasil

13.347.016/0001-VV

A sequência/mascara de pesos utilizada para validação é: (eu realmente não sei quem define isso, acredito que seja a Receita Federal)

5 4 3 2 9 8 7 6 5 4 3 2

Primeiro dígito:

1 3 3 4 7 0 1 6 0 0 0 1
5 4 3 2 9 8 7 6 5 4 3 2
5 12 9 8 63 0 7 36 0 0 0 2

1: Obter soma 5 + 12 + 9 + 8 + 63 + 0 + 7 + 36 + 0 + 0 + 0 + 2 = 142

2: Obter resto da divisão por 11 142 % 11 = 10

3: Subtrair base 11 do restante da divisão 11 - 10 = 1

Segundo dígito:

OBS: Lembre-se que o digito verificador 1 obtido no passo anterior foi adicionado ao número do documento;

1 3 3 4 7 0 1 6 0 0 0 1 1
6 5 4 3 2 9 8 7 6 5 4 3 2
6 15 12 12 14 0 8 42 0 0 0 3 2

1: Obter soma (6 + 15 + 12 + 12 + 14 + 0 + 8 + 42 + 0 + 0 + 0 + 3 + 2) = 114

2: Obter resto da divisão por 11 114 % 11 = 4

3: Subtrair base 11 do restante da divisão 11 - 4 = 7

Pronto, chegamos ao número completo do CNPJ:

13.347.016/0001-17


CPF

Para calcular os dígitos verificadores de um CPF não é muito diferente, sendo necessário somente utilizar a máscara de pesos correta para calculo, que é:

10 9 8 7 6 5 4 3 2

Vamos usar o número do CPF da Dilma Roussef para calcular os dígitos verificadores:

CPF inicial

133.267.246-VV

1
2
3
(1 * 10) + (3 * 9) + (3 * 8) + (2 * 7) + (6 * 6) +(7 * 5) + (2 * 4) + (4 * 3) + (6 * 2) = 178
178 % 11 = 2
11 - 2 = 9 # primeiro dígito verificador
1
2
3
(1 * 11) + (3 * 10) + (3 * 9) + (2 * 8) + (6 * 7) +(7 * 6) + (2 * 5) + (4 * 4) + (6 * 3) + (9 * 2) = 230
230 % 11 = 10
11 - 10 = 1 # segundo digito verificador

Portanto os dígitos completos do CPF da Dilmona são 9 e 1, o documento todo fica como:

133.267.246-91

Dilma VLW FLW



E para validar, #comofaz?

Para validar se um CPF ou CNPJ(ou qualquer documento) é valido, ao receber o número do documento, basta obter os dois últimos dígitos (que no caso são os dígitos verificadores), com isso você terá o número raiz/base do documento, em seguida é só calcular os dois dígitos verificadores(em cima do número raiz) e verificar se são EXATAMENTE os mesmos dígitos obtidos inicialmente, ex:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Para ser valido, os dígitos verificadores deveria ser 1 e 7
invalid_cnpj = "13347016000120"
digits = invalid_cnpj.slice(2, -2) # remove os 2 últimos caracteres, nesse caso são [2,0]

# imagine que o método .calculate_verify_digits executa o calculo que aprendemos nesse post
# o valor retornado abaixo será [1,7]
expected_digits = CNPJ.calculate_verify_digits(invalid_cnpj)# [1,7]

# Nesse momento, os valores das variáveis são:
# digits = ["2","0"]
# expected_digits = [1, 7]

# Lembre-se de converter todos os digitos para o mesmo tipo de dados, afinal ["2", "0"] != [2, 0]

# checa se os dígitos do documento recebido É EXATAMENTE o mesmo dos dígitos calculados matematicamente
expected_digits.map(&:to_i) == digits.map(&:to_i) # false

OBS: Além disso é importante que você não permita que os usuários utilizem documentos onde TODOS os digitos SÃO ÚNICOS, por exemplo no caso de CPF os seguintes documentos seguem o formato corretamente e também o cálculo, porém sabemos que não deveriam ser válidos:

  • 000.000.000-00
  • 111.111.111-11
  • 222.222.222-22
  • 333.333.333-33
  • 444.444.444-44
  • 555.555.555-55
  • 666.666.666-66
  • 777.777.777-77
  • 888.888.888-88
  • 999.999.999-99

E no caso de CNPJ:

  • 00.000.000/0000-00
  • 11.111.111/1111-11
  • 22.222.222/2222-22
  • 33.333.333/3333-33
  • 44.444.444/4444-44
  • 55.555.555/5555-55
  • 66.666.666/6666-66
  • 77.777.777/7777-77
  • 88.888.888/8888-88
  • 99.999.999/9999-99

Também pode ser uma boa ideia fazer blacklist dos seguintes CPFS: 123.456.789-09 e 012.345.678-90. Nesse caso, você pode criar um array/hash com os CPF’s e CNPJ whitelisted e então verificar se o CPF enviado está incluido na sua lista de documentos “válidos”(matematicamente) porém inválidos na prática, como por exemplo nesse(CPF) e nesse(CNPJ) código da gem do Nando Vieira. No caso da minha gem brazilian_documents eu faço uma validação um pouco diferente: Eu verifico inicialmente se o documento é composto por MAIS de um dígito ÚNICO, caso contrário esse documento não é considerado válidocódigo fonte, porém conforme eu disse acima é uma boa ideia também ter um lista de CPF/CNPJ whitelisted para números especificos, como é o caso de 123.456.789-09 e 012.345.678-90 especificamente.



Biblioteca Ruby

Enquanto eu ia escrevendo esse post, aproveitei para escrever o código de uma Rubygem para geração e validação de dígito verificador de qualquer documento, e outra que gera e valida documentos brasileiros - nesse momento é possível calcular e validar os seguintes documentos do Brasil:

  • CPF
  • CNPJ
  • Inscrição Estadual (das 27 federações, que são totalmente despadronizados, uma putaria que só).

Links:

Validação de documentos brasileiros: https://github.com/fidelisrafael/brazilian_documents
Validação de digito verificador generico: https://github.com/fidelisrafael/digit_checksum
Implementação de Documento H4ck com DigitChecksum



Referências

https://pt.wikipedia.org/wiki/D%C3%ADgito_verificador
https://pt.wikipedia.org/wiki/Cadastro_Nacional_da_Pessoa_Jur%C3%ADdica
http://ghiorzi.org/DVnew.htm
http://www.geradorcnpj.com/algoritmo_do_cnpj.htm
http://www.macoratti.net/alg_cnpj.htm
https://en.wikipedia.org/wiki/4-bit

Comments