您的位置:首页 > 编程语言 > Java开发

JAVA RSA非对称加密 XMLSignature/X509Certificate

2013-05-17 23:46 274 查看
仅供参考。

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

报文:

<?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#">
DVrRdcY7fZRCCPUtSjiOJBaMEJRualXZyuSzzcavYyyOXCnBZhd7w3XLvw66fJSvaHC1GHOECpTF
hRETWlp47bxvYUYIwA+jaltXb0BgkQiwkFYO8U0YEYPfVESG9lKL7cLWbz122OaxJSQkn5ZEf+Dn
Cp8kMGVR2BnW1ZC7VIE=
</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+gAwIBAgIQICPnBGbBhVL4rB50L9wn4zANBgkqhkiG9w0BAQUFADAkMQswCQYDVQQG
EwJDTjEVMBMGA1UEChMMQ0ZDQSBURVNUIENBMB4XDTA2MDYxMjA4MTEyNVoXDTA4MDYxMjAyNTIy
MVowgbIxCzAJBgNVBAYTAkNOMRUwEwYDVQQKEwxDRkNBIFRFU1QgQ0ExETAPBgNVBAsTCExvY2Fs
IFJBMRQwEgYDVQQLEwtlbnRlcnByaXNlczFjMGEGA1UEAx5aADAANAAxAEAAOAA5ADkAMAAxADkA
OQAwADEAOQA5ADAAMQAxAEAAMAA0ADAANgAyADQAMQAwADoAQQBQAEkAIABTAEkARwBOAEAAMAAw
ADAAMAAwADAAMAAxMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+jdc6rFyssSyXlu6AqzYX
x6/GkbZWSjGwd1fOy6z627fKxb5RdUPdra683+cE11iKJKn8C/UZ8DLHCijLSeryy9JskXIAPWZr
ccj42ig0r+1usIYZG21DKi5Q6Cx+tuxzjLcmyMiMkVYEhYedMKD/nWSETgsQYut+EZjOFvcZkwID
AQABo4IBaDCCAWQwHwYDVR0jBBgwFoAURnLcJXKfAk5Vg7WA+Qvb6ZOz9EUwHQYDVR0OBBYEFAdj
vrCDQvhIBeO0M+g1KvYZbJTdMA4GA1UdDwEB/wQEAwIEsDAeBgNVHREEFzAVgRNEYWlfYW1pQGhv
dG1haWwuY29tMAwGA1UdEwQFMAMBAQAwgeMGA1UdHwSB2zCB2DBNoEugSaRHMEUxCzAJBgNVBAYT
AkNOMRUwEwYDVQQKEwxDRkNBIFRFU1QgQ0ExDDAKBgNVBAsTA0NSTDERMA8GA1UEAxMIY3JsMTMy
XzIwgYaggYOggYCGfmxkYXA6Ly8yMTAuNzQuNDEuODc6Mzg5L0NOPWNybDEzMl8yLE9VPUNSTCxP
PUNGQ0EgVEVTVCBDQSxDPUNOP2NlcnRpZmljYXRlUmV2b2NhdGlvbkxpc3Q/YmFzZT9vYmplY3Rj
bGFzcz1jUkxEaXN0cmlidXRpb25Qb2ludDANBgkqhkiG9w0BAQUFAAOBgQB4RknyLopJ+RXWkITL
fiDmSIIW+JQX7MZKM/TtdoT45XdYc3ngAY3qRzM10xa0JU5GjwrOm9JzBU7NYVtzvc8AVOpoHh/X
I7Ocl03k6k07ZJZBgcgpzpayW6cjlyE+r62PenXAtNqkVtx5sW+TGNSpfzb284ldM2ezoBdZqhNu
mA==
</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代码以后看看再贴了。)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: