赞
踩
问题描述:
由于海关各个关区的申报都对接了总署,以前向各个关区申报的业务现在全部通过向总署申报,在向总署申报清单时遇到了报文加密问题,怎么加密也加不对。总署给的规则也不清晰,目前是第一家在做这个,所以也没人请教,特发此文用来记录下。
报文格式加密处理代码
- 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));
- //增加 Signature
- XmlElement signature = new XmlElement("Signature");//1层
- signature.setAttribute("xmlns", "http://www.w3.org/2000/09/xmldsig#");
- ceb621Message.addSubElement(signature);
- //增加 Signature-SignedInfo
- XmlElement signedInfo = new XmlElement("SignedInfo");//2层
- signature.addSubElement(signedInfo);
- //增加 Signature-SignedInfo-CanonicalizationMethod
- XmlElement canonicalizationMethod = new XmlElement("CanonicalizationMethod");//3层
- canonicalizationMethod.setAttribute("Algorithm", "http://www.w3.org/TR/2001/REC-xml-c14n-20010315");
- signedInfo.addSubElement(canonicalizationMethod);
- //增加 Signature-SignedInfo-SignatureMethod
- XmlElement signatureMethod = new XmlElement("SignatureMethod");//3层
- signatureMethod.setAttribute("Algorithm", "http://www.w3.org/2000/09/xmldsig#rsa-sha1");
- signedInfo.addSubElement(signatureMethod);
- //增加 Signature-SignedInfo-Reference
- XmlElement seference = new XmlElement("Reference");//3层
- seference.setAttribute("URI", "");
- signedInfo.addSubElement(seference);
- //增加 Signature-SignedInfo-Reference-Transforms
- XmlElement transforms = new XmlElement("Transforms");//4层
- seference.addSubElement(transforms);
- //增加 Signature-SignedInfo-Reference-Transforms-Transform
- XmlElement transform = new XmlElement(signedInfo, "Transform");//5层
- transform.setAttribute("Algorithm", "http://www.w3.org/2000/09/xmldsig#enveloped-signature");
- transforms.addSubElement(transform);
- //增加 Signature-SignedInfo-Reference-DigestMethod
- XmlElement digestMethod = new XmlElement("DigestMethod");//4层
- digestMethod.setAttribute("Algorithm", "http://www.w3.org/2000/09/xmldsig#sha1");
- seference.addSubElement(digestMethod);
- //增加 Signature-SignedInfo-Reference-DigestValue
- XmlElement digestValue = new XmlElement("DigestValue");//4层
- //String digestValueJQ = "digestValue加签值";
- digestValue.setValue(digestValueZY);
- seference.addSubElement(digestValue);
- //增加 Signature-SignatureValue
- XmlElement 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-KeyInfo
- XmlElement keyInfo = new XmlElement("KeyInfo");//2层
- signature.addSubElement(keyInfo);
- //增加 Signature-KeyInfo-KeyName
- XmlElement keyName = new XmlElement("KeyName");//3层
- String keyNameJQ = certificateInfo.getSerialNumber();
- keyName.setValue(keyNameJQ);
- keyInfo.addSubElement(keyName);
- //增加 Signature-KeyInfo-X509Data
- XmlElement x509Data = new XmlElement("X509Data");//3层
- keyInfo.addSubElement(x509Data);
- //增加 Signature-KeyInfo-X509Data-X509Certificate
- XmlElement 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());
- //signedInfo
- Document 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);
- }
-
- /**
- * 加密对节点进行预处理
- */
- @Override
- public void onXmlElementCreated(XmlElement xmlElement)
- {
- super.onXmlElementCreated(xmlElement);
- XmlElement ceb621Message = xmlElement.getSubElement("ceb:CEB621Message");
- String encodeStr = xmlObj.getXmlencoding();
- swxaJmService.setSignatureXmlElement(ceb621Message, encodeStr);
- }
-
- /**
- * 海关格式化xml内容
- */
- @Override
- public String toXml(XmlElement xmlElement)
- {
- XmlElement ceb621Message = xmlElement.getSubElement("ceb:CEB621Message");
- String encodeStr = xmlObj.getXmlencoding();
- return swxaJmService.toXmlText(ceb621Message, encodeStr);
- }
-
-
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。