Ir para conteúdo


- - - - -

Certificação de software

saft-pt

  • Por favor inicie sessão para responder
347 respostas a este tópico

#1 Manhoso

Manhoso

    Boolean User

  • Membro
  • PipPipPip
  • 148 mensagens

Publicado 30 de Julho de 2010 - 14:40

De acordo com os meus post nesta thread, vou começar a por ideias mais técnicas aqui.

Como disse ao undercover, a DGCI quer que enviemos o certificado gerado pelo openssl (ou pelo menos é essa a minha interpretação). Mas o busilis para quem trabalhar com .NET é que a M$ não trabalhar no mesmo formato. Continuo sem saber o porque deste desvio do standard de SSL.

Por causa disso, fiz um "parser" para a chave privada, no formato hex. Este formato   obtém-se da seguinte forma, depois de gerada a chave privadaa (PEM):
Código :
openssl rsa -in privada.key -text -noout

Obviamente não postar o código, pois estou no contexto de empresa...

Protocolo de testes: Gerar a encriptação em VB e decriptar usando openssl (linux)

O que sucede é que encriptação e decriptação funciona as mil maravilhas...Mas cedo reparei que não é isso que a DGCI quer. O que eles querem é a assinatura da hash SHA1. Tudo bem, a partir do momento em que tinha uma chave válida (penso eu, uma vez que consigo encriptar e decriptar), consigo gerar a assinatura da hash sem problemas.

O problema surge em validar a assinatura no linux (openssl). As assinaturas geradas não só não são dadas como válidas, como a assinatura gerada pelo openssl é completamente diferente, para os mesmos dados (deveria ser igual).

Ideias?
Hasta,

#2 undercover

undercover

    void

  • Membro
  • PipPip
  • 98 mensagens

Publicado 30 de Julho de 2010 - 16:39

Penso que se consegue fazer toda esta parte através de command line e system calls no VB.NET

Vou estudar bem o OpenSSL

#3 Manhoso

Manhoso

    Boolean User

  • Membro
  • PipPipPip
  • 148 mensagens

Publicado 30 de Julho de 2010 - 16:42

Poder pode... Mas era uma situacao a evitar. Por razoes de segurança e tal...
Além de que o open ssl no linux e em windows dá hashes diferentes. Nem estou a falar de hashes assinadas, as hashes dos dados dão diferentes.

Estou a estudar a tua sugestão, undercover. A da bouncy castle...Até agora ainda não está a fazer nada de jeito :S

#4 undercover

undercover

    void

  • Membro
  • PipPip
  • 98 mensagens

Publicado 30 de Julho de 2010 - 17:48

Eu acho que já consegui alguma coisa, apenas usando o OpenSSL  :D

gerei um par de chaves

a privada

Código (Bash):
openssl genrsa 1024 > private.key

e a pública

Código (Bash):
openssl rsa -in private.key -pubout -out public.key

depois assinei um ficheiro

Código (Bash):
openssl sha1 -sign private.key -out hash.bin Portaria_363_2010.pdf

e para verificar usei

Código (Bash):
openssl sha1 -verify public.key -signature hash.bin Portaria_363_2010.pdf

em principio deveria ser este o processo que a DGCI devia usar  :)

no entanto o campo onde vai estar a hash tem 200 caracteres de texto e por este processo é gerado um ficheiro binário com 128 bytes, será que se tem de colocar a assinatura em base64 ?  :hmm:

Citar

Além de que o open ssl no linux e em windows dá hashes diferentes

Vou testar, mas não devia acontecer ...

Citar

Poder pode... Mas era uma situacao a evitar. Por razoes de segurança e tal...

Penso que não haja grande problema em usar esta via, em ultimo caso posso inserir algumas medidas de segurança, mas o meu objectivo é por esta coisada a funcionar ... pois o nosso negócio não é andar a trabalhar para a DGCI  :wallbash: vou seguir o caminho do menor esforço, todo o tempo que eu perder com isto é tempo perdido em outras coisas mais úteis / lucráveis  :) 

#5 car4321

car4321

    CRLF

  • Membro
  • PipPipPipPipPip
  • 603 mensagens

Publicado 30 de Julho de 2010 - 18:22

Ver MensagemManhoso, em 30 de Julho de 2010 - 14:40, disse:


Como disse ao undercover, a DGCI quer que enviemos o certificado gerado pelo openssl (ou pelo menos é essa a minha interpretação).

Eles não querem o certificado. Juntamente com a declaração de Setembro a enviar online deverá ir um ficheiro .txt exclusivamente com a chave pública em PEM.

#6 car4321

car4321

    CRLF

  • Membro
  • PipPipPipPipPip
  • 603 mensagens

Publicado 30 de Julho de 2010 - 18:29

Ver MensagemManhoso, em 30 de Julho de 2010 - 14:40, disse:


O problema surge em validar a assinatura no linux (openssl). As assinaturas geradas não só não são dadas como válidas, como a assinatura gerada pelo openssl é completamente diferente, para os mesmos dados (deveria ser igual).

Ideias?
Hasta,

Manhoso, tenho algumas respostas na manga, mas preciso saber como é que assinaste em VB. É que há mil razões que não estarmos a assinar o texto/ ficheiro que pretendíamos.


Há algumas semanas que estou a fazer uma bateria de teste em vários campos.

Optei finalmente por implementar tudo com linhas de comando chamados a partir do VB, funciona tudo na perfeição e já posso pedir a certificação logo que possa cruzar teste com mais alguém. No entanto, para futuro, seria bom, implementar com o próprio VB. Para isso, preciso realmente de "companhia" nos aspectos técnicos.

#7 car4321

car4321

    CRLF

  • Membro
  • PipPipPipPipPip
  • 603 mensagens

Publicado 30 de Julho de 2010 - 18:36

Undercover, escreveste
openssl sha1 -sign private.key -out hash.bin Portaria_363_2010.pdf
mas tens de acrescentar o encoding em base64:

openssl enc -base64

Não estás a usar a especificação das regras técnicas ?

#8 undercover

undercover

    void

  • Membro
  • PipPip
  • 98 mensagens

Publicado 30 de Julho de 2010 - 18:48

Citar

Não estás a usar a especificação das regras técnicas ?
encontrei os links da FAQ e das especificações técnicas à cerca de 1/2 hora :)
tudo o que apresentei antes era baseado apenas na portaria

thanks pela dica da base64  :)

#9 undercover

undercover

    void

  • Membro
  • PipPip
  • 98 mensagens

Publicado 30 de Julho de 2010 - 19:54

Bem, depois de ler a documentação técnica da DGCI, o processo é simples em qualquer linguagem de programação.

Para isso usa-se o OpenSSL via linha de comandos, seja em Windows ou Linux, através de system calls no VB.NET/C#, no caso do PHP existe uma lib especifica para isso portanto os conceitos são os mesmos.

1º Criar chave privada encriptada (necessita password)
Código (Bash):
openssl genrsa -des3 -out private.pem 1024

2º Criar chave publica
Código (Bash):
openssl rsa -in private.pem -passin pass:minha_password -out public.pem -outform PEM –pubout

3º Criar Hash
Código (Bash):
echo "2010-05-18;2010-05-18T11:22:19;FAC 001/14;3.12; " | openssl dgst -sha1 -sign private.pem -passin pass:minha_password | openssl enc -base64 > hash.txt

4º Verificação (Opcional) -> deve dar Verified OK
Código (Bash):
type hash.txt | openssl enc -base64 -d > hash.bin
echo "2010-05-18;2010-05-18T11:22:19;FAC 001/14;3.12; " | openssl sha1 -verify public.pem -signature hash.bin

5º Entregar o public.pem à DGCI e implementar os system calls da vossa aplicação

PS: A chave privada ser encriptada é opcional, no entanto temos de assegurar que a chave não se sabe facilmente, o algoritmo pode ser mudado para outro para além do DES

#10 Manhoso

Manhoso

    Boolean User

  • Membro
  • PipPipPip
  • 148 mensagens

Publicado 01 de Agosto de 2010 - 23:22

Desculpem não ter dito nada no fim de semana, mas entretanto na sexta, consegui implementar o mecanismo como a DGCI quer. A cena de não andarmos a trabalhar para a DGCI para mim é treta...pois se não fizermos o mecanismo de cerrtificação, não temos a dita e por conseguinte vende-se menos...

A abordagem via sys calls chegou a estar em cima da mesa, mas apenas como último recurso, pois na minha opinião isso é estar a martelar. E para martelos já chegam os que são precisos para por o sw a funcionar.

Agora, passando a coisas práticas:

1º - Usando OpenSSL, gerar chave privada:

Código (Bash):
openssl genrsa -out privada.key 1024

2º - Gerar chave pública

Código (Bash):
openssl rsa -in privada.key -pubout -out publica.key

Agora, aqui temos várias hipoteses:
a) usar uma lib para traduzir de openssl para .NET(XML): Bouncy castle ou outra;
b)fazer a vossa propria lib para traduzir;
c) system calls (menos elegante);

Eu segui a via b) traduzindo a versão hexadecimal da chave privada. Primeiro obtive-a com:
Código (Bash):
openssl rsa -in privada.key -noout -text -out privada.hex

Esta abordagem tem a vantagem de não ter de me preocupar com endianess.

A partir dai é gerar a hash assinada e tá feito.

Com os testes preliminares que fiz ontem, as hashes estão válidas.
Amanha vou fazer os testes como deve ser.

Se usarem a abordagem com system calls não se esqueçam que o resultado tem de ir para a BD e não ficar num ficheiro de texto ;)

Resumindo, acho que até se consegue responder bem aos requisitos da DGCI...o texto que eles produziram é que não é dos mais claros... :P

Hasta

#11 undercover

undercover

    void

  • Membro
  • PipPip
  • 98 mensagens

Publicado 02 de Agosto de 2010 - 13:09

Citar

A cena de não andarmos a trabalhar para a DGCI para mim é treta...pois se não fizermos o mecanismo de cerrtificação, não temos a dita e por conseguinte vende-se menos...
Sim, mas não te vai aumentar as vendas, certo !?

Citar

A abordagem via sys calls chegou a estar em cima da mesa, mas apenas como último recurso, pois na minha opinião isso é estar a martelar. E para martelos já chegam os que são precisos para por o sw a funcionar.
Bem em relação a martelos, tens razão e não tens razão, se temos um SO e uma aplicação amplamente difundida como o OpenSSL que até a aconselhada e exemplificada pela DGCI, porque não usá-los em conjunto para chegarmos ao nosso objectivo, em vez de estarmos a reinventar a roda

Citar

Esta abordagem tem a vantagem de não ter de me preocupar com endianess.
Com base 64 tb não te precisas de preocupar daí ser amplamente usado em sistemas de rede de computadores

Citar

Se usarem a abordagem com system calls não se esqueçam que o resultado tem de ir para a BD e não ficar num ficheiro de texto
Sim isso está implícito na parte em que se tem de se "implementar os system calls da vossa aplicação"

Citar

o texto que eles produziram é que não é dos mais claros
A portaria está muito pouco clara, no entanto a FAQ e a documentação técnica está muito clara em relação a tudo, tenho pena de só ter encontrado estes dois documentos já no final da implementação.

A tua solução é muito boa no entanto não é nada útil à comunidade, pois a parte mais importante não é revelada, logo para quem queira fazer algo não vai encontrar na tua solução um caminho visível, só vai encontrar uma meia solução

#12 Manhoso

Manhoso

    Boolean User

  • Membro
  • PipPipPip
  • 148 mensagens

Publicado 02 de Agosto de 2010 - 21:09

Como disse anteriormente, apenas entrei nesta discussão para dar algum contributo, por muito minimo que seja. Agora, mais que isto não posso dar, pois a implementação, pese embora ter sido eu a fazer, não me pertence, mas sim a empresa para a qual trabalho...

Peço desculpa por não poder dar mais pormenores...Espero que compreendam.

#13 shotman

shotman

    null

  • Novo Membro
  • Pip
  • 5 mensagens

Publicado 03 de Agosto de 2010 - 10:29

Undercover, pelo teu método encriptando a chave privada, não há problema se os ficheiros contendo essa chave privada e respectiva pública estiverem disponíveis do lado do cliente, visto que está encriptada e não têm a nossa password? Obrigado.

#14 mganilho

mganilho

    null

  • Membro
  • Pip
  • 13 mensagens

Publicado 11 de Agosto de 2010 - 19:38

Boa tarde,
Já li e reli os vossos posts úteis, mas continuo com algumas dúvidas relacionadas com a assinatura que coloco a vossa consideração (se tiverem paciência para me responder  :cheesygrin:).

Utilizo VB.Net e já testei as mais variadas abordagens ao problema:
- system calls ao openssl:
Código (vb.net):
Dim procAssin As New Process()
        With procAssin.StartInfo
            .UseShellExecute = False
            .RedirectStandardOutput = True
            .RedirectStandardError = True
            .StandardOutputEncoding = Encoding.GetEncoding("Windows-1252")
            .FileName = "cmd.exe"
            .WorkingDirectory = "C:\OpenSSL-Win32\bin"
            .Arguments = "/c echo " & Chr(34) & Me.txtIn.Text & Chr(34) & " | openssl dgst -sha1 -sign C:\OpenSSL-Win32\bin\fzPrivateKey.pem -r | openssl enc -base64"
        End With
        procAssin.Start()
        procAssin.WaitForExit()
        Dim strErro As String = procAssin.StandardError.ReadToEnd()
        Dim strAssinatura As String = procAssin.StandardOutput.ReadToEnd()
        Me.txtOut2.Text = "Assinatura:" & _
                         vbCrLf & strAssinatura & strErro

- um dll da Chilkat (muito baseado no exemplo http://www.example-code.com/vbdotnet/rsa_openssl_sign.asp)

- a library System.Security da 2.0 (nomeadamente o Namespace System.Security.Cryptography), utilizando a PrivateKey gerada no OpenSSl e exportada para XML:
Código (vb.net):
Dim privateKey As RSACryptoServiceProvider
        Dim pkxml As String

        privateKey = New RSACryptoServiceProvider
        pkxml = ReadXMtoString("c:\fzPrivateKey.xml")
        privateKey.FromXmlString(pkxml)

        Dim buffer As Byte() = Encoding.Default.GetBytes(Me.txtIn.Text)
        Dim hash As Byte() = SHA1Managed.Create().ComputeHash(buffer)
        Dim formatter As RSAPKCS1SignatureFormatter = New RSAPKCS1SignatureFormatter(privateKey)

        formatter.SetHashAlgorithm("SHA1")

        Dim signature As Byte() = formatter.CreateSignature(hash)
        dt = New Data()
        dt.Bytes = signature

        Me.txtOut.Text = Me.txtOut.Text & _
                         vbCrLf & "Base64:" & dt.Base64 & _
                         vbCrLf & "Hex:" &  dt.Hex

Estas duas últimas opções são as que me agradam mais porque não tenho que instalar/distribuir os componentes do OpenSSl, nem o Microsoft Visual C++ 2008 Redistributable Package. E obviamente é mais interessante a última opção porque o Chillkat RSA é pago. Contudo, nas duas últimas opções não consigo obter a mesma assinatura (assim o acho na minha ignorância) que o openssl. Já testei com a versão 1.0.0a e 0.9.8odo Openssl, já mudei configurações e nada.

Alguém tem alguma sugestão? Uma vez que as regras técnicas da portaria referem a utilização do Openssl, não queria investir mais num sistema que não devolve resultados idênticos.

Já me ocorreu que o problema esteja relacionado com a versão do PKCS#1, que no .Net 2.0 é a v1.5 e no OpenSll actual é a v2.0 (acho eu). Fará isto sentido?

Obrigado pela atenção.

#15 Manhoso

Manhoso

    Boolean User

  • Membro
  • PipPipPip
  • 148 mensagens

Publicado 12 de Agosto de 2010 - 09:50

Também encontrei esse problema. para testar a assinatura tive que primeiro por num ficheiro, e gerar a hash desse ficheiro.

#16 undercover

undercover

    void

  • Membro
  • PipPip
  • 98 mensagens

Publicado 12 de Agosto de 2010 - 12:22

Código (vb.net):
        Dim buffer As Byte() = Encoding.Default.GetBytes(Me.txtIn.Text)
        Dim hash As Byte() = SHA1Managed.Create().ComputeHash(buffer)
        Dim formatter As RSAPKCS1SignatureFormatter = New RSAPKCS1SignatureFormatter(privateKey)

        formatter.SetHashAlgorithm("SHA1")

        Dim signature As Byte() = formatter.CreateSignature(hash)

Sem ter visto muita coisa sobre o teu código, parece-me que estás a fazer a mesma operação 2 vezes, posso estar enganado é só uma sugestão sem ter feito nenhum teste, tu vais buscar o texto no Me.txtIn.Text e convertes para bytes, portanto aqui tens um problema de encodings, devias não usar o Encoding.Default mas sim o Encoding.GetEncoding("Windows-1252"), depois disto tu crias logo a Hash mas se reparares o RSAPKCS1SignatureFormatter já faz isso quando defines qual o algoritmo de Hash que queres, aqui formatter.SetHashAlgorithm("SHA1"), penso que deverias gerar a assinatura apenas assim formatter.CreateSignature(buffer) e retirar a linha  Dim hash As Byte() = SHA1Managed.Create().ComputeHash(buffer).

#17 mganilho

mganilho

    null

  • Membro
  • Pip
  • 13 mensagens

Publicado 12 de Agosto de 2010 - 17:25

Muito obrigado ao manhoso e ao undercover pelos posts, foram de grande ajuda.

Citar

Também encontrei esse problema. para testar a assinatura tive que primeiro por num ficheiro, e gerar a hash desse ficheiro
Manhoso, tens toda a razão. Não utilizando o comando echo e assinando em vez disso um txt com a string, fica igualzinho ao output do .net. O mais engraçado é que depois de andar  :wallbash: e de tomar a informação das regras técnicas como certa, hoje ao almoço saiu este aditamento no site das DGCI:
http://info.portaldasfinancas.gov.pt/NR/rdonlyres/84B18C77-577B-4581-A846-2DB0201B0FB4/0/1_Aditamento_Especificaca_regras_tecnicas.pdf
E nem contempla a tua solução. Além disso, ainda acrescentam o que também descobri esta manhã: é necessário o argumento "-A" no comando "enc" para que o output seja todo em linha (sem line-feeds).

Citar

, parece-me que estás a fazer a mesma operação 2 vezes, ... penso que deverias gerar a assinatura apenas assim formatter.CreateSignature(buffer)
Undercover, na realidade o comando "RSAPKCS1SignatureFormatter.CreateSignature" destina-se apenas a assinar um hash e não o produz. Contudo, o teu post levou-me a rever o código e a descobrir que o objecto "RSACryptoServiceProvider" (que utilizo para suportar  a privatekey) possui um método para assinar, o "SignData" (este sim calculando o hash implicitamente). Assim, o código que apresentei no meu post anterior simplifica-se para:
Código (vb.net):
'referenciando o System.Security e importando o namespace System.Security.Cryptography
                 Dim privateKey As RSACryptoServiceProvider
        Dim pkxml As String
        Dim dt As Data

        privateKey = New RSACryptoServiceProvider
        pkxml = ReadXMtoString("c:\fzPrivateKey.xml") 'aqui pode ficar embutida a string da privatekey em vez de ler dum xml
        privateKey.FromXmlString(pkxml)

        Dim buffer As Byte() = Encoding.GetEncoding("Windows-1252").GetBytes(Me.txtIn.Text)
        Dim signature As Byte() = privateKey.SignData(buffer, "SHA1")

        dt = New Data()
        dt.Bytes = signature

        Me.txtOut.Text = "Signature:" & _
                vbCrLf & "Base64:" & vbCrLf & dt.Base64 & _
                vbCrLf & "Hex:" & vbCrLf & dt.Hex


Citar

...tens um problema de encodings, devias não usar o Encoding.Default mas sim o Encoding.GetEncoding("Windows-1252")...
Na realidade o meu Encoding.Default não produzia problemas, mas realmente fica muito melhor com uma referência explícita ao ("Windows-1252".

Mais uma vez, obrigado  :cheesygrin:.

#18 shotman

shotman

    null

  • Novo Membro
  • Pip
  • 5 mensagens

Publicado 13 de Agosto de 2010 - 11:37

Boas, seguindo o exemplo do mganilho, consigo gerar a hash correctamente com a private key (xml) e depois consigo validar essa hash com a public key correspondente (xml).
Agora tenho uma duvida. Por exemplo, quero encriptar a palavra XPTO; em windows, linux, e nesta abordagem em vb net, gerou-me 3 hash's diferentes.
Tenho uma versão (usando system calls no openssl) já implementada, mas precisa que a chave privada esteja disponível na pasta da aplicação, ainda que encriptada (já que sem a password ninguém consegue fazer nada dela).
Mas gostaria de ir pela última, usando a key exportada para XML. Só que a minha dúvida, é que pelo openssl, a frase XPTO dá origem a uma hash, e indo pelo vb net com a chave em xml gera-me outra hash totalmente diferente.

Depois como é para os senhores da dgci validarem? É que se lhes der uma hash gerada no VB, e eles a validarem com a chave publica em openssl, dá verification failure.

Obrigado desde já pela ajuda...

EDIT: OK esqueçam... já está tudo ok...

#19 baguera

baguera

    void

  • Membro
  • PipPip
  • 81 mensagens

Publicado 25 de Agosto de 2010 - 14:07

Boas, estou a trabalhar na certificaçao do Software mas estou a usar o VB6, a minha duvida é a seguinte qual a melhor forma, system calls, pois em VB6 não estou a ver outro jeito.
Agradeço a ajuda.

#20 mganilho

mganilho

    null

  • Membro
  • Pip
  • 13 mensagens

Publicado 25 de Agosto de 2010 - 15:28

Boa tarde baguera,
Podes utilizar perfeitamente o código .Net, desde que utilizes a técnica de Visual Basic Fusion explicada no artigo:
http://msdn.microsoft.com/en-us/library/ms364069(VS.80).aspx

Ou seja, crias um wrapper em VB.Net que depois podes referenciar em VB6 e utilizar normalmente.
Para tal basta:
  • criar um projecto "Class Library" em VB.Net
  • apagar a classe de defeito
  • inserir uma classe nova utilizando o template "COM Class" (não disponível em VS Express que te posso enviar por email se quiseres, já nem sei se o saquei há anos do artigo acima citado)
  • implementar o código normalmente
  • assinar o projecto (opcional mas tenho tido muito melhores resultados assim). Simplesmente fazer My Project>Signing, marcar "Sign the assembly" e criar uma nova chave (no combo seleccionar "<New...>"). Esta assinatura não tem nada a ver com o problema da encriptação que estamos a falar, utilizo-a em todos os wrappers que faço.
  • compilar o projecto (que origina automaticamente o registo do assembly como COM através da ferramenta regasm.exe (explicada mais à frente)
  • em VB6, na lista das referências COM, surge uma entrada para cada COM Class registada, basta seleccioná-la (também é possivel registar manualmente o ficheiro tlb que surge ao lado do dll)

A visibilidade COM das Classes .Net é conseguida pela utilização da ferramenta regasm.exe, embutida na .Net Framework desde a versão 1.1. Esta ferramenta regista o assembly .net, emulando o COM com base nos GUID's existentes no cabeçalho da COM Classs (por isso, não copiar uma COM Class sem os alterar, o template gera-os sempre de novo).

Para registar o dll noutro pc, ou noutra localização, utilizar um bat semelhante a este:
Código (DOS):
path=%path%;C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727

regasm /u "criptoWrapper.dll"
regasm /codebase /tlb "criptoWrapper.dll"

pause

Boa sorte  :D.