java读取证书公钥的实现
方式1:
使用javax.security.cert.X509Certificate进行解析
URLurl=Demo.class.getClassLoader().getResource("C000024.crt");//证书路径 System.out.println("公钥所在路径:"+url.getFile()); X509Certificatecert=X509Certificate.getInstance(newFileInputStream(url.getFile())); PublicKeypublicKey=cert.getPublicKey(); BASE64Encoderbase64Encoder=newBASE64Encoder(); StringpublicKeyString=base64Encoder.encode(publicKey.getEncoded()); System.out.println("-----------------公钥--------------------"); System.out.println(publicKeyString); System.out.println("-----------------公钥--------------------");
方式2:
使用java.security.cert.X509Certificate进行解析
URLurl=Demo.class.getClassLoader().getResource("C000024.crt");//证书路径 System.out.println("公钥所在路径:"+url.getFile()); CertificateFactorycf=CertificateFactory.getInstance("X.509"); X509Certificatecert=(X509Certificate)cf.generateCertificate(newFileInputStream(url.getFile())); PublicKeypublicKey=cert.getPublicKey(); BASE64Encoderbase64Encoder=newBASE64Encoder(); StringpublicKeyString=base64Encoder.encode(publicKey.getEncoded()); System.out.println("-----------------公钥--------------------"); System.out.println(publicKeyString); System.out.println("-----------------公钥--------------------");
说明:
因为只做示例,没有进行异常处理和流的释放,方式1的代码可能少点,方式2需要强转,美观上可能方式1更好看点,但方式1的实质还是调用的方式2,方式2内部有实现缓存策略。更多可以参考下api文档,文档上有提供示例。
补充:JAVA生成RSA公钥和私钥及RSA对数据的加签和验签
背景:
最近来到了新的公司,公司做的是保险支付相关业务,对接渠道的时候经常会用到数据的加签和验签,初次涉及RSA加签验签,通过网站生成了RSA公钥和私钥,用私钥将我要传送的数据进行了加签,并将我的公钥提供给了渠道方进行验签,结果在联调的时候,验签总是错误,渠道方用自己的私钥对数据加签后再用自己的公钥对数据进行验签却能通过,于是我也用自己的私钥对数据进行加签后再用自己的公钥对数据进行验签,结果让我惊讶,居然没有通过!
到了这里,产生错误的原因基本上已经一目了然了,我通过网站生成的公私钥是无法配对的,这当中可能涉及到了网站生成公私钥的时候已经对公私钥进行了处理,比如说PKCS8的处理,所以决定自己用Java来生成RSA公钥和私钥进行验证测试,文档写出来了,测试结果自然已经知道了,是通过的。
以下为完整的验签过程:
启动类:ZhongbaohuiApplication.java
packagecom.test.zhongbaohui; importorg.springframework.boot.SpringApplication; importorg.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication publicclassZhongbaohuiApplication{ publicstaticvoidmain(String[]args){ SpringApplication.run(ZhongbaohuiApplication.class,args); } }
请求Controller:RequestController.java
packagecom.test.zhongbaohui.controller; importcom.alibaba.fastjson.JSONObject; importcom.test.zhongbaohui.utils.RSASignUtils; importlombok.extern.slf4j.Slf4j; importorg.springframework.beans.factory.annotation.Autowired; importorg.springframework.web.bind.annotation.PostMapping; importorg.springframework.web.bind.annotation.RequestMapping; importorg.springframework.web.bind.annotation.RestController; importjavax.servlet.http.HttpServletRequest; importjavax.servlet.http.HttpServletResponse; importjava.util.HashMap; importjava.util.Map; /** *@program:zhongbaohui *@package:com.test.zhongbaohui.controller *@description: *@auther:chengjunyu *@createDate:2019/12/622:05 */ @RestController @RequestMapping(value="/test") @Slf4j publicclassRequestController{ @Autowired privateResponseControllerresponseController; @PostMapping("/getJsonObject") privateStringgetJsonObject(HttpServletRequestrequest,HttpServletResponseresponse){ JSONObjectjsonObject=newJSONObject(); jsonObject.put("signType","RSA"); jsonObject.put("enterpriseId","201975538583911110"); jsonObject.put("nonce","b0eed33073664f5fa983c5b774dbd4b6"); jsonObject.put("timestamp","2019-12-0701:19:25"); Mapmap=newHashMap<>(); map.put("bankCode","其他"); map.put("batchNo","201975538583911110b1084fa29f6c"); map.put("bankCardNumber","6217856100077026406"); map.put("paymentNote","佣金发放"); map.put("idCardNumber","320123199103104650"); map.put("mobile","15365176555"); map.put("bankName","中国银行"); map.put("outEnterpriseOrderNo","T20191207011545663692017"); map.put("realPayment","1.00"); map.put("serviceId","201968613430727001"); map.put("userName","程俊予"); jsonObject.put("data",map); //私钥内容 StringprivateKey="MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgFnOID56YNquwenrgnW1Ud+GBcSFojPOY00+TYq/qHVaprGPeuKlAcBebkyj4+G3H4t7e1DTOblQtZk/yi+2VcbDnhHQl3UVdkLkVMRXXCBPBJtjSo3RMMJFC6OCiKfzhujhhio7MJWWrMYLtAgMBAAECgYBplZud/CZv1KLzIA5bdbF2yk36FYoc3hl3iXLeiyp91NGc6hqhFSEyXPhvrZP0aAym9IC824Bjq4Gg7pkkHzYT3IGDCqqyodBYcdof8Jsk9t0G0Ll7G1dlQwl9R6+SAvauF5RUbwz5Byos6cnFbybfqAdRUdF96yH0Hw0QF1u8XQJBAPrpHvZpeOZNSY/M1wlJZv5gV1OoI9s+PZgJQHgWbT7FaiPDkZiAa7B6hGNBgUa7m4vEzGJNAOHxhdl1QMtlTjMCQQD3VInIf9EjKZn7LNcPQsl1AkXbwuXjtMceeuX43lcdapgQ+4Y6G5QU3fhwZxwsdZnUbLqJWzFgXw/F2E2DxopfAkBxGErgfsID7KpPquDySqel2P8DsjIXTIKu2Ny6REGRnaIt5KTnvFrN/StXIduHamC+K0KEvHi9XwQZ9IP0KgGJAkEA3hUzzywuP3OYhzhhN5vRx1YuIkGkKU3nSdAy9b+323seZoljooOm+QHDljKP0sAaS+sBqFqRQKa7Q/yQxdWd4wJBAIUXethFnMr3U9FetKHmWKwOPh23EHM0xPdVzMcb24WwK7QAXCMo71ugG6qqmBA+wYCrjPwbMu5XysB5+d5ZNC0="; Stringsign=RSASignUtils.sign(jsonObject,privateKey); log.info("验签sign为:{}",sign); jsonObject.put("sign",sign); Stringmessage=responseController.returnMsg(jsonObject.toJSONString()); returnmessage; } }
响应Controller:ResponseController.java
packagecom.test.zhongbaohui.controller; importcom.alibaba.fastjson.JSON; importcom.alibaba.fastjson.JSONObject; importcom.test.zhongbaohui.utils.RSASignUtils; importlombok.extern.slf4j.Slf4j; importorg.springframework.web.bind.annotation.PostMapping; importorg.springframework.web.bind.annotation.RestController; /** *@program:zhongbaohui *@package:com.test.zhongbaohui.controller *@description: *@auther:chengjunyu *@createDate:2019/12/720:46 */ @RestController @Slf4j publicclassResponseController{ @PostMapping("/returnMsg") publicStringreturnMsg(Stringmessage){ JSONObjectjsonObject=JSONObject.parseObject(message); log.info("接受请求内容为:{}",jsonObject.toJSONString()); Stringsign=jsonObject.getString("sign"); jsonObject.remove("sign"); StringpublicKey="MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD5gn/eAnLyf6xZziA+emDarsHp64J1tVHfhgXEhaIzzmNNPk2Kv6h1Wqaxj3ripQHAXm5Mo+Phtx+Le3tQ0zm5ULWZP8ovtlXGw54R0Jd1FXZC5FTEV1wgTwSbY0qN0TDCRQujgoin84bo4YYqOzCVlqzGC7QIDAQAB"; booleanflag=RSASignUtils.verify(jsonObject,publicKey,sign); JSONObjectobject=newJSONObject(); if(flag){ object.put("code","200"); object.put("status","success"); object.put("message:","验签成功"); }else{ object.put("code","400"); object.put("status","failure"); object.put("message:","验签失败"); } returnobject.toJSONString(); } }
RSA工具类:RSASignUtils.java
packagecom.test.zhongbaohui.utils; importcom.alibaba.fastjson.JSONObject; importlombok.extern.slf4j.Slf4j; importorg.apache.tomcat.util.codec.binary.Base64; importorg.springframework.stereotype.Component; importsun.misc.BASE64Decoder; importsun.misc.BASE64Encoder; importjava.io.IOException; importjava.io.UnsupportedEncodingException; importjava.security.*; importjava.security.interfaces.RSAPrivateKey; importjava.security.interfaces.RSAPublicKey; importjava.security.spec.InvalidKeySpecException; importjava.security.spec.PKCS8EncodedKeySpec; importjava.security.spec.X509EncodedKeySpec; importjava.util.HashMap; importjava.util.Map; /** *@program:zhongbaohui *@package:com.test.zhongbaohui.controller *@description: *@auther:chengjunyu *@createDate:2019/12/623:03 */ @Slf4j @Component publicclassRSASignUtils{ publicstaticfinalStringKEY_ALGORITHM="RSA"; privatestaticfinalStringPUBLIC_KEY="RSAPublicKey"; privatestaticfinalStringPRIVATE_KEY="RSAPrivateKey"; publicstaticfinalStringSIGNATURE_ALGORITHM="MD5withRSA"; publicstaticfinalIntegerRSA_KEY_SIZE=1024; /* *@function:使用字符串格式的私钥为JSONObject格式的内容加签 *@param:[jsonObject,privateKey] *@return:java.lang.String *@auther:chengjunyu *@date:2019/12/721:06 */ publicstaticStringsign(JSONObjectjsonObject,StringprivateKey){ StringsignMsg=""; Stringdata=jsonObject.toString(); log.info("加签对象内容为:{}",data); try{ byte[]keyBytes=decryptBASE64(privateKey); PKCS8EncodedKeySpeckeySpec=newPKCS8EncodedKeySpec(keyBytes); KeyFactorykeyFactory=KeyFactory.getInstance("RSA"); PrivateKeykey=keyFactory.generatePrivate(keySpec); Signaturesignature=Signature.getInstance("MD5withRSA"); signature.initSign(key); signature.update(data.getBytes("ISO-8859-1")); signMsg=Base64.encodeBase64String(signature.sign()); }catch(Exceptionvar8){ var8.printStackTrace(); } returnsignMsg; } /* *@function:使用字符串格式的公钥为JSONObject格式的内容验签 *@param:[jsonObject,publicKey,sign] *@return:boolean *@auther:chengjunyu *@date:2019/12/814:56 */ publicstaticbooleanverify(JSONObjectjsonObject,StringpublicKey,Stringsign){ Strings=jsonObject.toJSONString(); log.info("s:{}",s); booleanrs=false; try{ byte[]keyBytes=decryptBASE64(publicKey); X509EncodedKeySpeckeySpec=newX509EncodedKeySpec(keyBytes); KeyFactorykeyFactory=KeyFactory.getInstance("RSA"); PublicKeykey=keyFactory.generatePublic(keySpec); Signaturesignature=Signature.getInstance("MD5withRSA"); signature.initVerify(key); signature.update(s.getBytes("ISO-8859-1")); returnsignature.verify(Base64.decodeBase64(sign.getBytes())); }catch(Exceptionvar9){ var9.printStackTrace(); returnrs; } } /* *@function:获取PublicKey格式的公钥,本例中未使用 *@param:[key] *@return:java.security.PublicKey *@auther:chengjunyu *@date:2019/12/816:10 */ publicstaticPublicKeygetPublicKey(Stringkey){ PublicKeypublicKey=null; try{ byte[]keyBytes=(newBASE64Decoder()).decodeBuffer(key); X509EncodedKeySpeckeySpec=newX509EncodedKeySpec(keyBytes); //RSA对称加密算法 KeyFactorykeyFactory=KeyFactory.getInstance(KEY_ALGORITHM); //取公钥匙对象 publicKey=keyFactory.generatePublic(keySpec); }catch(NoSuchAlgorithmExceptione){ e.printStackTrace(); }catch(InvalidKeySpecExceptione){ e.printStackTrace(); }catch(IOExceptione){ e.printStackTrace(); } returnpublicKey; } /* *@function:获取PublicKey格式的私钥,本例中未使用 *@param:[key] *@return:java.security.PrivateKey *@auther:chengjunyu *@date:2019/12/816:10 */ publicstaticPrivateKeygetPrivateKey(Stringkey){ PrivateKeyprivateKey=null; try{ byte[]keyBytes=(newBASE64Decoder()).decodeBuffer(key); PKCS8EncodedKeySpeckeySpec=newPKCS8EncodedKeySpec(keyBytes); KeyFactorykeyFactory=KeyFactory.getInstance(KEY_ALGORITHM); privateKey=keyFactory.generatePrivate(keySpec); }catch(IOExceptione){ e.printStackTrace(); }catch(NoSuchAlgorithmExceptione){ e.printStackTrace(); }catch(InvalidKeySpecExceptione){ e.printStackTrace(); } returnprivateKey; } /* *@function:初始化公钥和私钥 *@param:[] *@return:java.util.Map*@auther:chengjunyu *@date:2019/12/814:34 */ publicstaticMap initKey(){ KeyPairGeneratorkeyPairGen=null; try{ keyPairGen=KeyPairGenerator.getInstance(KEY_ALGORITHM); }catch(NoSuchAlgorithmExceptione){ e.printStackTrace(); } keyPairGen.initialize(RSA_KEY_SIZE); KeyPairkeyPair=keyPairGen.generateKeyPair(); RSAPublicKeypublicKey=(RSAPublicKey)keyPair.getPublic(); RSAPrivateKeyprivateKey=(RSAPrivateKey)keyPair.getPrivate(); Map keyMap=newHashMap (2); keyMap.put(PUBLIC_KEY,publicKey); keyMap.put(PRIVATE_KEY,privateKey); returnkeyMap; } //获得公钥字符串 publicstaticStringgetPublicKeyStr(Map keyMap){ //获得map中的公钥对象转为key对象 Keykey=(Key)keyMap.get(PUBLIC_KEY); //编码返回字符串 returnencryptBASE64(key.getEncoded()); } //获得私钥字符串 publicstaticStringgetPrivateKeyStr(Map keyMap){ //获得map中的私钥对象转为key对象 Keykey=(Key)keyMap.get(PRIVATE_KEY); //编码返回字符串 returnencryptBASE64(key.getEncoded()); } //编码返回字符串 publicstaticStringencryptBASE64(byte[]key){ return(newBASE64Encoder()).encodeBuffer(key); } //解码返回byte publicstaticbyte[]decryptBASE64(Stringkey){ byte[]bytes=null; try{ return(newBASE64Decoder()).decodeBuffer(key); }catch(IOExceptione){ returnbytes; } } publicstaticvoidmain(String[]args){ Map keyMap=initKey(); StringpublicKey=getPublicKeyStr(keyMap); log.info("JAVA生成RSA公钥:{}",publicKey); StringprivateKey=getPrivateKeyStr(keyMap); log.info("JAVA生成RSA私钥:{}",privateKey); } }
注意:
本文中请求和响应类中的私钥和公钥均是不完整的,在请求和响应类中的私钥和公钥由RSASignUtils工具类生成后,再替代入请求和响应类中,请求类中使用私钥加签,响应类中使用公钥验签。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持毛票票。如有错误或未考虑完全的地方,望不吝赐教。