Página 1 de 2

Assinar texto/arquivo com certificado digital pelo windows

Enviado: 04 Out 2017 14:05
por dbsh
Gera DigestValue, SignatureValue, X509 para incluir em XML
DigestValue = Hash SHA256/SHA512, entre outros
SignatureValue = DigestValue assinado

Assina texto/arquivo digitalmente

Código: Selecionar todos

#pragma /es3
#pragma /w3

#define __TESTE__

//xp, window vista, 2003 server ou posterior
//Capicom.dll - Capicom 2.0 - Capicom.h

#define CAPICOM_HASH_ALGORITHM_SHA1     0
#define CAPICOM_HASH_ALGORITHM_MD2      1
#define CAPICOM_HASH_ALGORITHM_MD4      2
#define CAPICOM_HASH_ALGORITHM_MD5      3
#define CAPICOM_HASH_ALGORITHM_SHA_256  4
#define CAPICOM_HASH_ALGORITHM_SHA_384  5
#define CAPICOM_HASH_ALGORITHM_SHA_512  6

#define CAPICOM_ENCRYPTION_ALGORITHM_RC2  0
#define CAPICOM_ENCRYPTION_ALGORITHM_RC4  1
#define CAPICOM_ENCRYPTION_ALGORITHM_DES  2
#define CAPICOM_ENCRYPTION_ALGORITHM_3DES 3
#define CAPICOM_ENCRYPTION_ALGORITHM_AES  4 // v2.0

#define CAPICOM_ENCRYPTION_KEY_LENGTH_MAXIMUM  0 
#define CAPICOM_ENCRYPTION_KEY_LENGTH_40_BITS  1 
#define CAPICOM_ENCRYPTION_KEY_LENGTH_56_BITS  2 
#define CAPICOM_ENCRYPTION_KEY_LENGTH_128_BITS 3 
#define CAPICOM_ENCRYPTION_KEY_LENGTH_192_BITS 4 // AES v2.0 
#define CAPICOM_ENCRYPTION_KEY_LENGTH_256_BITS 5 // AES v2.0 

#define CAPICOM_ENCODE_ANY    0xffffffff 
#define CAPICOM_ENCODE_BASE64 0 
#define CAPICOM_ENCODE_BINARY 1 

#define CAPICOM_CERTIFICATE_INCLUDE_CHAIN_EXCEPT_ROOT 0
#define CAPICOM_CERTIFICATE_INCLUDE_WHOLE_CHAIN       1
#define CAPICOM_CERTIFICATE_INCLUDE_END_ENTITY_ONLY   2

#define CAPICOM_LOCAL_MACHINE_STORE          1
#define CAPICOM_CURRENT_USER_STORE           2
#define CAPICOM_STORE_OPEN_READ_ONLY         0
#define CAPICOM_STORE_OPEN_READ_WRITE        1
#define CAPICOM_STORE_OPEN_MAXIMUM_ALLOWED   2
#define CAPICOM_CERTIFICATE_FIND_SHA1_HASH   0
#define CAPICOM_AUTHENTICATED_ATTRIBUTE_SIGNING_TIME 0

#define CAPICOM_VERIFY_SIGNATURE_ONLY 0

#ifdef __TESTE__
PROCEDURE TesteCapicom
LOCAL sTexto, aAss, sCript, sDescript, DigestValue, SignatureValue, x509

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

DigestValue    := HashCapicom( sTexto )
aAss           := SignatureCapicom( DigestValue )
SignatureValue := aAss[1]
X509           := aAss[2]

HB_SYMBOL_UNUSED( x509 )

?
? DigestValue == CHKSignatureCapicom( SignatureValue )
? IsValidSignatureCapicom( DigestValue, SignatureValue )

sCript    := CriptCapiCom( sTexto, DigestValue, 4, 5 )
sDescript := DescriptCapiCom( sCript, DigestValue, 4, 5 )

?
? sDescript == sTexto

//sCript    := criptCapiCom( sTexto, PafChavePrivada(), 4, 5 )
//sDescript := DescriptCapiCom( sCript, PafChavePublica(), 4, 5 )

?
? sDescript == sTexto

wait
RETURN
#endif


//Esta função só cria um hash da string passada como parâmetro
FUNCTION HashCapicom( sTexto, AlgoritimoHash  )
LOCAL objHash

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

IF AlgoritimoHash = NIL
   AlgoritimoHash := CAPICOM_HASH_ALGORITHM_SHA_256
ENDIF

objHash := CreateObject("CAPICOM.HashedData.1")
objHash:Algorithm := AlgoritimoHash
objHash:Hash( sTexto )

RETURN objHash:Value


//Esta função assina string passada como parâmetro
//DigestValue = Hash Gerado por HashCapicom
FUNCTION SignatureCapicom( DigestValue, Cert, Encode )
LOCAL SignedData, CertBase64, Signer, sRet, TimeAttrib

//System.Security.Cryptography.Pkcs

IF DigestValue = NIL
   RETURN NIL
ENDIF

IF Encode = NIL
   Encode := CAPICOM_ENCODE_BASE64
ENDIF

//Signer := CreateObject("CAPICOM.Signer.1")  //versao 1
Signer := CreateObject("CAPICOM.Signer.2")  //versao 2

IF Cert = NIL
   Cert := SelecionaCertificadoCapicom()
   IF Cert = NIL
      RETURN NIL
   ENDIF
   Signer:Certificate := cert
ELSE
   Signer:Certificate := cert:DefaultInterface
ENDIF

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

Signer:Options := CAPICOM_CERTIFICATE_INCLUDE_CHAIN_EXCEPT_ROOT

//usado na chave <X509Certificate>
CertBase64 := Signer:Certificate:Export(CAPICOM_ENCODE_BASE64)
CertBase64 := Trim(StrTran(certBase64, Chr(13) + Chr(10), ''))

TimeAttrib :=  CreateObject("CAPICOM.Attribute")
TimeAttrib:Name := CAPICOM_AUTHENTICATED_ATTRIBUTE_SIGNING_TIME
TimeAttrib:Value = DateTime()

Signer:AuthenticatedAttributes:Add(TimeAttrib)

SignedData := CreateObject("CAPICOM.SignedData.1")
SignedData:Content := DigestValue

//segundo parametro falso, apenas retona assinatura do texto, não inclui no texto
sRet := SignedData:Sign(Signer, .F., Encode)

RETURN {sRet, CertBase64}


//Esta função retorna Hash sem Assinatura
//sAss = Hash Assinada
FUNCTION CHKSignatureCapicom( sAss )
LOCAL SignedData

IF sAss = NIL
   RETURN NIL
ENDIF

SignedData := CreateObject("CAPICOM.SignedData.1")
SignedData:Verify( sAss, .F., CAPICOM_VERIFY_SIGNATURE_ONLY);

RETURN SignedData:Content


//Esta função Verifica se assinatura e valida
//DigestValue = Hash
//SignatureValue = Hash Assinada
FUNCTION IsValidSignatureCapicom( DigestValue, SignatureValue )

IF DigestValue = NIL .or. SignatureValue = NIL
   RETURN .F.
ENDIF

RETURN CHKSignatureCapicom( SignatureValue ) == DigestValue


//carrega certificado digital
FUNCTION SelecionaCertificadoCapicom()
LOCAL MyStore, Certificates

MyStore := CreateObject("CAPICOM.Store")
MyStore:Open(CAPICOM_CURRENT_USER_STORE, "My", CAPICOM_STORE_OPEN_READ_ONLY)

begin sequence with {|| Break() }
   Certificates := MyStore:Certificates:Select("Selecione um certificado digital","Algoritimo de Assinatura SHA256RSA")
recover
   RETURN NIL
end

IF MyStore:certificates:Count = 0
   RETURN NIL
ENDIF

RETURN certificates:Item(1)




Assinar texto/arquivo com certificado digital pelo windows

Enviado: 05 Out 2017 14:58
por JoséQuintas
Legal.
Testar isso pra ver se bate com a assinatura que uso hoje.
Se isso eliminar a necessidade do MSXML5 vai ser bom.

Assinar texto/arquivo com certificado digital pelo windows

Enviado: 10 Out 2017 19:13
por JoséQuintas
Ainda não comparei com a que uso pra assinar XML, mas coloquei na pasta de rascunhos (drafts) da Sefazclass.
Fonte modificado e usando classe.

https://github.com/JoseQuintas/sefazcla ... apicom.prg

Até aproveitei pra criar um CH completo da CAPICOM, com tudo que pude encontrar.
Pode ser útil pra qualquer fonte que use CAPICOM.

https://github.com/JoseQuintas/sefazcla ... capicom.ch

Lembrando que, como está na pasta da sefazclass, pra quem usar, basta indicar sefazclass.hbc (e mais o #include lógico)
Neste caso a indicação da sefazclass só vai servir pra indicar aonde encontrar o arquivo capicom.ch e nada mais.

Assinar texto/arquivo com certificado digital pelo windows

Enviado: 10 Out 2017 19:15
por JoséQuintas
A propósito....
O Harbour tem funções de hash.
Caso dê certo, talvez dê pra fazer pelo Harbour, e só reste a assinatura mesmo.

Assinar texto/arquivo com certificado digital pelo windows

Enviado: 04 Dez 2017 11:04
por AlainSilva
Ola bom dia, sou novo no fórum. Estou usando a classe e estou tendo o seguinte erro:
METHOD HashData( cData, nAlgorithm ) CLASS CapicomClass
LOCAL oCapicom
IF cData = NIL
cData := DToS( Date() ) + Time()
ENDIF
IF nAlgorithm = NIL
nAlgorithm := CAPICOM_HASH_ALGORITHM_SHA_256
ENDIF
oCapicom := CreateObject("CAPICOM.HashedData.1")
oCapicom:Algorithm := nAlgorithm
oCapicom:Hash( cData )
RETURN oCapicom:Value

Error occurred at: 04/12/2017, 08:50:26
   Error description: Error CAPICOM.HashedData.1/9  The HashedData object does not contain hashed value.
: _ALGORITHM
   Args:
     [   1] = N   4

Seria a versão da capicom.dll? Se for onde baixo essa dll?
Obrigado

Assinar texto/arquivo com certificado digital pelo windows

Enviado: 04 Dez 2017 12:56
por Daniel

Assinar texto/arquivo com certificado digital pelo windows

Enviado: 04 Dez 2017 14:26
por AlainSilva
Ola Daniel, não adiantou, atualizei, alias era a que eu já tinha, registrei e o erro continua.
Não aceita o oCapicom:Algorithm := nAlgorithm (nAlgorithm = 4 )
Error description: Error CAPICOM.HashedData.1/9 The specified encryption algorithm is invalid.
: _ALGORITHM
Args:
[ 1] = N 4

Assinar texto/arquivo com certificado digital pelo windows

Enviado: 04 Dez 2017 16:18
por Daniel
você tem certeza que esta pegando a versão nova?
pelo cmd usa este comando na pasta raiz
dir /s capicom.dll
ele vai mostra onde as capicom.dll esta

Assinar texto/arquivo com certificado digital pelo windows

Enviado: 04 Dez 2017 17:08
por AlainSilva
Sim Daniel, é a mesma que eu uso pra nfe. Registrei regsvr32 capicom
.DLL certinho. O detalhe é que estou utilizando o xbarbour e não o harbour. Será que pode ser isso? O sha1 vai de boa. Sha256 da pau.

Assinar texto/arquivo com certificado digital pelo windows

Enviado: 04 Dez 2017 17:24
por Daniel
tem esta linha
#define CAPICOM_HASH_ALGORITHM_SHA_256 4
se tiver ai e erro no xHarbour
testei aqui deu certo

testa assim pra ver se da certo

Código: Selecionar todos

FUNCTION HashCapicom(stexto, AlgoritimoHash   )
	LOCAL objHash

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

	IF AlgoritimoHash = NIL
	   AlgoritimoHash := 4
	ENDIF

	objHash := CreateObject("CAPICOM.HashedData.1")
	objHash:Algorithm := AlgoritimoHash
	objHash:Hash( sTexto )

	RETURN objHash:Value

Assinar texto/arquivo com certificado digital pelo windows

Enviado: 04 Dez 2017 19:01
por JoséQuintas
Problema 1: dependendo da versão da CAPICOM, ela não tem o algorítmo SHA256

Problema 2: XHARBOUR, LIBs e BORLAND C

Por mais que se fale.... não adianta... volta sempre a mesma questão.

XHarbour... é interessante... mas não tem atualização, tem problemas.
LIBs... tentam consertar o XHarbour... cada uma faz de um jeito a mesma coisa...
Borland C... permite rotinas duplicadas no EXE... ou seja, nunca se sabe o que vai ser executado, pode ser a rotina certa, pode ser a rotina errada...

Tente num fonte em separado, antes de acrescentar ao aplicativo.
De preferência, CONSOLE, pra não precisar de nenhuma LIB Lixo.

Se assim funcionar, aí avise a LIB Lixo pra ser corrigida.
Avisar XHarbour não adianta... nunca mais vão corrigir nada nele....

Assinar texto/arquivo com certificado digital pelo windows

Enviado: 05 Dez 2017 08:08
por AlainSilva
Bom dia, Daniel eu já tinha feito isso de passar o valor direto para a variável mas o erro persiste. Bom, primeiro acho que preciso saber se estou com a capicom correta.
Se possível tem como me enviar a capicom que tem o algoritimo sha256?
meu email: alainsilva73@gmail.com

Minha capicom: data: 11/04/2007 CAPICOM.DLL tam: 511.328 bytes


Agora se eu estiver a capicom correta e o problema for o xharbour não tem outra opção, vou ter que passar a usar o harbour.

Assinar texto/arquivo com certificado digital pelo windows

Enviado: 05 Dez 2017 10:18
por JoséQuintas
O que faço sempre é tentar fazer o programador usar a cabeça.
Não precisa acreditar no que escrevem, e também não adianta nada virar "copiador de fonte".

Isso não é nada do outro mundo, é relativamente simples.
MICROSOFT FORNECE ÚLTIMA CAPICOM.

uma rápida pesquisa no google sobre capicom e sha256:
capicom.png
O primeiro link aberto
capicom2.png
Uma pesquisa de capicom download
capicom3.png
Olhem só que interessante....
O KIT CAPICOM da Microsoft vém até com muitos exemplos.

Assinar texto/arquivo com certificado digital pelo windows

Enviado: 05 Dez 2017 17:20
por AlainSilva
Obrigado pela ajuda, consegui rodar a rotina, vou fazer mais testes.

Assinar texto/arquivo com certificado digital pelo windows

Enviado: 06 Dez 2017 14:19
por AlainSilva
boa tarde, como eu já tenho as funções da nfe e do manifesto que utiliza sha1, estou fazendo os testes pra ver se assinatura fica igual.
Percebi o seguinte. O xml seria esse:
cTexto := '<envEvento xmlns="http://www.portalfiscal.inf.br/nfe" versao="1.00"><idLote>1</idLote><evento xmlns="http://www.portalfiscal.inf.br/nfe" versao="1.00"><infEvento Id="ID2102103517115233147700015355001000097206106174393001"><cOrgao>91</cOrgao><tpAmb>2</tpAmb><CNPJ>43198696000468</CNPJ><chNFe>35171152331477000153550010000972061061743930</chNFe><dhEvento>2017-12-06T11:24:08-02:00</dhEvento><tpEvento>210210</tpEvento><nSeqEvento>1</nSeqEvento><verEvento>1.00</verEvento><detEvento versao="1.00"><descEvento>Ciencia da Operacao</descEvento></detEvento></infEvento><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><Si ... tionMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n- ... tureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/><Reference URI="#ID2102103517115233147700015355001000097206106174393001"><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#envel ... <Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n- ... gestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" ... /envEvento>'

A tag <X509Certificate> traz igual. Já a TAg <DigestValue> na minha rotina sempre traz um valor diferente. por exemplo: em 3 envios do mesmo xml ficou assim:
1vez)SbaWmCq15aemJKCpXeRbqh5padA=
2vez)HKckad0MNEeT5MomesU6eoG936A=
3vez)r8xDsLDicSAsUFTK8JlYacfm2Ko=

Já nessa rotina o cDigestValue é sempre o mesmo e diferente desses: F0D98762598842AE8C61B6CE5A595E397C698D87

obs: eu alterei para sha1 ok ( nAlgorithm := CAPICOM_HASH_ALGORITHM_SHA1 ou 0)