Criptografia em AdvPL – Parte 03

Introdução

Nos post anterior (Criptografia em AdvPL – Parte 02), vimos com mais propriedades os hashes criptográficos MD5 e SHA1, e as funções AdvPL correspondentes. Agora, vamos ver todas as demais funções de hash disponíveis no AdvPL !!!

Formatos suportados no AdvPL

As funções publicadas no AdvPL para hash criptográfico permitem o cálculo de hash usando os seguintes formatos / algoritmos:

  • MD5
  • RIPEMD160
  • SHA1
  • SHA224
  • SHA256
  • SHA384
  • SHA512

A maioria das gerações de hash possuem funções próprias, enquanto outras usam uma função de encapsulamento para gerar vários tipos de hash criptográfico. Vamos começar pela função que permite gerar todos estes hashes.

Função AdvPL EVPDigest()

Esta função permite gerar todos os hashes acima a partir de uma string em AdvPL, e um segundo parâmetro numérico para indicar qual o algoritmo para a geração do hash deve ser utilizado. A documentação dela na TDN está disponível no link http://tdn.totvs.com/display/tec/EVPDigest

A diferença de comportamento dela para as demais já vistas anteriormente, é que — por hora — seu retorno é uma nova string binária com o hash correspondente, e não uma string com o hash em hexadecimal. Mas isso não é problema, podemos converter o resultado para hexadecimal de forma muito simples. Vamos ao exemplo:

User Function Hash2()
Local cInfo := 'Hello AdvPL'
Local nI

conout('String ......... ['+cInfo+']')

conout('MD5 ............ ['+Str2Hex(EVPDigest(cInfo,1))+']')
conout('RIPEMD160 ...... ['+Str2Hex(EVPDigest(cInfo,2))+']')
conout('SHA1 ........... ['+Str2Hex(EVPDigest(cInfo,3))+']')
conout('SHA224 ......... ['+Str2Hex(EVPDigest(cInfo,4))+']')
conout('SHA256 ......... ['+Str2Hex(EVPDigest(cInfo,5))+']')
conout('SHA384 ......... ['+Str2Hex(EVPDigest(cInfo,6))+']')
conout('SHA512 ......... ['+Str2Hex(EVPDigest(cInfo,7))+']')

Return

// Converte cada byte da string em uma string com 2 caracteres
// em hexadecimal, representando o valor do byte ( de 00 a ff ) 
STATIC Function Str2Hex(cBuffer)
Local cRet := '', nI
For nI := 1 to len(cBuffer)
  cRet += padr(__dectohex(asc(substr(cBuffer,nI,1))),2,'0')
Next
Return cRet

Com esta função, podemos gerar quaisquer um dos hashes da lista acima. Agora vamos ver o resultado no console do Totvs Application Server:

String ......... [Hello AdvPL]
MD5 ............ [cab49bf9a88ee1c3bfa6c34220edb58e]
RIPEMD160 ...... [ae2497e1672cce7642e329da57ba7fd6b4d5334e]
SHA1 ........... [d7e0a366d6f262c9bca0f3fe89c060f9b876f6ed]
SHA224 ......... [929692e8d0e887e887c82fb26af9b799a311c44c793845ddaceb7073]
SHA256 ......... [a06b154db33e70fab8bed58a9854975b97ea10b8e8f3a097b36f2956fd6f4019]
SHA384 ......... [918a60a0a2c080771b6ef194af54ee22af1c6046544dc5f3f21d5d4d3e202ba1d9249766339f4a5dc743cc2ba5969ed1]
SHA512 ......... [8be7f9a5286c3ed334511572ecbc41fcfb3fe4a1bb6070b2b16b30737e9df022e7781c9793873da7647996bd19485b58b84f5d4aa0106f3c7c84566ae1241022]

Agora, vamos rever a lista de funções para ver o que faltou:

As funções SHA256(), SHA384() e SHA512() recebem os mesmos parâmetros da SHA1(), e retornam o hash calculado usando o respectivo algoritmo, sem mais mistérios. MD5 e MD5File() já vimos no post anterior, faltou apenas a HMAC().

Função AdvPL HMAC()

HMAC é o acrônimo de Hash-based Message Authentication Code — trata-se de uma construção específica para calcular o código de autenticação de mensagem (MAC) envolvendo uma função hash criptográfica em combinação com uma chave secreta, definida pela RFC 2104.

No primeiro post sobre criptografia (Criptografia em AdvPL – Parte 01) eu havia comentado sobre uma técnica chamada “salting” — salgar — usada para você adicionar um valor fixo adicional — e secreto — na informação para gerar e validar o hash, certo? Por razões óbvias, você “salga” uma informação que você vai armazenar e validar, do seu jeito. A HMAC permite fazer isso mais “elegantemente” 😀

Internamente a função gera um hash criptográfico da string informada como primeiro argumento, usando um método de hash informado no segundo argumento, junto com uma string AdvPL contendo uma palavra-chave no terceiro argumento, retornando uma string contendo o código hash correspondente representado em hexadecimal. Podemos alterar o formato do retorno para uma string em bytes com o hash gerado através do quarto parâmetro. Vamos pro exemplo que fica mais fácil:

User Function Hash3()
Local cInfo := 'Hello AdvPL'
Local cChave := 'abracadabra'

conout("String ...... ["+cInfo+"]")
conout("Chave ....... ["+cChave+"]")
conout("HMAC MD5 .... ["+HMAC( cInfo, cChave, 1 ) +"]")
conout("HMAC SHA1 ... ["+HMAC( cInfo, cChave, 3 ) +"]")
conout("HMAC SHA256 . ["+HMAC( cInfo, cChave, 5 ) +"]")
conout("HMAC SHA512 . ["+HMAC( cInfo, cChave, 7 ) +"]")

Return


// Resultado no console

String ...... [Hello AdvPL]
Chave ....... [abracadabra]
HMAC MD5 .... [8fe3373f9a96fd5cf8f3ec1c038b26b9]
HMAC SHA1 ... [d4993adf35c2377417e281d77c5134cc6c2cecde]
HMAC SHA256 . [06245e76c80b6e1a6e955eb94fe1577540f6ea8644d0e55c69d590eddaeb44a1]
HMAC SHA512 . [e8a8edcec569d5ea8d31d6a9880eb145232d2ccf29ad624f8f0f575dd71372c530eee0436c9a3aa639a416c989dbe3b06d03f5cee369a4729f5675e8d8f9972f]

Os métodos suportados de hashing usados pela função são MD5, SHA1, SHA256 e SHA512, sendo o seu retorno correspondente ao método internamente utilizado. Da mesma forma que as demais funções de hashing, ela não é reversível, então a verificação de um hashing gerado pela HMAC() somente pode ser feita recalculando o hash do conteúdo original, e tendo a palavra-passe utilizada.

Função HASH não criptográfica

Até agora vimos funções de hash criptográfico, que têm as seguintes premissas — leia-se `hash` onde está escrito `resumo`:

  • deve ser fácil computar o valor de dispersão (hash) para qualquer mensagem
  • deve ser difícil gerar uma mensagem a partir de seu resumo (hash)
  • deve ser difícil modificar a mensagem sem modificar o seu resumo (hash)
  • deve ser difícil encontrar duas mensagens diferentes com o mesmo resumo (hash).

Porém, o conceito de hash é simplesmente gerar um valor de tamanho fixo baseado em um conteúdo de tamanho variável. Um hash não criptográfico é usado por exemplo para acelerar buscas em listas de tamanhos variáveis, que torna a busca por valores muito, muito rápida. Este artifício chama-se HASHMAP.

HASHMAP

Vamos partir por exemplo de uma lista de palavras ordenada com 1000 (mil) palavras. Com a lista está ordenada, a operação de busca pode fazer uma pesquisa binária — compara direto o texto a ser buscado com o elemento no meio da lista, se for menor, ignora tudo pra baixo e refaz a busca, se for maior ignora tudo pra cima e refaz a busca, até acabar a lista ou encontrar o elemento pesquisado, o que vier primeiro.

Na pior das hipóteses, em uma pesquisa binária em uma lista com 1000 elementos, a primeira busca descarta 500, a segunda 250, a terceira 125, a quarta 62, a quinta 31, depois 16, 8, 4, 2, 1 — e com apenas 10 comparações foi possível determinar que um determinado valor não existe na lista, certo ?

Agora, se ao invés disso, criarmos na memoria uma lista sequencial (Array), onde pré-alocamos um determinado número de elementos, por exemplo 2048 elementos, acessados diretamente pelo índice do array (de 1 a 2048), onde cada elemento é um outro array vazio, e criamos uma função de hash não criptográfico, que a partir de strings de tamanho variável, gere um número entre 1 e 2048, ao inserir um dado calculamos o hash da informação e inserimos ela diretamente no node correspondente. Com isso, você criou um HASHMAP (ou Mapa de Hash) de tamanho 2048.

Na hora de fazer a busca, a primeira etapa é calcular o hash para já buscar o array com os elementos de mesmo hash direto, em tempo constante. Depois, você compara o que você quer buscar apenas com os poucos elementos que eventualmente podem apresentar colisão de hash. Você reduz de 10 comparações para um cálculo de hash e uma comparação, fazendo apenas uma comparação adicional para cada colisão 😀

HASHMAP nativo no AdvPL

Em AdvPL existem um conjunto de funções para criar um hashmap para Arrays e até uma classe para isso — veja no link da TDN TDN – Manipulação de matriz (HashMap) — com elas nem precisamos criar o nosso hash, ela cria um mapa internamente, e permite buscas em tempo linear — não tende a crescer mesmo que a lista seja bem grande. Este recurso já foi visto em posts anteriores no blog, veja as referências no final do post.

Nem preciso dizer que, dependendo das diferenças entre os conteúdos dos elementos do array, não é fácil fazer uma função de hash para gerar um mapa de tamanho fixo que evite colisões, mesmo com mais elementos no mapa do que elementos no array. Logo, reinventar a roda é desnecessário para estes casos, use as funções de HASHMAP para Arrays do AdvPL e seja feliz !!! ❤

Conclusão

Agora que já vimos praticamente tudo sobe hash, vamos entrar no mundo dos certificados digitais e chaves criptográficas 😀

Espero que tenham gostado, e desejo a todos TERABYTES DE SUCESSO !!!

Referências

 

 

7 comentários sobre “Criptografia em AdvPL – Parte 03

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google

Você está comentando utilizando sua conta Google. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s