Processo de certificação de software de gestão e código-exemplo em VB.NET (full .NET Fx & .NET CF)
As empresas que produzem software de gestão estarão neste momento a par da necessidade de a partir de 1 de Janeiro de 2011 disponibilizarem aos seus clientes novas versões das suas aplicações que implementem os requisitos necessários à chamada ‘certificação de software’. O mecanismo a implementar passa por no momento da gravação de um documento criar um hash a partir das suas características, baseado num certificado asimétrico, que garantirá que nenhum dos elementos importantes do documento é editado depois de emitido.
A moving2u, apesar de não criar software de gestão na perspectiva ‘stand alone’, dado que a nossa solução de mobilidade para PDAs integra sempre com um sistema de gestão de terceiros (actualmente contempla Primavera, PHC, Eticadata, SAP Business One, Gexor, entre outros), também é visada por este processo de certificação. Assim sendo, no sentido de garantir a legalidade da sua utilização por parte dos nossos clientes visados por essa regulamentação, encetámos os passos necessários ao seu cumprimento, no sentido de disponibilizar até ao final do ano uma nova versão que assine cada um dos documentos legais com o referido hash, que imprima a informação requerida pela portaria e que permita gerar o ficheiro SAFT-PT, que até agora era sempre emitido pelo sistema onde os documentos eram integrados.
Para o processo da assinatura em si, passo a descrever os passos necessários para a geração do hash em aplicações .NET:
- descarregar o OpenSSL para Windows para criar as chaves privada e pública e gerar um hash para teste
http://www.shininglightpro.com/products/Win32OpenSSL.html
- descarregar o OpenSSLKey para poder converter a chave privada no formato PEM no formato XML
http://www.jensign.com/opensslkey/ (link no final da página)
- criar a chave privada
openssl genrsa -out MinhaChavePrivada.pem 1024
- criar a chave pública a aprtir da chave privada
openssl rsa -in MinhaChavePrivada.pem -out MinhaChavePublica.pem -outform PEM -pubout
- exportar a chave privada de ‘pem’ para ‘xml’
Correr o opensslkey, indicar o caminho do ficheiro PEM, na consola obtem-se entre outras coisas a chave privada em formato XML, copiar essa parte para um ficheiro .XML
- gerar um hash utilizando o openSSL para testar. Ter em conta que o Windows acrescenta um CR+LF ao echo, pelo que o valor obtido será sempre diferente do que as finanças obteriam para a mesma string
echo 2010-05-18;2010-05-18T11:22:19;FAC 001/14;3.12; | openssl dgst -sha1 -sign MinhaChavePrivada.pem | openssl enc -base64 –A
- gerar um hash utilizando o openSSL para testar. Criar um ficheiro string.txt com o conteúdo da string a encriptar, sem linefeed no final! …
copy con string.txt<ENTER>
2010-05-18;2010-05-18T11:22:19;FAC 001/14;3.12; <CTRL-Z><ENTER>
…e utilizar o seguinte comando
openssl dgst -sha1 -sign MinhaChavePrivada.pem string.txt| openssl enc -base64 –A
- código em VB.net (adicionar referência ao System.Security.Cryptography):
Imports System.Security.Cryptography
Imports System.Text
Module Module1
Sub Main()
' descomentar o vbCrLf caso se pretenda obter um hash comparável com o obtido com o openssl em Windows
Dim stringToHash As String = "2010-05-18;2010-05-18T11:22:19;FAC 001/14;3.12; " ' + vbCrLf
Using privatekey As RSACryptoServiceProvider = New RSACryptoServiceProvider
Dim privateKeyXML As String = System.IO.File.ReadAllText("C:\Trabalho\OpenSSL-Win64\bin\MinhaChavePrivada.xml")
privatekey.FromXmlString(privateKeyXML)
Dim buffer As Byte() = Encoding.GetEncoding("Windows-1252").GetBytes(stringToHash)
Dim signature As Byte() = privatekey.SignData(buffer, "SHA1")
Console.WriteLine(Convert.ToBase64String(signature))
End Using
End Sub
End Module
- A .NET CompactFramework 3.5 não suporta o método FromXmlString pelo que é preciso instanciar um objecto do tipo RSAParameters e preenchê-lo ‘manualmente’ (adicionar referências ao System.Xml e System.Xml.Linq):
Imports System.Security.Cryptography
Imports System.Text
Module Module1
Sub Main()
' descomentar o vbCrLf caso se pretenda obter um hash comparável com o obtido com o openssl em Windows
Dim stringToHash As String = "2010-05-18;2010-05-18T11:22:19;FAC 001/14;3.12; " ' + vbCrLf
Using privatekey As RSACryptoServiceProvider = New RSACryptoServiceProvider
Dim privateKeyXML As String = "..." ' carregar o xml da chave privada para esta string
Dim xe As XElement
xe = XElement.Load(privateKeyXML)
Dim rsaP As RSAParameters = New RSAParameters() With {.Modulus = Convert.FromBase64String(xe.Element("Modulus").Value), _
.Exponent = Convert.FromBase64String(xe.Element("Exponent").Value), _
.P = Convert.FromBase64String(xe.Element("P").Value), _
.Q = Convert.FromBase64String(xe.Element("Q").Value), _
.DP = Convert.FromBase64String(xe.Element("DP").Value), _
.DQ = Convert.FromBase64String(xe.Element("DQ").Value), _
.InverseQ = Convert.FromBase64String(xe.Element("InverseQ").Value), _
.D = Convert.FromBase64String(xe.Element("D").Value)}
privatekey.ImportParameters(rsaP)
Dim buffer As Byte() = Encoding.GetEncoding("Windows-1252").GetBytes(stringToHash)
Dim signature As Byte() = privatekey.SignData(buffer, "SHA1")
Debug.WriteLine(Convert.ToBase64String(signature))
End Using
End Sub
End Module
Actualizado em 2010/09/08 para usar um ficheiro com a string da qual queremos gerar o hash sem o problema do Echo em Windows. Outra alternativa é utilizar um comando Echo portado do equivalente em Unix e que com o switch –n não gera o linefeed.
Todos os processos e o código apresentados servem apenas para exemplificar a forma de obtenção do hash do documento, sem ter em conta regras de boas práticas de desenvolvimento, performance ou segurança, não devendo ser considerado para produção. Obviamente serão declinadas quaisquer reclamações sobre a utilização do mesmo.
Ideias para o seu desenvolvimento foi obtido a partir do fórum ‘Portugal a Programar’ http://www.portugal-a-programar.org/forum/index.php/topic,48555.15.html onde sugiro que sejam discutidas questões relacionadas com este tópico
Este post não tem como objectivo defender ou criticar o processo da certificação de software, pelo que todos os comentários nesse sentido não serão publicados.