JAVA RSA非对称加密 XMLSignature/X509Certificate

来源:互联网 发布:js获取选择的select 编辑:程序博客网 时间:2024/05/16 05:32

仅供参考。

私钥自己持有用来加密,公钥用来解密,报文包含的主要几部分是:未加密数据、公钥、签名、摘要

报文:

<?xml version="1.0" encoding="UTF-8"?><PGGATE><Message id="A20130521113348"><MPIRes id="S20130521113348"><RespCode>0000</RespCode></MPIRes><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo xmlns="http://www.w3.org/2000/09/xmldsig#"><CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" xmlns="http://www.w3.org/2000/09/xmldsig#"/><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" xmlns="http://www.w3.org/2000/09/xmldsig#"/><Reference URI="#S20130521113348" xmlns="http://www.w3.org/2000/09/xmldsig#"><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" xmlns="http://www.w3.org/2000/09/xmldsig#"/><DigestValue xmlns="http://www.w3.org/2000/09/xmldsig#">wj2BDi23oLeVtmG/uZg4n49aKdk=</DigestValue></Reference></SignedInfo><SignatureValue xmlns="http://www.w3.org/2000/09/xmldsig#">DVrRdcY7fZRCCPUtSjiOJBaMEJRualXZyuSzzcavYyyOXCnBZhd7w3XLvw66fJSvaHC1GHOECpTFhRETWlp47bxvYUYIwA+jaltXb0BgkQiwkFYO8U0YEYPfVESG9lKL7cLWbz122OaxJSQkn5ZEf+DnCp8kMGVR2BnW1ZC7VIE=</SignatureValue><KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"><X509Data xmlns="http://www.w3.org/2000/09/xmldsig#"><X509Certificate xmlns="http://www.w3.org/2000/09/xmldsig#">MIIDxjCCAy+gAwIBAgIQICPnBGbBhVL4rB50L9wn4zANBgkqhkiG9w0BAQUFADAkMQswCQYDVQQGEwJDTjEVMBMGA1UEChMMQ0ZDQSBURVNUIENBMB4XDTA2MDYxMjA4MTEyNVoXDTA4MDYxMjAyNTIyMVowgbIxCzAJBgNVBAYTAkNOMRUwEwYDVQQKEwxDRkNBIFRFU1QgQ0ExETAPBgNVBAsTCExvY2FsIFJBMRQwEgYDVQQLEwtlbnRlcnByaXNlczFjMGEGA1UEAx5aADAANAAxAEAAOAA5ADkAMAAxADkAOQAwADEAOQA5ADAAMQAxAEAAMAA0ADAANgAyADQAMQAwADoAQQBQAEkAIABTAEkARwBOAEAAMAAwADAAMAAwADAAMAAxMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+jdc6rFyssSyXlu6AqzYXx6/GkbZWSjGwd1fOy6z627fKxb5RdUPdra683+cE11iKJKn8C/UZ8DLHCijLSeryy9JskXIAPWZrccj42ig0r+1usIYZG21DKi5Q6Cx+tuxzjLcmyMiMkVYEhYedMKD/nWSETgsQYut+EZjOFvcZkwIDAQABo4IBaDCCAWQwHwYDVR0jBBgwFoAURnLcJXKfAk5Vg7WA+Qvb6ZOz9EUwHQYDVR0OBBYEFAdjvrCDQvhIBeO0M+g1KvYZbJTdMA4GA1UdDwEB/wQEAwIEsDAeBgNVHREEFzAVgRNEYWlfYW1pQGhvdG1haWwuY29tMAwGA1UdEwQFMAMBAQAwgeMGA1UdHwSB2zCB2DBNoEugSaRHMEUxCzAJBgNVBAYTAkNOMRUwEwYDVQQKEwxDRkNBIFRFU1QgQ0ExDDAKBgNVBAsTA0NSTDERMA8GA1UEAxMIY3JsMTMyXzIwgYaggYOggYCGfmxkYXA6Ly8yMTAuNzQuNDEuODc6Mzg5L0NOPWNybDEzMl8yLE9VPUNSTCxPPUNGQ0EgVEVTVCBDQSxDPUNOP2NlcnRpZmljYXRlUmV2b2NhdGlvbkxpc3Q/YmFzZT9vYmplY3RjbGFzcz1jUkxEaXN0cmlidXRpb25Qb2ludDANBgkqhkiG9w0BAQUFAAOBgQB4RknyLopJ+RXWkITLfiDmSIIW+JQX7MZKM/TtdoT45XdYc3ngAY3qRzM10xa0JU5GjwrOm9JzBU7NYVtzvc8AVOpoHh/XI7Ocl03k6k07ZJZBgcgpzpayW6cjlyE+r62PenXAtNqkVtx5sW+TGNSpfzb284ldM2ezoBdZqhNumA==</X509Certificate><X509SubjectName xmlns="http://www.w3.org/2000/09/xmldsig#">CN=041@89901990199011@04062410:API SIGN@00000001,OU=enterprises,OU=Local RA,O=CFCA TEST CA,C=CN</X509SubjectName><X509CRL xmlns="http://www.w3.org/2000/09/xmldsig#">UzIwMTMwNTIxMTEzMzQ4</X509CRL><X509SKI xmlns="http://www.w3.org/2000/09/xmldsig#">B2O+sINC+EgF47Qz6DUq9hlslN0=</X509SKI><X509IssuerSerial xmlns="http://www.w3.org/2000/09/xmldsig#"><X509IssuerName xmlns="http://www.w3.org/2000/09/xmldsig#">O=CFCA TEST CA,C=CN</X509IssuerName><X509SerialNumber xmlns="http://www.w3.org/2000/09/xmldsig#">42721711840498543783102462139127572451</X509SerialNumber></X509IssuerSerial></X509Data></KeyInfo></Signature></Message></PGGATE>

MPIRES内容是传输数据,ID对应下面REFERENCE中的URI

DIGESTVALUE的值是摘要,是由指定METHOD得到的数据的哈希值

SIGNATUREVALUE是签名值,是由私钥将数据加密得到的值

X509CERTIFICATE里面一大串字符是公钥,用来解密

验签的步骤:

1:验公钥是否由根证书发行,如果数据、摘要被修改,公钥被修改->野鸡公钥,这一步通不过

2:验摘要,取数据的哈希值跟摘要比较,如果仅仅数据被修改,这一步通不过

3:验签名,用公钥给签名解密,结果与摘要(是否再次哈希数据?)比较,如果数据和摘要被修改,这一步通不过

验签JAVA代码:参数为如上XML类型

public boolean checkXmlSignature(Document inputDoc) throws Exception {try {if (inputDoc == null) {return false;}coverCert(inputDoc);XmlConv xmlConv = new XmlConv();String str = new String(xmlConv.converDocByte(inputDoc),"utf-8");Element signatureElement = (Element) inputDoc.getElementsByTagNameNS(Constants.SignatureSpecNS,Constants._TAG_SIGNATURE).item(0);XMLSignature sig = new XMLSignature(signatureElement,XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1);//用根证书的公钥验证公钥X509Certificate certificate = sig.getKeyInfo().getX509Certificate();                        String strCA = "-----BEGIN CERTIFICATE-----" + "\n"                        + "MIIDezCCAmOgAwIBAgIJAMx6VPEfkqaLMA0GCSqGSIb3DQEBBAUAMHQxFjAUBgNV" + "\n"                        + "BAoTDUFjY29yU2VydmljZXMxFDASBgNVBAsTC1N5c3RlbUFkbWluMRgwFgYDVQQD" + "\n"                        + "Ew9BY2NvclNlcnZpY2VzQ0ExKjAoBgkqhkiG9w0BCQEWG2NvbGluLmJhaUBhY2Nv" + "\n"                        + "cnNlcnZpY2VzLmNvbTAeFw0xMDA1MjQxNjM0MjZaFw0xNjA1MjIxNjM0MjZaMHQx" + "\n"                        + "FjAUBgNVBAoTDUFjY29yU2VydmljZXMxFDASBgNVBAsTC1N5c3RlbUFkbWluMRgw" + "\n"                        + "FgYDVQQDEw9BY2NvclNlcnZpY2VzQ0ExKjAoBgkqhkiG9w0BCQEWG2NvbGluLmJh" + "\n"                        + "ggEBAJqZOQmf1P6iocEOsTRyWfaX9ZlJXS5+3Z0Cu1IhwqUM2WDB1fpR9FVAbs5j" + "\n"                        + "JAn3vjfvDjqdttRTLavGV79EmDctUHoK2W2XkAWMa7Hg9x7leXNRLZ4nFMP8hI5v" + "\n"                        + "4CxzUJl7gMgpsmCsv4oo9d38UmU2O2MvZ5Q5LOwGTbNTdZQ4SHNKcc3wumlMI90h" + "\n"                        + "mhhCRzDjF3dYeapr28oy/7uHPaWK+eNQwioBXJMmbn1RFMEa8PeXcG2PYEHSDHHi" + "\n"                        + "BtSSS0pLtMOXq+hmUliHxZymGObY13Fx1KfqLbbn6A4gKCnp8T97Kb7jvtBY8nR4" + "\n"                        + "8M58/uB8Ej1J2m7CTZiIEolbD9kCAwEAAaMQMA4wDAYDVR0TBAUwAwEB/zANBgkq" + "\n"                        + "hkiG9w0BAQQFAAOCAQEAig1mlEYTpRDs+H5UPLd4KQDZBEy2xS9diePAihgne9/4" + "\n"                        + "qvXnolq6vD4kvnObdb1ne48ZlLlps7ikDfC1Ylv2DvUmGhJDCG76ffvgapo2Z83p" + "\n"                        + "msTQY06ZxJqxpfhYclu7IFNWgFPAv49jInIpDdZa0svwDPy0PILXj975pH6pPBat" + "\n"                        + "83rzNts7NO0D/MI8rLF0MA6Fspz62lR+uqFeHMJfuy3C45DhzZ5ppQIwEvwbgdnE" + "\n"                        + "HoERDxu8i//SbtRPVsbX82X4E5Sv7YEeFj3diYfn1ig3ix6RwATpboSTlQzH9BcI" + "\n"                        + "rtCpKZ5xnjj+3BaNl9rmaP37hpeNVBJE9BPe2dBaPw==" + "\n"                        + "-----END CERTIFICATE-----" + "\n";X509Certificate RTPubCA = cvt2Cert(strCA);certificate.verify(RTPubCA.getPublicKey());//验签名if (!sig.checkSignatureValue(certificate)) {return false;}} catch (XMLSecurityException xsex) {throw new Exception(xsex);} catch (Exception ex) {throw new Exception(ex);}return true;}public static X509Certificate cvt2Cert(String certInfo)throws Exception{        try{            CertificateFactory cf = CertificateFactory.getInstance("X.509");            InputStream in = new ByteArrayInputStream(certInfo.getBytes());            X509Certificate c = (X509Certificate)cf.generateCertificate(in);            return c;        }catch(Exception ex){            throw ex;        }    }
-------------------------------------------------------------------------------------------验签结束--------------------------------------------------------------------------------------------------------------

生成签名:参数是证书、私钥、需要签名的XML格式数据,返回XML文件如上

public Node doCreateXmlSignature(Document inputDoc, String sigidString,PrivateKey privateKey, X509Certificate certInfo) throws PGException {Node outNode;try {if(inputDoc == null) {return inputDoc;}if(sigidString == null || privateKey == null || certInfo == null) {return null;}XMLSignature sig = new XMLSignature(inputDoc, null,XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1);XMLSignature.setDefaultPrefix(sig.getBaseNamespace(),servercommon.Constants.BLANK);sig.setFollowNestedManifests(false);sig.addDocument("#" + sigidString, null,Constants.ALGO_ID_DIGEST_SHA1, null, null);/*sig.addDocument("#" + sigidString, null,Constants.ALGO_ID_DIGEST_SHA1, null, null);*///sig.addDocument("#" + sigidString, (Transforms) null,//Constants.ALGO_ID_DIGEST_SHA1, null,//"http://www.w3.org/2000/09/xmldsig#Object");XMLX509SubjectName subjectName = new XMLX509SubjectName(inputDoc,certInfo);X509Data x509Data = new X509Data(inputDoc);XMLX509Certificate xmlCert = new XMLX509Certificate(x509Data.getDocument(), certInfo);XMLX509CRL xmlCrl = new XMLX509CRL(inputDoc, sigidString.getBytes(server.common.Constants.XML_ENCODE_UTF8));XMLX509SKI xmlKI = new XMLX509SKI(inputDoc, certInfo);XMLX509IssuerSerial xmlIssuerSerial = new XMLX509IssuerSerial(inputDoc, certInfo);x509Data.add(xmlCert);x509Data.add(subjectName);x509Data.add(xmlCrl);x509Data.add(xmlKI);x509Data.add(xmlIssuerSerial);sig.getKeyInfo().add(x509Data);sig.sign(privateKey);Element rootCup = inputDoc.getDocumentElement();rootCup.getFirstChild().appendChild(sig.getElement());outNode = inputDoc;} catch (XMLSecurityException xsex) {xsex.printStackTrace();throw new PGException(Module.SYSTEM_MODULE,Rescode.XML_SIGNATURE_ERROR, xsex);} catch (UnsupportedEncodingException ueex) {throw new PGException(Module.SYSTEM_MODULE, Rescode.TOUTF8_ERROR,ueex);} catch (Exception ex) {ex.printStackTrace();throw new PGException(Module.DEFAULT_MODULE,Rescode.DEFAULT_RESCODE, ex);}return outNode;}

这里X509DATA里面添加了5个节点,对应XML文件的五个节点

OK



---------------------------------------------------------------------------从前的理解-仅供参考--------------------------------------------------------------------------------------------------------------

(用来保证传输数据没有被修改,在我们项目里面,从商户网站确认支付转入我们这边的支付网关时、支付扣款完成返回支付成功或者失败状态到商户网站时,用到了密钥加密。其他地方都没有。因为,支付金额被篡改、支付结果被篡改都是绝对不允许的。

非对称密钥基本特点,有一个加密密钥称公钥,一个解密密钥称私钥,成对出现。公钥仅仅用来加密,私钥仅仅用来解密。

比如用户登录网站,输入卡号密码,提交以后服务器返回卡内余额,如果用这种加密方法流程就可能是这样的:

用户登录网站时访问服务器,服务器生成一对密钥A,把公钥A发送给客户端;

登录完成后客户端本地生成一对密钥B;

提交卡号密码时,用公钥A把数据加密,同时传到服务器的还有公钥B;

服务器接收到数据后,用私钥A把卡号密码解密,查出余额,用公钥B加密,传给客户端;

客户端用私钥B解密余额;

OK。

整个过程中,只传输公钥。

这是我理解的一点点,打个比方,解释非对称原理,实际中不知道有没有这么玩。也不知道有没有客户端生成密钥这回事。

签名:

其实密钥不会对数据加密。

服务器接收到的数据有三部分,一是实体数据,这是加密不加密都无所谓,可以为明文;二是公钥;三是签名;

这里的签名是一段加密过的密文,就是由私钥把实体数据进行加密的结果。

服务器端的步骤是:先验证公钥,然后将签名解密,然后比较实体数据和解密后的结果。

JAVA代码以后看看再贴了。)

原创粉丝点击