11package br .com .swconsultoria .nfe .util ;
22
3- import java .security .InvalidParameterException ;
4- import java .security .MessageDigest ;
5- import java .security .NoSuchAlgorithmException ;
6-
7- /**
8- *
9- * @author Samuel Oliveira
10- */
3+ import br .com .swconsultoria .certificado .Certificado ;
4+ import br .com .swconsultoria .certificado .CertificadoService ;
5+ import br .com .swconsultoria .nfe .exception .NfeException ;
6+
7+ import java .nio .charset .StandardCharsets ;
8+ import java .security .*;
9+ import java .util .Base64 ;
10+ import java .util .Optional ;
11+
12+ /**
13+ * @author Samuel Oliveira
14+ */
1115public class NFCeUtil {
1216
1317 /**
14- *
1518 * Funcao Responsavel por Devolver o QrCode já no padrão da Nota.
1619 *
17- * @param chave : Chave de Acesso da NFCe
18- * @param ambiente : Identificação do Ambiente (1 – Produção, 2 – Homologação)
19- * @param idToken : Identificador do CSC – Código de Segurança do Contribuinte no Banco de Dados da SEFAZ
20- * @param CSC : Código de Segurança do Contribuinte (antigo Token)
20+ * @param chave : Chave de Acesso da NFCe
21+ * @param ambiente : Identificação do Ambiente (1 – Produção, 2 – Homologação)
22+ * @param idToken : Identificador do CSC – Código de Segurança do Contribuinte no Banco de Dados da SEFAZ
23+ * @param CSC : Código de Segurança do Contribuinte (antigo Token)
2124 * @param urlConsulta : Url De Consulta da Nfc-e do Estado
22- *
25+ * <p>
26+ * A NT 2025-001 define que deve ser utilizado o padrao v3 para o QrCode da NFC-e.
27+ * Essa funcao será deletada em breve, e a nova funcao getCodeQRCodeV3 deve ser utilizada.
2328 * @return String do QrCode
2429 */
30+ @ Deprecated
2531 public static String getCodeQRCode (String chave , String ambiente , String idToken , String CSC , String urlConsulta ) throws NoSuchAlgorithmException {
2632
2733 StringBuilder value = new StringBuilder ();
@@ -34,6 +40,21 @@ public static String getCodeQRCode(String chave, String ambiente, String idToken
3440 return urlConsulta + "?p=" + value + "|" + cHashQRCode ;
3541 }
3642
43+ /**
44+ * Funcao Responsavel por Devolver o QrCode V3 já no padrão da Nota.
45+ *
46+ * @param chave : Chave de Acesso da NFCe
47+ * @param ambiente : Identificação do Ambiente (1 – Produção, 2 – Homologação)
48+ * @param urlConsulta : Url De Consulta da Nfc-e do Estado
49+ *
50+ * Para NFC-e emitida “on-line”: https://endereco-consulta-QRCode?p=<chave_acesso>|<versao_qrcode>|<tpAmb>
51+ *
52+ * @return String do QrCode
53+ */
54+ public static String getCodeQRCodeV3 (String chave , String ambiente , String urlConsulta ) {
55+ return String .format ("%s?p=%s|3|%s" , urlConsulta , chave , ambiente );
56+ }
57+
3758 /**
3859 * Funcao Responsavel por Devolver o QrCode já no padrão da Nota.
3960 *
@@ -42,8 +63,13 @@ public static String getCodeQRCode(String chave, String ambiente, String idToken
4263 * @param idToken : Identificador do CSC – Código de Segurança do Contribuinte no Banco de Dados da SEFAZ
4364 * @param CSC : Código de Segurança do Contribuinte (antigo Token)
4465 * @param urlConsulta : Url De Consulta da Nfc-e do Estado
66+ * <p>
67+ * A NT 2025-001 define que deve ser utilizado o padrao v3 para o QrCode da NFC-e.
68+ * Essa funcao será deletada em breve, e a nova funcao getCodeQRCodeV3 deve ser utilizada.
69+ *
4570 * @return String do QrCode
4671 */
72+ @ Deprecated
4773 public static String getCodeQRCodeContingencia (String chave , String ambiente , String dhEmi , String valorNF , String digVal , String idToken , String CSC , String urlConsulta ) throws NoSuchAlgorithmException {
4874
4975 StringBuilder value = new StringBuilder ();
@@ -57,16 +83,46 @@ public static String getCodeQRCodeContingencia(String chave, String ambiente, St
5783 String cHashQRCode = getHexa (getHash (value .toString () + CSC )).toUpperCase ();
5884
5985 return urlConsulta + "?p=" + value + "|" + cHashQRCode ;
86+
6087 }
6188
6289 /**
90+ * Funcao Responsavel por Devolver o QrCode V3 de contingencia já no padrão da Nota.
91+ *
92+ * @param chave : Chave de Acesso da NFCe
93+ * @param ambiente : Identificação do Ambiente (1 – Produção, 2 – Homologação)
94+ * @param dhEmi : Campo dhEmi (B09) da NFCe
95+ * @param valorNF : Campo de Valor da Nota (W16)
96+ * @param tpDestinatario : 1=CNPJ; 2=CPF; 3=idEstrangeiro; Caso Destinatário estrangeiro ou não identificado, informar apenas nulo ou vazio
97+ * @param identDest : Identificação do Destinatário CPF ou CNPJ na NFC-e.; Caso Destinatário estrangeiro ou não identificado, informar apenas nulo ou vazio
98+ * @param urlConsulta : Url De Consulta da Nfc-e do Estado
99+ *
100+ * Para NFC-e emitida em contingência “off-line”:
101+ * https://endereco-consultaQRCode?p=<chave_acesso>|<versao_qrcode>|<tpAmb>|<dia_data_emissao>|<vNF>|<tp_idDest>|<idDest>|<assinatura>
63102 *
103+ * @return String do QrCode
104+ */
105+ public static String getCodeQRCodeContingenciaV3 (String chave , String ambiente , String dhEmi , String valorNF ,
106+ String tpDestinatario , String identDest , String urlConsulta ,
107+ Certificado certificado ) throws NfeException {
108+
109+ String valor = String .format ("%s?p=%s|3|%s|%s|%s|%s|%s" ,
110+ urlConsulta , chave , ambiente , dhEmi .substring (8 , 10 ), valorNF ,
111+ Optional .ofNullable (tpDestinatario ).orElse ("" ),
112+ Optional .ofNullable (identDest ).orElse ("" ));
113+
114+ String assinatura = "" ;
115+ return valor + "|" + assinarQrCodeV3 (valor ,certificado );
116+
117+ }
118+
119+ /**
64120 * Função responsável por gerar o hashCSRT conforme definições da NT2018.005 v1.40.
65121 *
66122 * @param chave Chave da nota fiscal com 44 caracteres.
67- * @param csrt Token/Código de Segurança do Responsável Técnico, fornecido pela Sefaz de da estado.
123+ * @param csrt Token/Código de Segurança do Responsável Técnico, fornecido pela Sefaz de da estado.
68124 * @return bytes conforme definição da NF2018.005 v1.40 sem fazer encode em base64.
69- * Isso porque já será feito ao gerar o xml devido ao tipo no XSD ser xs:base64Binary.
125+ * Isso porque já será feito ao gerar o xml devido ao tipo no XSD ser xs:base64Binary.
70126 * @throws NoSuchAlgorithmException caso não encontre suporte para SHA-1.
71127 */
72128 public static byte [] geraHashCSRT (String chave , String csrt ) throws NoSuchAlgorithmException {
@@ -79,23 +135,22 @@ public static byte[] geraHashCSRT(String chave, String csrt) throws NoSuchAlgori
79135 return getHash (csrt + chave );
80136 }
81137
82-
83- /**
84- * @param valor
85- * @return
86- */
138+ /**
139+ * @param valor
140+ * @return
141+ */
87142 private static byte [] getHash (String valor ) throws NoSuchAlgorithmException {
88143
89- MessageDigest md = MessageDigest .getInstance ("SHA-1" );
90- md .update (valor .getBytes ());
91- return md .digest ();
144+ MessageDigest md = MessageDigest .getInstance ("SHA-1" );
145+ md .update (valor .getBytes ());
146+ return md .digest ();
147+ }
148+
149+ private static String getHexa (String valor ) {
150+ return getHexa (valor .getBytes ());
92151 }
93-
94- private static String getHexa (String valor ) {
95- return getHexa (valor .getBytes ());
96- }
97-
98- private static String getHexa (byte [] bytes ) {
152+
153+ private static String getHexa (byte [] bytes ) {
99154 StringBuilder s = new StringBuilder ();
100155 for (byte aByte : bytes ) {
101156 int parteAlta = ((aByte >> 4 ) & 0xf ) << 4 ;
@@ -104,9 +159,27 @@ private static String getHexa(byte[] bytes) {
104159 s .append ('0' );
105160 }
106161 s .append (Integer .toHexString (parteAlta | parteBaixa ));
107- }
108- return s .toString ();
109- }
162+ }
163+ return s .toString ();
164+ }
165+
166+ private static String assinarQrCodeV3 (String dados , Certificado certificado ) throws NfeException {
167+ try {
168+ KeyStore keyStore = CertificadoService .getKeyStore (certificado );
169+
170+ KeyStore .PrivateKeyEntry pkEntry = (KeyStore .PrivateKeyEntry ) keyStore .getEntry (certificado .getNome (),
171+ new KeyStore .PasswordProtection (ObjetoUtil .verifica (certificado .getSenha ()).orElse ("" ).toCharArray ()));
172+
173+ PrivateKey privateKey = pkEntry .getPrivateKey ();
174+ Signature signature = Signature .getInstance ("SHA1withRSA" );
175+ signature .initSign (privateKey );
176+ signature .update (dados .getBytes (StandardCharsets .UTF_8 ));
177+ byte [] signed = signature .sign ();
178+ return Base64 .getEncoder ().encodeToString (signed );
179+ } catch (Exception e ) {
180+ throw new NfeException ("Erro ao gerar assinatura do QRCode V3: " + e .getMessage (), e );
181+ }
182+ }
110183
111184}
112185
0 commit comments