11package br .com .swconsultoria .nfe .util ;
22
3+ import br .com .swconsultoria .certificado .Certificado ;
4+ import br .com .swconsultoria .certificado .CertificadoService ;
5+ import br .com .swconsultoria .certificado .exception .CertificadoException ;
6+ import br .com .swconsultoria .nfe .exception .NfeException ;
37import org .junit .jupiter .api .Test ;
48
9+ import java .io .FileNotFoundException ;
10+ import java .net .URI ;
11+ import java .net .URISyntaxException ;
512import java .nio .charset .StandardCharsets ;
6- import java .security .NoSuchAlgorithmException ;
13+ import java .nio .file .Paths ;
14+ import java .security .*;
715import java .util .Base64 ;
16+ import java .util .Objects ;
817
9- import static org .junit .jupiter .api .Assertions .assertArrayEquals ;
10- import static org .junit .jupiter .api .Assertions .assertEquals ;
11- import static org .junit .jupiter .api .Assertions .assertThrows ;
18+ import static org .junit .jupiter .api .Assertions .*;
1219
1320class NFCeUtilTest {
1421
@@ -29,24 +36,90 @@ void geraHashCSRTParametrosInvalidos() {
2936 IllegalArgumentException exception = assertThrows (IllegalArgumentException .class , ()
3037 -> geraHashCSRTBase64 (null , csrt )
3138 );
32- assertEquals (exception . getMessage (), "Chave não deve ser nula ou vazia" );
39+ assertEquals ("Chave não deve ser nula ou vazia" , exception . getMessage () );
3340
3441 //Chave Com menos Caracteres
3542 exception = assertThrows (IllegalArgumentException .class , ()
3643 -> geraHashCSRTBase64 ("123" , csrt )
3744 );
38- assertEquals (exception . getMessage (), "Chave deve conter 44 caracteres." );
45+ assertEquals ("Chave deve conter 44 caracteres." , exception . getMessage () );
3946
4047 //CSRC Vazio
4148 exception = assertThrows (IllegalArgumentException .class , ()
4249 -> geraHashCSRTBase64 (chave , "" )
4350 );
44- assertEquals (exception . getMessage (), "CSRT não deve ser nulo ou vazio" );
51+ assertEquals ("CSRT não deve ser nulo ou vazio" , exception . getMessage () );
4552 }
4653
4754 private byte [] geraHashCSRTBase64 (String chave , String csrt ) throws NoSuchAlgorithmException {
4855 //O XSD é xs:base64Binary e já faz o base64, aqui é uma "simulação" para os testes
4956 return Base64 .getEncoder ().encode (NFCeUtil .geraHashCSRT (chave , csrt ));
5057 }
5158
59+ @ Test
60+ void getCodeQRCodeContingenciaV3Sucesso () throws Exception {
61+ String chave = "41180678393592000146558900000006041028190697" ;
62+ String tpAmp = "2" ;
63+ String dhEmi = "2025-07-01T12:37:06-03:00" ;
64+ String vNF = "12.34" ;
65+ String tpDestRegraQrCode = "2" ;
66+ String cpf = "11111111111" ;
67+ String dadosAssinar = obterDadosAssinar (chave , tpAmp , dhEmi , vNF , tpDestRegraQrCode , cpf );
68+ Certificado certificado = obterCertificado ();
69+
70+ String qrcodeGerado = NFCeUtil .getCodeQRCodeContingenciaV3 (chave , tpAmp , dhEmi , vNF , tpDestRegraQrCode , cpf ,
71+ "https://fake.it" , certificado );
72+ byte [] assinatura = Base64 .getDecoder ().decode (qrcodeGerado .split ("\\ |" )[7 ]);
73+
74+ assertTrue (isAssinaturaValida (certificado , dadosAssinar , assinatura ));
75+ }
76+
77+ /**
78+ * Neste caso da assinatura não bater a Sefaz retorna:
79+ * 583-Rejeicao: Valor da assinatura do qrCode difere do valor calculado
80+ */
81+ @ Test
82+ void getCodeQRCodeContingenciaV3FalhaDadosDivergentes ()
83+ throws FileNotFoundException , URISyntaxException , CertificadoException , NfeException , GeneralSecurityException {
84+ String chave = "41180678393592000146558900000006041028190697" ;
85+ String tpAmp = "2" ;
86+ String dhEmi = "2025-07-01T12:37:06-03:00" ;
87+ String vNF = "12.34" ;
88+ String tpDestRegraQrCode = "2" ;
89+ String cpf = "11111111111" ;
90+
91+ String dadosAssinar = obterDadosAssinar (chave , tpAmp , dhEmi , vNF , tpDestRegraQrCode , "22222222222" );
92+ Certificado certificado = obterCertificado ();
93+
94+ String qrcodeGerado = NFCeUtil .getCodeQRCodeContingenciaV3 (chave , tpAmp , dhEmi , vNF , tpDestRegraQrCode , cpf ,
95+ "https://fake.it" , certificado );
96+ byte [] assinatura = Base64 .getDecoder ().decode (qrcodeGerado .split ("\\ |" )[7 ]);
97+
98+ assertFalse (isAssinaturaValida (certificado , dadosAssinar , assinatura ));
99+ }
100+
101+ private String obterDadosAssinar (String chave , String tpAmp , String dhEmi , String vNF , String tpDestRegraQrCode ,
102+ String cpf ) {
103+ //Conforme manual v6.0 QRCode - Assinar apenas Campos 1 ao 7, incluindo os separadores |.
104+ return String .format ("%s|3|%s|%s|%s|%s|%s" , chave , tpAmp , dhEmi .substring (8 , 10 ), vNF , tpDestRegraQrCode , cpf );
105+ }
106+
107+ private Certificado obterCertificado () throws URISyntaxException , CertificadoException , FileNotFoundException {
108+ URI uri = Objects .requireNonNull (NFCeUtilTest .class .getClassLoader ()
109+ .getResource ("NAO_UTILIZE.pfx" ))
110+ .toURI ();
111+ return CertificadoService .certificadoPfx (Paths .get (uri ).toString (), "123456" );
112+ }
113+
114+ private boolean isAssinaturaValida (Certificado certificado , String dadosAssinar , byte [] assinatura )
115+ throws GeneralSecurityException , CertificadoException {
116+ Signature verifier = Signature .getInstance ("SHA1withRSA" );
117+ KeyStore keyStore = CertificadoService .getKeyStore (certificado );
118+ PublicKey publicKey = keyStore .getCertificate (certificado .getNome ()).getPublicKey ();
119+
120+ verifier .initVerify (publicKey );
121+ verifier .update (dadosAssinar .getBytes (StandardCharsets .UTF_8 ));
122+ return verifier .verify (assinatura );
123+ }
124+
52125}
0 commit comments