对接海关总署电子口岸时遇到清单加密问题的总结
                                                            生活随笔
收集整理的這篇文章主要介紹了
                                对接海关总署电子口岸时遇到清单加密问题的总结
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.                        
                                問題描述:
由于海關各個關區的申報都對接了總署,以前向各個關區申報的業務現在全部通過向總署申報,在向總署申報清單時遇到了報文加密問題,怎么加密也加不對。總署給的規則也不清晰,目前是第一家在做這個,所以也沒人請教,特發此文用來記錄下。
 
報文格式加密處理代碼
import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.util.Map; import *.CertificateInfo; import *.init.CustSwxaJm; import *.XmlElement; /*** <p>標題: 調用三未信安加密機加密</p>* <p>功能: 提供對海關總署報文加密的加密服務 </p>*/ public class CustSwxaJmService {private final CustSwxaJm swxaJm;private final CertificateInfo certificateInfo;public CustSwxaJmService(Map<String,Object> envParams){this.swxaJm = new CustSwxaJm(envParams);this.certificateInfo = new CertificateInfo(envParams);}/*** @param envParams* @param index 密鑰索引位置 (1:南沙,2:黃埔)*/public CustSwxaJmService(Map<String,Object> envParams, int index){this.swxaJm = new CustSwxaJm(envParams, index);this.certificateInfo = new CertificateInfo(envParams, index);}/*** 對加密節點進行預處理* @param envParams* @param ceb621Message* @param encodeStr*/public void setSignatureXmlElement(XmlElement ceb621Message, String encodeStr){String digestValueZY = swxaJm.getHash_SHAl(toHashText(ceb621Message));//增加 SignatureXmlElement signature = new XmlElement("Signature");//1層signature.setAttribute("xmlns", "http://www.w3.org/2000/09/xmldsig#");ceb621Message.addSubElement(signature);//增加 Signature-SignedInfoXmlElement signedInfo = new XmlElement("SignedInfo");//2層signature.addSubElement(signedInfo);//增加 Signature-SignedInfo-CanonicalizationMethodXmlElement canonicalizationMethod = new XmlElement("CanonicalizationMethod");//3層canonicalizationMethod.setAttribute("Algorithm", "http://www.w3.org/TR/2001/REC-xml-c14n-20010315");signedInfo.addSubElement(canonicalizationMethod);//增加 Signature-SignedInfo-SignatureMethodXmlElement signatureMethod = new XmlElement("SignatureMethod");//3層signatureMethod.setAttribute("Algorithm", "http://www.w3.org/2000/09/xmldsig#rsa-sha1");signedInfo.addSubElement(signatureMethod);//增加 Signature-SignedInfo-ReferenceXmlElement seference = new XmlElement("Reference");//3層seference.setAttribute("URI", "");signedInfo.addSubElement(seference);//增加 Signature-SignedInfo-Reference-TransformsXmlElement transforms = new XmlElement("Transforms");//4層seference.addSubElement(transforms);//增加 Signature-SignedInfo-Reference-Transforms-TransformXmlElement transform = new XmlElement(signedInfo, "Transform");//5層transform.setAttribute("Algorithm", "http://www.w3.org/2000/09/xmldsig#enveloped-signature");transforms.addSubElement(transform);//增加 Signature-SignedInfo-Reference-DigestMethodXmlElement digestMethod = new XmlElement("DigestMethod");//4層digestMethod.setAttribute("Algorithm", "http://www.w3.org/2000/09/xmldsig#sha1");seference.addSubElement(digestMethod);//增加 Signature-SignedInfo-Reference-DigestValueXmlElement digestValue = new XmlElement("DigestValue");//4層//String digestValueJQ = "digestValue加簽值";digestValue.setValue(digestValueZY);seference.addSubElement(digestValue);//增加 Signature-SignatureValueXmlElement signatureValue = new XmlElement("SignatureValue");//2層signature.addSubElement(signatureValue);String signatureValueJQ = swxaJm.getPrivateSign(toXmlText(ceb621Message, encodeStr));//getXMLStr(signedInfo, 2)//signatureValueJQ.replace(" ", "\n");signatureValue.setValue(signatureValueJQ);//增加 Signature-KeyInfoXmlElement keyInfo = new XmlElement("KeyInfo");//2層signature.addSubElement(keyInfo);//增加 Signature-KeyInfo-KeyNameXmlElement keyName = new XmlElement("KeyName");//3層String keyNameJQ = certificateInfo.getSerialNumber();keyName.setValue(keyNameJQ);keyInfo.addSubElement(keyName);//增加 Signature-KeyInfo-X509DataXmlElement x509Data = new XmlElement("X509Data");//3層keyInfo.addSubElement(x509Data);//增加 Signature-KeyInfo-X509Data-X509CertificateXmlElement x509Certificate = new XmlElement("X509Certificate");//4層String x509CertificateJQ = certificateInfo.getX509InfoBase64();//x509CertificateJQ.replace(" ", "\n");x509Certificate.setValue(x509CertificateJQ);x509Data.addSubElement(x509Certificate);}/*** 海關格式化XML內容* @param xmlElement* @param encodeStr* @return*/public String toXmlText(XmlElement xmlElement, String encodeStr){ByteArrayOutputStream os = new ByteArrayOutputStream();PrintStream out = new PrintStream(os);String nodeName = "Signature";//添加頭結點 out.print(encodeStr);out.print('\n');list(xmlElement, out, 0, nodeName);return new String(os.toByteArray());}private String toHashText(XmlElement xmlElement){ByteArrayOutputStream os = new ByteArrayOutputStream();PrintStream out = new PrintStream(os);list(xmlElement, out, 0, "Signature");String xmlTest = new String(os.toByteArray());return xmlTest;}private void list(XmlElement xmlElement, PrintStream out, int baseIndent, String nodeName){if (!existParentElement(xmlElement, nodeName)){for (int i = 0; i < baseIndent; i++){out.print('\t');}}out.print("<" + xmlElement.qName);if (xmlElement.localName != null && xmlElement.localName.length() > 0){out.print(" name=\"" + xmlElement.localName + "\"");}for (final String name : xmlElement.getAttributes().keySet()){out.print(" " + name + "=\"" + XmlElement.xmlEscape(xmlElement.getAttributes().get(name), 0xffff) + "\"");}int nSub = xmlElement.subElements.size();if (nSub == 0){if (xmlElement.value != null && xmlElement.value.length() > 0){out.print(">" + XmlElement.xmlEscape(xmlElement.value, 31) + "</" + xmlElement.qName + ">");if (!existParentElement(xmlElement, nodeName)){out.print('\n');}} else{out.print("/>");if (!existParentElement(xmlElement, nodeName)){out.print('\n');}}} else{out.print(">");if (!existParentElement(xmlElement, nodeName)){out.print('\n');}if (xmlElement.value != null && xmlElement.value.length() > 0){if (!existParentElement(xmlElement, nodeName)){for (int i = 0; i < baseIndent + 1; i++){out.print('\t');}}out.print(xmlElement.value);if (!existParentElement(xmlElement, nodeName)){out.print('\n');}}for (int i = 0; i < nSub; i++){list(xmlElement.subElements.get(i), out, baseIndent + 1, nodeName);}for (int i = 0; i < baseIndent; i++){if (!existParentElement(xmlElement, nodeName)){out.print('\t');}}out.print("</" + xmlElement.qName + ">");if (!existParentElement(xmlElement, nodeName)){out.print('\n');}}}/*** 判斷父節點中是否存在nodeName節點* @param xmlElement 節點* @param nodeName 比較節點* @return*/private boolean existParentElement(XmlElement xmlElement, String nodeName){boolean flag = false;String name = xmlElement.qName;if (nodeName.equals(name)){flag = true;} else{XmlElement pNode = xmlElement.getParentNode();if (pNode != null){String pname = pNode.qName;if (nodeName.equals(pname)){flag = true;} else{flag = existParentElement(pNode, nodeName);}}}return flag;} } 獲取證書的代碼 import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.Map; import org.apache.xml.security.utils.Base64; /*** <p>標題: 證書信息</p>* <p>功能: 獲取證書信息</p>*/ public class CertificateInfo {/**系統環境變量*/private final Map<String,Object> envParams;/**證書地址*/private String x509CertFilePath;/**證書*/private X509Certificate x509Certificate;/**證書編號*/private String SerialNumber;/**證書信息Base64編碼*/private String x509InfoBase64;public CertificateInfo(Map<String,Object> envParams){this.envParams = envParams;init(1);}public CertificateInfo(Map<String,Object> envParams, int index){this.envParams = envParams;init(index);}private void init(int index){setX509CertFilePath(initX509CertFilePath(index));setX509Certificate(initX509Certificate());setSerialNumber(initSerialNumber());setX509InfoBase64(initX509InfoBase64());}/*** 證書地址* @return*/public String initX509CertFilePath(int index){switch (index){case 1:return CustSysOptions.getCertificateAddress(this.envParams);case 3:return CustSysOptions.getCertificateAddress_A(this.envParams);}return null;}/*** 獲取證書* @return*/private X509Certificate initX509Certificate(){X509Certificate x509Cert = null;FileInputStream in = null;try{in = new FileInputStream(getX509CertFilePath());CertificateFactory cf = CertificateFactory.getInstance("X.509");x509Cert = (X509Certificate) cf.generateCertificate(in);} catch (FileNotFoundException e){throw new RuntimeException("證書文件不存在,文件路徑:" + getX509CertFilePath(), e);} catch (CertificateException e){throw new RuntimeException("獲取證書內容失敗!", e);} finally{try{if (in != null){in.close();}} catch (IOException e){throw new RuntimeException("關閉讀取證書的文件流失敗!", e);}}return x509Cert;}/*** 獲取證書編號* @return* 趙力*/private String initSerialNumber(){String numberStr = getX509Certificate().getSerialNumber().toString(16);if (StrUtil.isNotNull(numberStr) && numberStr.length() < 16){StringBuilder buf = new StringBuilder();int num = 16 - numberStr.length();for (int i = 0; i < num; i++){buf.append("0");}numberStr = buf.toString() + numberStr;}return numberStr;}/*** 獲取證書信息BASE64編碼* @return* 趙力*/private String initX509InfoBase64(){try{return Base64.encode(x509Certificate.getEncoded());} catch (CertificateEncodingException e){throw new RuntimeException("獲取證書信息BASE64編碼失敗", e);}}public String getX509CertFilePath(){return x509CertFilePath;}private void setX509CertFilePath(String x509CertFilePath){this.x509CertFilePath = x509CertFilePath;}public X509Certificate getX509Certificate(){return x509Certificate;}private void setX509Certificate(X509Certificate x509Certificate){this.x509Certificate = x509Certificate;}public String getSerialNumber(){return SerialNumber;}private void setSerialNumber(String serialNumber){SerialNumber = serialNumber;}public String getX509InfoBase64(){return x509InfoBase64;}private void setX509InfoBase64(String x509InfoBase64){this.x509InfoBase64 = x509InfoBase64;} } 三未信安加密對象代碼 import java.io.IOException; import java.io.StringReader; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.MessageDigest; import java.security.PrivateKey; import java.security.Security; import java.security.Signature; import java.util.Map; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.apache.xml.security.Init; import org.apache.xml.security.c14n.CanonicalizationException; import org.apache.xml.security.c14n.Canonicalizer; import org.apache.xml.security.c14n.InvalidCanonicalizerException; import org.apache.xml.security.utils.Base64; import org.apache.xml.security.utils.IgnoreAllErrorHandler; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import com.sansec.jce.provider.SwxaProvider; /*** <p>標題:三未信安加密對象 </p>* <p>功能:對發送總署的報文進行加密 </p>*/ public class CustSwxaJm {/**配置文件地址*/private String swxaConfigFilePath;/**內部密鑰位置*/private int keyIndex;/**內部密鑰*/private KeyPair inKeyPair;/**外部密鑰*/private KeyPair outKeyPair;public CustSwxaJm(Map<String,Object> envParams){init(envParams, 1);}public CustSwxaJm(Map<String,Object> envParams, int keyIndex){init(envParams, keyIndex);}/*** 初始化加密對象*/private void init(Map<String,Object> envParams, int keyIndex){setSwxaConfigFilePath(StrUtil.obj2str(DataConfig.getDataConfig(envParams, "swxaConfigFilePath")));initProvider();setKeyIndex(keyIndex);setInKeyPair(initInKeyPair());setOutKeyPair(initOutKeyPair());}/*** 初始化配置文件* 功能:加載配置文件并進行初始化*/private void initProvider(){SwxaProvider provider = new SwxaProvider(getSwxaConfigFilePath());Security.addProvider(provider);}/*** 生成內部密鑰*/private KeyPair initInKeyPair(){KeyPair kp = null;try{KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "SwxaJCE");kpg.initialize(keyIndex << 16);kp = kpg.genKeyPair();if (kp == null){throw new RuntimeException();}} catch (Exception e){throw new RuntimeException("獲取內部密鑰失敗");}return kp;}/*** 生成外部密鑰*/private static KeyPair initOutKeyPair(){KeyPair kp = null;try{int keylength = 1024;KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "SwxaJCE");kpg.initialize(keylength);kp = kpg.genKeyPair();if (kp == null){throw new RuntimeException();}} catch (Exception e){throw new RuntimeException("生成外部密鑰失敗");}return kp;}/*** 生成HASH摘要*/public String getHash_SHAl(String xmlInfo){byte[] plain_bytes;try{Init.init();Canonicalizer canonicalizer = Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS);plain_bytes = canonicalizer.canonicalize(xmlInfo.getBytes());} catch (RuntimeException e){throw new RuntimeException("報錯內容", e);} catch (CanonicalizationException e){throw new RuntimeException("報錯內容", e);} catch (ParserConfigurationException e){throw new RuntimeException("報錯內容", e);} catch (IOException e){throw new RuntimeException("報錯內容", e);} catch (SAXException e){throw new RuntimeException("報錯內容", e);} catch (InvalidCanonicalizerException e){throw new RuntimeException("報錯內容", e);}String hashShal;MessageDigest md;try{md = MessageDigest.getInstance("SHA1", "SwxaJCE");md.update(plain_bytes);byte[] data = md.digest();hashShal = Base64.encode(data);} catch (Exception e){throw new RuntimeException("加密機生成hash摘要失敗");}return hashShal;}/*** 進行加簽* @param strSignedInfo XML報文不包含頭的文本*/public String getPrivateSign(String xmlText){String privateSignatue;DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();factory.setNamespaceAware(true);factory.setValidating(true);byte[] bytes = null;try{DocumentBuilder builder = factory.newDocumentBuilder();builder.setErrorHandler(new IgnoreAllErrorHandler());//signedInfoDocument doc = builder.parse(new InputSource(new StringReader(xmlText)));NodeList nodeList = doc.getElementsByTagName("SignedInfo");Node node = nodeList.item(0);Init.init();Canonicalizer canon = Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS);//格式化bytes = canon.canonicalizeSubtree(node);PrivateKey privateKey = getInKeyPair().getPrivate();Signature signatue = null;signatue = Signature.getInstance("SHA1WithRSA", "SwxaJCE");signatue.initSign(privateKey);signatue.update(bytes);privateSignatue = Base64.encode(signatue.sign());} catch (Exception e){throw new RuntimeException("加密機進行內部簽名失敗");}return privateSignatue;}private String getSwxaConfigFilePath(){return swxaConfigFilePath;}private void setSwxaConfigFilePath(String swxaConfigFilePath){this.swxaConfigFilePath = swxaConfigFilePath;}public KeyPair getInKeyPair(){return inKeyPair;}private void setInKeyPair(KeyPair inKeyPair){this.inKeyPair = inKeyPair;}public int getKeyIndex(){return keyIndex;}private void setKeyIndex(int keyIndex){this.keyIndex = keyIndex;}public KeyPair getOutKeyPair(){return outKeyPair;}private void setOutKeyPair(KeyPair outKeyPair){this.outKeyPair = outKeyPair;} }
實際調用
package snsoft.customs.custentryelist.serv;import java.math.BigDecimal; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; /*** <p>標題: 海關總署進境清單導出監聽</p>*/ public class CustentryelistZSXmlListener {protected final String DATATYPE1 = "YYYYMMDDhhmmss";protected final String DATATYPE2 = "YYYYMMDD";private static final String MTABLE = "custentryelist";private final CustSwxaJmService swxaJmService;/*** @param envParams* @param parameter* @param xmlObj*/public CustentryelistZSXmlListener(Map<String,Object> envParams, Map<String,Object> parameter, XmlExObject xmlObj){super(envParams, parameter, xmlObj);this.swxaJmService = new CustSwxaJmService(envParams);}/*** 加密對節點進行預處理*/@Overridepublic void onXmlElementCreated(XmlElement xmlElement){super.onXmlElementCreated(xmlElement);XmlElement ceb621Message = xmlElement.getSubElement("ceb:CEB621Message");String encodeStr = xmlObj.getXmlencoding();swxaJmService.setSignatureXmlElement(ceb621Message, encodeStr);}/*** 海關格式化xml內容*/@Overridepublic String toXml(XmlElement xmlElement){XmlElement ceb621Message = xmlElement.getSubElement("ceb:CEB621Message");String encodeStr = xmlObj.getXmlencoding();return swxaJmService.toXmlText(ceb621Message, encodeStr);}}
 
 
 
總結
以上是生活随笔為你收集整理的对接海关总署电子口岸时遇到清单加密问题的总结的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 文件类型一共有多少种?后缀又有多少?用什
- 下一篇: SAP 成本核算流程
