Criptografia em AdvPL – Parte 14

Introdução

No post anterior (Criptografia em AdvPL – Parte 13) vimos mais detalhes sobre assinatura digital, e as funções PrivSignRSA() e PrivVeryRSA(). Agora, vamos ver as funções EVPPrivSign() e EVPPrivVery(), e mais algumas coisas interessantes ! Para ver o índice de tudo o que já foi publicado nessa série de posts, acesse o link Criptografia e Segurança.

Direto ao ponto

As funções de assinatura e verificação de assinatura vistas anteriormente exigiam que você calculasse o hash criptográfico de um conteúdo, e depois assinasse este hash. As funções EVPPrivSign() e EVPPrivVery() possuem basicamente apenas uma diferença: Você informa diretamente o conteúdo e o tipo do hash criptográfico a ser usado, e a função faz a geração do hash internamente, e ela gera/verifica a assinatura com apenas uma chamada 😀 Vejam a diferença de chamada, baseado nos códigos de exemplo do post anterior:

// Por exemplo, ao invés de 
cHash := SHA1( cStrImage , 1 )
cSignature := PrivSignRSA( "\siga0984\rootca.key", cHash, 2, "" )

// Você chega no mesmo resultado usando:
cSignature := EVPPrivSign( "\siga0984\rootca.key", cStrImage, 3, "" )

Reparem que as funções recebem um parâmetro numérico para indicar o tipo de hash criptográfico utilizado, mas cada função possui a sua tabela de valores e significados. Consulte a documentação das funções no TDN para maiores detalhes — vide links no final do post. E, para realizar a validação de uma assinatura …

// Ao invés de ....
cHash := SHA1( cStrImage , 1 )
lOk := PrivVeryRSA( "\siga0984\rootCA-public.key", cHash, 2, cSignature )

// podemos usar 
lOk := EVPPrivVery( "\siga0984\rootCA-public.key", cStrImage, 3, cSignature, "" )

Logo, se você não vai usar o hash do conteúdo para nada diferente da assinatura, você pode simplesmente gerar a assinatura sobre o conteúdo usando a EVPPrivSign() dizendo qual o tipo do hash que será usado para assinar 😀

Ainda existe mais uma função de assinatura digital no AdvPL, chamada SMimeSign(), que veremos nesta sequência de posts. Agora, vamos ver mais duas funções auxiliares usadas para retornar algumas informações de uma chave privada: RSAExponent() e RSAModulus()

Por dentro das chaves criptográficas – Módulo

Existem informações de uma chave criptográfica — privada ou pública — que podem ser úteis ou necessárias para realizar algumas validações. Internamente  — e visto da forma mais simples possível — uma chave criptográfica RSA é criada a partir de dois números primos escolhidos aleatoriamente, e a partir deles são calculados dois elementos, chamados de “módulo” e “expoente”. O módulo é a parte comum das duas chaves, tanto a privada como a pública.

Em alguns posts para trás eu gerei uma chave privada usando o OpenSSL, e gerei a chave pública a partir da chave privada. Ao consultar o módulo de ambas, elas devem ter o mesmo valor. Veja no exemplo abaixo usando um par de chaves privada e pública gerados anteriormente usando a OpenSSL:

openssl rsa -in note-juliow-ssd.key -modulus -noout

Modulus=BC5B5604E28A5888652286CE3342C4151ACA9B4EAD7E7B42927E64E93B5C30F9DE34B0C3FBE26269E7D73CF1CB78C284DA15C32B222C307D713FD447340A3950D48FBCFA170BEE6E38281A06B338825164BF7BD075EAFDE1F985AC21FAF8EEFBB5(...)

openssl rsa -in note-juliow-ssd-public.key -pubin -modulus -noout

Modulus=BC5B5604E28A5888652286CE3342C4151ACA9B4EAD7E7B42927E64E93B5C30F9DE34B0C3FBE26269E7D73CF1CB78C284DA15C32B222C307D713FD447340A3950D48FBCFA170BEE6E38281A06B338825164BF7BD075EAFDE1F985AC21FAF8EEFBB5(...)

 

Função AdvPL RSAModulus()

A informação do módulo de uma chave privada ou pública também pode ser obtida em AdvPL usando a função RSAModulus(). A única diferença é que o módulo retornado pelo AdvPL está no formato binário (RAW), em uma string contendo os bytes de 0 a 255, enquanto a OpenSSL retorna o módulo em uma string hexadecimal — que podemos converter facilmente, vide exemplo abaixo:

USER Function GetKeyMod()
Local cPrivMod, cPublMod
Local cPrivHex, cPublHex

cPrivMod := RSAModulus( '\certificates\note-juliow-ssd.key', .F. )
If empty(cPrivMod)
  UserException('Falha ao obter o módulo da Chave Privada')
Endif
cPrivHex := Upper(Str2Hex(cPrivMod)) 
conout("MODULUS - Private Key")
conout(cPrivHex) 

cPublMod := RSAModulus( '\certificates\note-juliow-ssd-public.key', .T. )
If empty(cPublMod)
  UserException('Falha ao obter o módulo da Chave Pública')
Endif
cPublHex := Upper(Str2Hex(cPublMod))
conout("MODULUS - Public Key")
conout(cPublHex)

Return

STATIC Function Str2Hex(cBuffer)
Local cRet := '', nI
For nI := 1 to len(cBuffer)
	cRet += padl(__dectohex(asc(substr(cBuffer,nI,1))),2,'0')
Next
Return cRet

No exemplo acima, usando os mesmos arquivos do exemplo da OpenSSL, contendo respectivamente a chave privada e a chave púbica correspondente à chave privada, e obtive os mesmos valores. É importante eu informar corretamente para a função se a chave informada é pública ou privada. Caso isso não seja informado corretamente, a função retorna NIL. Com esse recurso eu consigo verificar se uma determinada chave pública foi gerada a partir de uma chave privada, e também se uma determinada chave é privada ou pública — testando a mesma duas vezes. O resultado do programa acima pode ser visto no log de console do TOTVS Application Server.

*** Observação muito importante ***

Minha primeira tentativa de execução não funcionou. O programa está correto, a chave pública foi gerada a partir da chave privada como manda o figurino usando a OpenSSL, mas mesmo assim a função RSAModulus() retornava NIL quando eu a utilizava com a chave pública ! Então, depois algumas pesquisas …. entendi o que houve 😀

A chave pública usada no exemplo anterior foi gerada a partir da chave privada, usando o seguinte comando:

openssl rsa -in note-juliow-ssd.key -pubout -out note-juliow-ssd-public.key

Resultado obtido:

—–BEGIN PUBLIC KEY—–
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvFtWBOKKWIhlIobOM0LE
FRrKm06tfntCkn5k6TtcMPneNLDD++JiaefXPPHLeMKE2hXDKyIsMH1xP9RHNAo5
UNSPvPoXC+5uOCgaBrM4glFkv3vQder94fmFrCH6+O77tXlqAvWDFfqVtRgfdudX
QaH3hCO9jDHuAsZYQ2pA/yRBtjPO63utFNBDz7917G1avpSDbtdx7EC4aDbIKpCc
0G5knOY+KG7FO3CkxX3/kQ348vcn3c0EBiw6zngj00MvSXflThMtGIxDXS59cMTb
X9yaseYFNxT4gopaDEciB6thIEODtcyPCZNftDKbGblQNZEru4v3XKZ7Him0cw34
k+nWmpD4SaSriYpWn49r4XtktKr4EWu5kmaqRgRdu10XUuEXNoaAcB9kRUdvEvLL
NyArbDYyp+1am6n6RzSoGnmNHYThKZ6pZJfzg2R5np1yKgUNTljs/yzXxaJcsuYI
Jo4XEuOZLlB/pj/vbKpFCA342/wV9EIpLRPRTCs+ch/pDCq9OGBcJ91jfDKswPAG
hRrcZGfZRLy8g/xlKhoMBHfqKQb43jW6S80jxocRv03M2NAgVChQ3bLjIfKdZxon
ERVukqw8rGZwhjG8VTmF/p9lAinWzDZR8uIVkxNvobVHr8wgx5T+RDdZkJhG/b56
HMGHeleUBdsKYPPKQhsBiTUCAwEAAQ==
—–END PUBLIC KEY—–

Esta chave pública está correta, PORÉM existem algumas formas de codificação para uma chave pública, onde as duas principais são: PKCS#1 — que contém apenas o módulo e o expoente — e PKCS#8, que pode conter mais informações. No resumo, esta chave está no formato PKCS#8, e contém uma informação adicional dos primeiros 32 caracteres da chave, onde está gravado que “o formato interno da chave é PKCS#1” !!

Quando eu gero uma a chave pública usando a OpenSSL — com a parametrização utilizada — o comportamento default é codificar a chave pública no formato PKCS#8. Se eu quero gerar uma chave pública “sequinha”, no formato PKCS#1, eu posso fazer de duas formas:

  • A partir da chave privada, trocando o parametro “-pubout” para “-RSAPublicKey_out”
openssl rsa -in note-juliow-ssd.key -RSAPublicKey_out -out note-juliow-ssd-public_rsa.key

Resultado obtido:

—–BEGIN RSA PUBLIC KEY—–
MIICCgKCAgEAvFtWBOKKWIhlIobOM0LEFRrKm06tfntCkn5k6TtcMPneNLDD++Ji
aefXPPHLeMKE2hXDKyIsMH1xP9RHNAo5UNSPvPoXC+5uOCgaBrM4glFkv3vQder9
4fmFrCH6+O77tXlqAvWDFfqVtRgfdudXQaH3hCO9jDHuAsZYQ2pA/yRBtjPO63ut
FNBDz7917G1avpSDbtdx7EC4aDbIKpCc0G5knOY+KG7FO3CkxX3/kQ348vcn3c0E
Biw6zngj00MvSXflThMtGIxDXS59cMTbX9yaseYFNxT4gopaDEciB6thIEODtcyP
CZNftDKbGblQNZEru4v3XKZ7Him0cw34k+nWmpD4SaSriYpWn49r4XtktKr4EWu5
kmaqRgRdu10XUuEXNoaAcB9kRUdvEvLLNyArbDYyp+1am6n6RzSoGnmNHYThKZ6p
ZJfzg2R5np1yKgUNTljs/yzXxaJcsuYIJo4XEuOZLlB/pj/vbKpFCA342/wV9EIp
LRPRTCs+ch/pDCq9OGBcJ91jfDKswPAGhRrcZGfZRLy8g/xlKhoMBHfqKQb43jW6
S80jxocRv03M2NAgVChQ3bLjIfKdZxonERVukqw8rGZwhjG8VTmF/p9lAinWzDZR
8uIVkxNvobVHr8wgx5T+RDdZkJhG/b56HMGHeleUBdsKYPPKQhsBiTUCAwEAAQ==
—–END RSA PUBLIC KEY—–

Reparem que a primeira chave pública gerada possui o header “—–BEGIN PUBLIC KEY—--“, e agora a chave pública gerada com o argumento “-RSAPublicKey_out” tem um header diferente: —–BEGIN RSA PUBLIC KEY—–

  • Gerando a chave pública no formato PKCS#1 a partir do formato PKCS#8

Se você já tem a chave pública, apenas precisa trocar de PKCS#8 para PKCS#1 com a OpenSSL, basta utilizar:

openssl rsa -pubin -in note-juliow-ssd-public.key -RSAPublicKey_out -out note-juliow-ssd-public_rsa.key

Com isso, agora sim nós temos uma chave pública no formato PKCS#1, que a função RSAModulus() do AdvPL consegue extrair o módulo, basta informar o nome do arquivo adequado “note-juliow-ssd-public_rsa.key”

Por dentro das chaves criptográficas – Expoente

Uma segunda informação importante das chaves criptográficas é o “expoente público”, que está presente  — e igual — em ambas as chaves, privada e pública. Normalmente o expoente utilizado é o número 65537 — por razões de segurança e compatibilidade. Utilizando a função RSAExponent(), podemos obter este número. A sintaxe e parâmetros da função RSAExponent() é igual a RSAModulus(), e o retorno também é uma string AdvPL em formato binário (RAW), contendo bytes de 0 a 255 — que podem ser convertidos para hexadecimal usando a mesma função do exemplo anterior 😀

Conclusão

Por hora, posso concluir que já vimos bastante informações sobre criptografia, chaves criptográficas, OpenSSL e AdvPL. Mas posso afirmar que ainda temos mais conteúdo a frente 😀

Espero que estas informações lhes sejam úteis, e lhes desejo novamente TERABYTES DE SUCESSO !!!!

Referências

 

Um comentário sobre “Criptografia em AdvPL – Parte 14

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