Clipper On Line • Ver Tópico - Assinar texto/arquivo com certificado digital pelo windows

Assinar texto/arquivo com certificado digital pelo windows

Aqui você poderá oferecer suas Contribuições, Dicas e Tutoriais (Texto ou Vídeo) que sejam de interesse de todos.

Moderador: Moderadores

 

Assinar texto/arquivo com certificado digital pelo windows

Mensagempor rochinha » 07 Dez 2017 18:11

Amiguinhos,

ao testar me faltou as funções:


HB_SYMBOL_UNUSED()
CriptCapiCom()
DescriptCapiCom()
OPS! LINK QUEBRADO? Veja ESTE TOPICO antes e caso não encontre ENVIE seu email com link do tópico para fivolution@hotmail.com. Agradecido.

@braços : ? )

A justiça divina tarda mas não falha, enquanto que a justiça dos homens falha porque tarda.
Avatar de usuário

rochinha
Membro Master

Membro Master
 
Mensagens: 4532
Data de registro: 18 Ago 2003 20:43
Cidade/Estado: São Paulo - Brasil
Curtiu: 796 vezes
Mens.Curtidas: 242 vezes

Assinar texto/arquivo com certificado digital pelo windows

Mensagempor JoséQuintas » 19 Jan 2018 16:51

Só hoje testei isso.
O mais próximo que cheguei foi alterando a rotina de Hash, mas o digest value não bate.

Sha1, porque está no manual da NFE.
O resto peguei numa rotina da NET.

   IF nAlgorithm = NIL
      nAlgorithm := CAPICOM_HASH_ALGORITHM_SHA1 // 256
   ENDIF

   oUtil    := win_OleCreateObject( "CAPICOM.Utilities" )
   oCapicom := win_OleCreateObject( "CAPICOM.HashedData.1" )
   oCapicom:Algorithm := nAlgorithm
   oCapicom:Hash( cData )

   RETURN oUtil:Base64Encode( outil:HexToBinary( oCapicom:Value ) )


DigestValue PwA/AD8APwA/AD8APwA/AD8APwA=

DigestValue d/H7RrkNBl1a159pNWFgKKycQ9k=


Se o digestvalue não bate... nem adianta assinar, porque é o digestvalue que é assinado.
Falta algum detalhe referente ao XML.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 17942
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

Assinar texto/arquivo com certificado digital pelo windows

Mensagempor JoséQuintas » 19 Jan 2018 17:00

Inclusive tem uma parte, não chega a ser errada, mas é só pra complicar:

Signer := CreateObject("CAPICOM.Signer.2") //versao 2
Signer:Certificate := cert
CertBase64 := Signer:Certificate:Export(CAPICOM_ENCODE_BASE64)


a rotina acima coloca o certificado no "assinador", pra extrair o certificado....

Mais prático eliminar isso e usar direto o certificado:

Cert:Export( CAPICOM_ENCODE_BASE64 )
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 17942
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

Assinar texto/arquivo com certificado digital pelo windows

Mensagempor JoséQuintas » 19 Jan 2018 17:06

A rotina alterada:

/*
http://www.pctoledo.com.br/forum/viewtopic.php?f=43&t=18664
*/

#define __TESTE__

#include "sefaz_capicom.ch"
#include "hbclass.ch"
#ifdef __TESTE__

PROCEDURE TesteCapicom

   LOCAL cTexto, cSignatureValue, cDigestValue, cPublicKey

   cTexto    := "texto a ser gerado hash, no caso de arquivo, carregue o arquivo e passe para esta funcao"

   cDigestValue    := CapicomClass():HashData( cTexto )
   cSignatureValue := CapicomClass():Sign( cDigestValue, , , @cPublicKey )

   ?
   ? cDigestValue == CapicomClass():VerifySignature( cSignatureValue )
   ? IsValidSignatureCapicom( cDigestValue, cSignatureValue )
   ? cPublicKey

   WAIT

   RETURN
#endif

FUNCTION IsValidSignatureCapicom( cDigestValue, cSignatureValue )

   IF cDigestValue = NIL .OR. cSignatureValue = NIL
      RETURN .F.
   ENDIF

   RETURN CapicomClass():VerifySignature( cSignatureValue ) == cDigestValue

CREATE CLASS CapicomClass

   METHOD SelectCertificate()
   METHOD VerifySignature( cSignedData )
   METHOD HashData( cData, nAlgorithm )
   METHOD PublicKey( oCAPICOMCert )
   METHOD Sign( cDigestValue, oCAPICOMcert, nEncode, cPublicKey )

   END CLASS

METHOD SelectCertificate() CLASS CapicomClass

   LOCAL oCapicom, oCertificate

   oCapicom:= win_OleCreateObject( "CAPICOM.Store" )
   oCapicom:Open( CAPICOM_CURRENT_USER_STORE, "My", CAPICOM_STORE_OPEN_READ_ONLY )
   BEGIN SEQUENCE WITH { || __BreakBlock() }
      oCertificate := oCapicom:Certificates:Select( "Selecione um certificado digital", "Algoritmo de Assinatura SHA256RSA" )
   END SEQUENCE
   IF oCapicom:Certificates:Count() == 0
      RETURN NIL
   ENDIF

   RETURN oCertificate:Item( 1 )

METHOD VerifySignature( cSignedData ) CLASS CapicomClass

   LOCAL oCapicom

   IF cSignedData == NIL
      RETURN NIL
   ENDIF

   oCapicom := win_OleCreateObject( "CAPICOM.SignedData.1" )
   oCapicom:Verify( cSignedData, .F., CAPICOM_VERIFY_SIGNATURE_ONLY )

   RETURN oCapicom:Content

METHOD HashData( cData, nAlgorithm ) CLASS CapicomClass

   LOCAL oCapicom, oUtil

   IF cData = NIL
      cData := DToS( Date() ) + Time()
   ENDIF

   IF nAlgorithm = NIL
      nAlgorithm := CAPICOM_HASH_ALGORITHM_SHA1 // 256
   ENDIF

   oUtil    := win_OleCreateObject( "CAPICOM.Utilities" )
   oCapicom := win_OleCreateObject( "CAPICOM.HashedData.1" )
   oCapicom:Algorithm := nAlgorithm
   oCapicom:Hash( cData )

   RETURN oUtil:Base64Encode( outil:HexToBinary( oCapicom:Value ) )
   // RETURN oCapicom:Value

METHOD PublicKey( oCapicomCert ) CLASS CapicomClass

   LOCAL cPublicKey

   //oCapicom := win_OleCreateObject( "CAPICOM.Signer.2" )
   //oCapicom:Signer:Certificate := oCAPICOMCert
   //oCapicom:Signer:Options := CAPICOM_CERTIFICATE_INCLUDE_CHAIN_EXCEPT_ROOT
   cPublicKey := StrTran( /* oCapicom:Certificate:*/ oCapicomCert:Export( CAPICOM_ENCODE_BASE64 ), Chr(13) + Chr(10), "" )

   RETURN cPublicKey

METHOD Sign( cDigestValue, oCAPICOMCert, nEncode, cPublicKey ) CLASS CapicomClass

   LOCAL oCAPICOMSignedData, oCAPICOMSigner, oCAPICOMTimeStamp, cSignature

   IF cDigestValue = NIL
      RETURN NIL
   ENDIF

   IF nEncode = NIL
      nEncode := CAPICOM_ENCODE_BASE64
   ENDIF

   oCAPICOMSigner := win_OleCreateObject( "CAPICOM.Signer.2" ) // versao 2

   IF oCAPICOMCert = NIL
      oCAPICOMCert := ::SelectCertificate()
      IF oCAPICOMCert = NIL
         RETURN NIL
      ENDIF
      oCAPICOMSigner:Certificate := oCAPICOMcert
   ELSE
      oCAPICOMSigner:Certificate := oCAPICOMcert:DefaultInterface
   ENDIF

   IF ! ( oCAPICOMSigner:Certificate:HasPrivateKey ;
         .AND. DToS( oCAPICOMSigner:Certificate:ValidFromDate ) <= DToS( Date() ) ;
         .AND. DToS( oCAPICOMSigner:Certificate:ValidToDate ) >= DToS( Date() ) )
      RETURN NIL
   ENDIF

   oCAPICOMSigner:Options := CAPICOM_CERTIFICATE_INCLUDE_CHAIN_EXCEPT_ROOT
   cPublicKey             := StrTran( oCAPICOMSigner:Certificate:Export( CAPICOM_ENCODE_BASE64 ), Chr(13) + Chr(10), "" )

   oCAPICOMTimeStamp := win_OleCreateObject( "CAPICOM.Attribute" )
   oCAPICOMTimeStamp:Name  := CAPICOM_AUTHENTICATED_ATTRIBUTE_SIGNING_TIME
   oCAPICOMTimeStamp:Value := hb_DateTime()

   oCAPICOMSigner:AuthenticatedAttributes:Add( oCAPICOMTimeStamp )

   oCAPICOMSignedData := win_OleCreateObject( "CAPICOM.SignedData.1" )
   oCAPICOMSignedData:Content := cDigestValue

   // segundo parametro falso, apenas retona assinatura do texto, não inclui no texto
   cSignature := oCAPICOMSignedData:Sign( oCAPICOMSigner, .F., nEncode )

   RETURN cSignature


E a rotina que usei pra teste:

PROCEDURE Main

   LOCAL cXml, cDigestValue, cSignatureValue, cXml2, cPublicKey

   cPublicKey      := CapicomClass():PublicKey( CapicomCertificado( "CORDEIRO" ) )
   cXml            := MemoRead( "X.XML" )
   cXml2           := cXml
   cXml            := XmlNode( cXml, "infNFe", .T. )
   cDigestValue    := CapicomClass():HashData( cXml )
   cSignatureValue := CapicomClass():Sign( cDigestValue, , , @cPublicKey )

   CapicomAssinaXml( @cXml2, "CORDEIRO" )
   hb_MemoWrit( "d:\temp\assinado.xml", cXml2 )

   ? "DigestValue", cDigestValue
   ? "DigestValue", XmlNode( cXml2, "DigestValue" )
   ? cDigestValue == XmlNode( cXml2, "DigestValue" )
   ? cSignatureValue == XmlNode( cXml2, "SignatureValue" )
   ? cPublicKey == XmlNode( cXml2, "X509Certificate" )
   Inkey(0)

   RETURN


Compilei usando isto:

hbmk2 test.prg \cdrom\fontes\integra\sefazclass\drafts\assinaturacapicom.prg -otest josequintas.hbc -gtwin
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 17942
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

Assinar texto/arquivo com certificado digital pelo windows

Mensagempor sygecom » 20 Jan 2018 08:10

Ze,
Tenho uma sugestão. Depois de usar o METODO OPEN() da CAPICOM.Store, seria bom fechar o mesmo com: oCapicom:close(), isso evita corromper o certificado A3 que fica gravado nos pendrive/cartão, para certificado A1, se acontecer é só instalar de novo.

oCapicom:= win_OleCreateObject( "CAPICOM.Store" )
oCapicom:Open( CAPICOM_CURRENT_USER_STORE, "My", CAPICOM_STORE_OPEN_READ_ONLY )
BEGIN SEQUENCE WITH { || __BreakBlock() }
    oCertificate := oCapicom:Certificates:Select( "Selecione um certificado digital", "Algoritmo de Assinatura SHA256RSA" )
END SEQUENCE
oCapicom:close()


https://msdn.microsoft.com/en-us/library/windows/desktop/aa388120%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396
Leonardo Machado
xHarbour.org + Hwgui + PostgreSql
leonardodemachado@hotmail.com

Faça você também sua doação esse fórum é uma lenda viva: http://www.pctoledo.com.br/doacao
Avatar de usuário

sygecom
Usuário Nível 7

Usuário Nível 7
 
Mensagens: 6987
Data de registro: 21 Jul 2006 10:12
Cidade/Estado: Alvorada-RS
Curtiu: 1 vez
Mens.Curtidas: 127 vezes

Assinar texto/arquivo com certificado digital pelo windows

Mensagempor JoséQuintas » 20 Jan 2018 08:46

Lembro de ter gerado erro no Close(), por isso deixei de usar.
Uso assim há anos e nunca tive problema.
Mas vou fazer novos testes.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 17942
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

Anterior



Retornar para Contribuições, Dicas e Tutoriais

Quem está online

Usuários vendo este fórum: Nenhum usuário registrado online e 2 visitantes


Ola Amigo, espero que meu site e forum tem lhe beneficiado, com exemplos e dicas de programacao.
Entao divulgue o link da Doacao abaixo para seus amigos e redes sociais ou faça uma doacao para o site forum...
MUITO OBRIGADO PELA SUA DOACAO!
Faça uma doação para o forum
cron
v
Olá visitante, seja bem-vindo ao Fórum Clipper On Line!
Efetue o seu login ou faça o seu Registro