diff --git a/CTe.Utils/CTe/ExtCTe.cs b/CTe.Utils/CTe/ExtCTe.cs index e0f3d31f7..c43e6b003 100644 --- a/CTe.Utils/CTe/ExtCTe.cs +++ b/CTe.Utils/CTe/ExtCTe.cs @@ -33,7 +33,6 @@ using System; using System.IO; -using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Text; using System.Xml; @@ -297,7 +296,7 @@ public static infCTeSupl QrCode(this CteEletronica cte, X509Certificate2 certifi && cte.infCte.ide.tpEmis != tpEmis.teSVCSP ) { - var assinatura = Convert.ToBase64String(CreateSignaturePkcs1(certificadoDigital, encoding.GetBytes(chave))); + var assinatura = Convert.ToBase64String(AssinaturaDigital.CriarAssinaturaPkcs1(certificadoDigital, encoding.GetBytes(chave))); qrCode.Append("&sign="); qrCode.Append(assinatura); } @@ -308,23 +307,6 @@ public static infCTeSupl QrCode(this CteEletronica cte, X509Certificate2 certifi }; } - private static byte[] CreateSignaturePkcs1(X509Certificate2 certificadoDigital, byte[] Value) - { - var rsa = certificadoDigital.GetRSAPrivateKey(); - - RSAPKCS1SignatureFormatter rsaF = new RSAPKCS1SignatureFormatter(rsa); - - SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider(); - - byte[] hash = null; - - hash = sha1.ComputeHash(Value); - - rsaF.SetHashAlgorithm("SHA1"); - - return rsaF.CreateSignature(hash); - } - public static void SalvarXmlEmDisco(this CteEletronica cte, ConfiguracaoServico configuracaoServico = null) { var instanciaServico = configuracaoServico ?? ConfiguracaoServico.Instancia; diff --git a/CTe.Utils/CTe/ExtCTeOs.cs b/CTe.Utils/CTe/ExtCTeOs.cs index 928f34b2e..437f6e799 100644 --- a/CTe.Utils/CTe/ExtCTeOs.cs +++ b/CTe.Utils/CTe/ExtCTeOs.cs @@ -9,7 +9,6 @@ using DFe.Utils.Assinatura; using System; using System.IO; -using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Text; using System.Xml; @@ -72,7 +71,7 @@ public static infCTeSupl QrCode(this CteEletronica cte, X509Certificate2 certifi && cte.InfCte.ide.tpEmis != tpEmis.teSVCSP ) { - var assinatura = Convert.ToBase64String(CreateSignaturePkcs1(certificadoDigital, encoding.GetBytes(chave))); + var assinatura = Convert.ToBase64String(AssinaturaDigital.CriarAssinaturaPkcs1(certificadoDigital, encoding.GetBytes(chave))); qrCode.Append("&sign="); qrCode.Append(assinatura); } @@ -83,23 +82,6 @@ public static infCTeSupl QrCode(this CteEletronica cte, X509Certificate2 certifi }; } - private static byte[] CreateSignaturePkcs1(X509Certificate2 certificadoDigital, byte[] Value) - { - var rsa = certificadoDigital.GetRSAPrivateKey(); - - RSAPKCS1SignatureFormatter rsaF = new RSAPKCS1SignatureFormatter(rsa); - - SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider(); - - byte[] hash = null; - - hash = sha1.ComputeHash(Value); - - rsaF.SetHashAlgorithm("SHA1"); - - return rsaF.CreateSignature(hash); - } - public static string Chave(this CteEletronica cte) { var chave = cte.InfCte.Id.Substring(3, 44); diff --git a/DFe.Testes/DFe.Testes.csproj b/DFe.Testes/DFe.Testes.csproj index 1efc8325b..cc90271e4 100644 --- a/DFe.Testes/DFe.Testes.csproj +++ b/DFe.Testes/DFe.Testes.csproj @@ -22,8 +22,4 @@ - - - - diff --git a/DFe.Testes/Utils/Assinatura/AssinaturaDigitalTesteUnitario.cs b/DFe.Testes/Utils/Assinatura/AssinaturaDigitalTesteUnitario.cs new file mode 100644 index 000000000..570b4bba6 --- /dev/null +++ b/DFe.Testes/Utils/Assinatura/AssinaturaDigitalTesteUnitario.cs @@ -0,0 +1,48 @@ +using System.Security.Cryptography; +using System.Text; +using DadosDeTestes.AssinaturaDigital; +using DFe.Utils.Assinatura; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace DFe.Testes.Utils.Assinatura; + +[TestClass] +public class AssinaturaDigitalTesteUnitario +{ + [TestMethod(displayName: "Dado dados para geração do hash sha1 bytes, quando obter hash sha1 bytes, então deve obter hash sha1 em bytes igual do SHA1CryptoServiceProvider.")] + [DynamicData(nameof(AssinaturaDigitalTesteDados.ObterDadosParaGeracaoDoHashSha1Bytes), typeof(AssinaturaDigitalTesteDados), DynamicDataSourceType.Method)] + public void DadoDadosParaGeracaoDoHashSha1BytesQuandoObterHashSha1BytesEntaoDeveObterHashSha1EmBytesIgualDoSha1CryptoServiceProvider(string dadosEmString) + { + // Arrange + var dadosEmBytes = Encoding.UTF8.GetBytes(dadosEmString); + var bytesEsperados = ObterHashSha1BytesUsandoSha1CryptoServiceProvider(dadosEmBytes); + + // Act + var bytesRetornado = AssinaturaDigital.ObterHashSha1Bytes(dadosEmBytes); + + // Assert + CollectionAssert.AreEqual(bytesEsperados, bytesRetornado); + } + + [TestMethod(displayName: "Dado dados para geração do hash sha1 bytes, quando obter hash sha1 bytes, então deve obter hash sha1 em bytes.")] + [DynamicData(nameof(AssinaturaDigitalTesteDados.ObterDadosParaGeracaoDoHashSha1BytesEValorEsperado), typeof(AssinaturaDigitalTesteDados), DynamicDataSourceType.Method)] + public void DadoDadosParaGeracaoDoHashSha1BytesQuandoObterHashSha1BytesEntaoDeveObterHashSha1EmBytes(string dadosEmString, byte[] bytesEsperados) + { + // Arrange + var dadosEmBytes = Encoding.UTF8.GetBytes(dadosEmString); + + // Act + var bytesRetornado = AssinaturaDigital.ObterHashSha1Bytes(dadosEmBytes); + + // Assert + CollectionAssert.AreEqual(bytesEsperados, bytesRetornado); + } + + private byte[] ObterHashSha1BytesUsandoSha1CryptoServiceProvider(byte[] dados) + { + var sha1 = new SHA1CryptoServiceProvider(); + var hashSha1Bytes = sha1.ComputeHash(dados); + + return hashSha1Bytes; + } +} \ No newline at end of file diff --git a/DFe.Utils/Assinatura/AssinaturaDigital.cs b/DFe.Utils/Assinatura/AssinaturaDigital.cs index 86a3173b7..3c099e3b7 100644 --- a/DFe.Utils/Assinatura/AssinaturaDigital.cs +++ b/DFe.Utils/Assinatura/AssinaturaDigital.cs @@ -31,6 +31,7 @@ /* Rua Comendador Francisco josé da Cunha, 111 - Itabaiana - SE - 49500-000 */ /********************************************************************************/ using System; +using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.Xml; using System.Xml; @@ -82,5 +83,38 @@ public static SignatureZeus Assina(T objeto, string id, X509Certificate2 cert var assinatura = FuncoesXml.XmlStringParaClasse(xmlDigitalSignature.OuterXml); return assinatura; } + + /// + /// Gera uma assinatura digital no formato PKCS1 utilizando o algoritmo RSA com SHA-1. + /// + /// Certificado digital com chave privada usada para assinar. + /// Dados a serem assinados em formato de array de bytes. + /// Assinatura digital como um array de bytes. + public static byte[] CriarAssinaturaPkcs1(X509Certificate2 certificado, byte[] valor) + { + var rsa = certificado.GetRSAPrivateKey(); + + var rsaFormatter = new RSAPKCS1SignatureFormatter(rsa); + rsaFormatter.SetHashAlgorithm("SHA1"); + + var hashSha1Bytes = ObterHashSha1Bytes(valor); + + var assinatura = rsaFormatter.CreateSignature(hashSha1Bytes); + + return assinatura; + } + + /// + /// Obtém o hash SHA-1 em formato byte array a partir de um array de bytes informado. + /// + public static byte[] ObterHashSha1Bytes(byte[] dados) + { + using (var sha1 = SHA1.Create()) + { + var sha1HashBytes = sha1.ComputeHash(dados); + + return sha1HashBytes; + } + } } } \ No newline at end of file diff --git a/DadosDeTestes/AssinaturaDigital/AssinaturaDigitalDadosDeTeste.cs b/DadosDeTestes/AssinaturaDigital/AssinaturaDigitalDadosDeTeste.cs new file mode 100644 index 000000000..c34c52976 --- /dev/null +++ b/DadosDeTestes/AssinaturaDigital/AssinaturaDigitalDadosDeTeste.cs @@ -0,0 +1,28 @@ +using System.Security.Cryptography; + +namespace DadosDeTestes.AssinaturaDigital; + +public class AssinaturaDigitalTesteDados +{ + public static IEnumerable ObterDadosParaGeracaoDoHashSha1Bytes() + { + return new List + { + new object[] { "92037465012398765432100011223344556677889900|2|1|F1A9B237CD8800FFE234A9912B674CFA1" }, + new object[] { "87122345099887766554433221100009988776655443" }, + new object[] { "73456789101112131415161718192021222324252627" }, + new object[] { "65829374618273645564738291028374618273645564" } + }; + } + + public static IEnumerable ObterDadosParaGeracaoDoHashSha1BytesEValorEsperado() + { + return new List + { + new object[] { "92037465012398765432100011223344556677889900|2|1|F1A9B237CD8800FFE234A9912B674CFA1", new byte[] { 128, 55, 179, 49, 198, 97, 206, 43, 246, 208, 112, 183, 231, 3, 23, 105, 114, 184, 33, 153 }}, + new object[] { "87122345099887766554433221100009988776655443", new byte[] { 151, 153, 16, 228, 170, 100, 76, 248, 192, 58, 160, 126, 157, 224, 171, 233, 75, 23, 118, 67 }}, + new object[] { "73456789101112131415161718192021222324252627", new byte[] { 71, 100, 124, 212, 171, 46, 181, 47, 206, 96, 227, 230, 215, 8, 14, 131, 167, 214, 99, 181 }}, + new object[] { "65829374618273645564738291028374618273645564", new byte[] { 147, 88, 158, 178, 38, 247, 111, 70, 151, 152, 182, 14, 69, 18, 129, 97, 157, 47, 222, 50 }} + }; + } +} \ No newline at end of file diff --git a/DadosDeTestes/NFe/Utils/ConversaoDadosDeTeste.cs b/DadosDeTestes/NFe/Utils/ConversaoDadosDeTeste.cs new file mode 100644 index 000000000..1978358b1 --- /dev/null +++ b/DadosDeTestes/NFe/Utils/ConversaoDadosDeTeste.cs @@ -0,0 +1,15 @@ +namespace DadosDeTestes.NFe.Utils; + +public class ConversaoDadosDeTeste +{ + public static IEnumerable ObterDadosParaGerarHashSha1DeStringEValorEsperado() + { + return new List + { + new object[] { "92037465012398765432100011223344556677889900|2|1|F1A9B237CD8800FFE234A9912B674CFA1", "8037b331c661ce2bf6d070b7e703176972b82199" }, + new object[] { "87122345099887766554433221100009988776655443|1|2|9CFD3321AAC4900BDEAFA1105BC088119", "5994d3d62ca107c89677e7bede2f1e6a9371d9da" }, + new object[] { "73456789101112131415161718192021222324252627|2|2|A7C44B8D56E9002FAB1133DCE5AA784C3", "ebbb014e73ff18fec652350da4a24907fad21297" }, + new object[] { "65829374618273645564738291028374618273645564|1|1|B21C9D77E04A00BBF5C21EA39988D10AA", "19f80bbd273e606d206880f79ea56a671b263586" } + }; + } +} \ No newline at end of file diff --git a/MDFe.Classes/Extensoes/ExtMDFe.cs b/MDFe.Classes/Extensoes/ExtMDFe.cs index 4841b820b..71a8a3327 100644 --- a/MDFe.Classes/Extensoes/ExtMDFe.cs +++ b/MDFe.Classes/Extensoes/ExtMDFe.cs @@ -41,7 +41,6 @@ using MDFe.Utils.Validacao; using System; using System.IO; -using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Text; using MDFEletronico = MDFe.Classes.Informacoes.MDFe; @@ -161,7 +160,7 @@ public static MDFEletronico Assina(this MDFEletronico mdfe, EventHandler if (mdfe.InfMDFe.Ide.TpEmis == MDFeTipoEmissao.Contingencia) { var encoding = Encoding.UTF8; - var sign = Convert.ToBase64String(CreateSignaturePkcs1(config.X509Certificate2, encoding.GetBytes(mdfe.Chave()))); + var sign = Convert.ToBase64String(AssinaturaDigital.CriarAssinaturaPkcs1(config.X509Certificate2, encoding.GetBytes(mdfe.Chave()))); mdfe.InfMDFeSupl.QrCodMDFe += "&sign=" + sign; } @@ -254,7 +253,7 @@ public static MdfeInfMDFeSupl QrCode(this MDFEletronico mdfe, X509Certificate2 c switch (mdfe.InfMDFe.Ide.TpEmis) { case MDFeTipoEmissao.Contingencia: - var assinatura = Convert.ToBase64String(CreateSignaturePkcs1(certificadoDigital, encoding.GetBytes(mdfe.Chave()))); + var assinatura = Convert.ToBase64String(AssinaturaDigital.CriarAssinaturaPkcs1(certificadoDigital, encoding.GetBytes(mdfe.Chave()))); qrCode.Append("&sign="); qrCode.Append(assinatura); break; @@ -265,23 +264,5 @@ public static MdfeInfMDFeSupl QrCode(this MDFEletronico mdfe, X509Certificate2 c QrCodMDFe = qrCode.ToString() }; } - - private static byte[] CreateSignaturePkcs1(X509Certificate2 certificado, byte[] Value) - { - var rsa = certificado.GetRSAPrivateKey(); - - RSAPKCS1SignatureFormatter rsaF = new RSAPKCS1SignatureFormatter(rsa); - - SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider(); - - byte[] hash = null; - - hash = sha1.ComputeHash(Value); - - rsaF.SetHashAlgorithm("SHA1"); - - return rsaF.CreateSignature(hash); - - } } } diff --git a/NFe.Utils.Testes/ConversaoTesteUnitario.cs b/NFe.Utils.Testes/ConversaoTesteUnitario.cs new file mode 100644 index 000000000..8f3361cf8 --- /dev/null +++ b/NFe.Utils.Testes/ConversaoTesteUnitario.cs @@ -0,0 +1,18 @@ +using DadosDeTestes.NFe.Utils; +using Xunit; + +namespace NFe.Utils.Testes; + +public class ConversaoTesteUnitario +{ + [Theory(DisplayName = "Dado dados em string para geração do hex sha1 de string, quando obter hex sha1 de string, então deve obter hex sha1 de string.")] + [MemberData(nameof(ConversaoDadosDeTeste.ObterDadosParaGerarHashSha1DeStringEValorEsperado), MemberType = typeof(ConversaoDadosDeTeste))] + public void DadoDadosEmStringParaGeracaoDoHexSha1DeStringQuandoObterHexSha1DeStringEntaoDeveObterHexSha1DeString(string dadosEmString, string stringEsperada) + { + // Act + var valorRetornado = Conversao.ObterHexSha1DeString(dadosEmString); + + // Assert + Assert.Equal(stringEsperada, valorRetornado); + } +} \ No newline at end of file diff --git a/NFe.Utils.Testes/NFe.Utils.Testes.csproj b/NFe.Utils.Testes/NFe.Utils.Testes.csproj index 0391c87f7..c84a94097 100644 --- a/NFe.Utils.Testes/NFe.Utils.Testes.csproj +++ b/NFe.Utils.Testes/NFe.Utils.Testes.csproj @@ -17,6 +17,7 @@ + diff --git a/NFe.Utils/Conversao.cs b/NFe.Utils/Conversao.cs index 4f6c59fc8..0752a1b22 100644 --- a/NFe.Utils/Conversao.cs +++ b/NFe.Utils/Conversao.cs @@ -31,9 +31,9 @@ /* Rua Comendador Francisco josé da Cunha, 111 - Itabaiana - SE - 49500-000 */ /********************************************************************************/ using System; -using System.Security.Cryptography; using System.Text; using DFe.Classes.Flags; +using DFe.Utils.Assinatura; using NFe.Classes.Informacoes.Detalhe.Tributacao.Estadual.Tipos; using NFe.Classes.Informacoes.Emitente; using NFe.Classes.Informacoes.Identificacao.Tipos; @@ -231,10 +231,10 @@ public static string ObterHexSha1DeString(string s) { var bytes = Encoding.UTF8.GetBytes(s); - var sha1 = SHA1.Create(); - var hashBytes = sha1.ComputeHash(bytes); + var hashSha1Bytes = AssinaturaDigital.ObterHashSha1Bytes(bytes); + var hexSha1DeString = ObterHexDeByteArray(hashSha1Bytes); - return ObterHexDeByteArray(hashBytes); + return hexSha1DeString; } /// diff --git a/NFe.Utils/InfRespTec/GerarHashCSRT.cs b/NFe.Utils/InfRespTec/GerarHashCSRT.cs index 420aa4d97..0382d74b4 100644 --- a/NFe.Utils/InfRespTec/GerarHashCSRT.cs +++ b/NFe.Utils/InfRespTec/GerarHashCSRT.cs @@ -1,6 +1,6 @@ using System; -using System.Security.Cryptography; using System.Text; +using DFe.Utils.Assinatura; namespace Shared.NFe.Utils.InfRespTec { @@ -22,13 +22,8 @@ public static string HashCSRT(string csrt, string chave, Encoding encoding = nul var data = encoding.GetBytes(csrtChave); - string chaveBase64; - - using (SHA1CryptoServiceProvider cryptoTransformSha1 = new SHA1CryptoServiceProvider()) - { - var hash = cryptoTransformSha1.ComputeHash(data); - chaveBase64 = Convert.ToBase64String(hash); - } + var sha1HashBytes = AssinaturaDigital.ObterHashSha1Bytes(data); + var chaveBase64 = Convert.ToBase64String(sha1HashBytes); return chaveBase64; }