RSASignatureTools.java 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. /*
  2. * FileName:RSASignatureTools.java
  3. * <p>
  4. * Copyright (c) 2017-2020, <a href="http://www.webcsn.com">hermit (794890569@qq.com)</a>.
  5. * <p>
  6. * Licensed under the GNU General Public License, Version 3 (the "License");
  7. * you may not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. * <p>
  10. * http://www.gnu.org/licenses/gpl-3.0.html
  11. * <p>
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. *
  18. */
  19. package cn.com.lzt.common.util.security;
  20. import com.daju.base.exception.UnexpectedException;
  21. import org.apache.commons.codec.binary.Base64;
  22. import java.io.*;
  23. import java.security.*;
  24. import java.security.interfaces.RSAPrivateKey;
  25. import java.security.interfaces.RSAPublicKey;
  26. import java.security.spec.InvalidKeySpecException;
  27. import java.security.spec.PKCS8EncodedKeySpec;
  28. import java.security.spec.X509EncodedKeySpec;
  29. /**
  30. * RSA签名工具类
  31. * @author xiaosf
  32. * @date 2017年6月8日
  33. */
  34. public class RSASignatureTools {
  35. /**
  36. * 生成RSA密码对,保存到basePath下
  37. * @param basePath 保存秘钥的路径
  38. * @throws Exception
  39. */
  40. public static void generateRSAKeys(String basePath,KeyStoreFileType keyType){
  41. File f=new File(basePath);
  42. if(!f.exists()){
  43. boolean b=f.mkdirs();
  44. if(!b){
  45. throw new UnexpectedException("不能创建目录:"+basePath);
  46. }
  47. }
  48. // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
  49. KeyPairGenerator keyPairGen = null;
  50. try {
  51. keyPairGen = KeyPairGenerator.getInstance("RSA");
  52. } catch (NoSuchAlgorithmException e) {
  53. throw new UnexpectedException("无此算法");
  54. }
  55. // 初始化密钥对生成器,密钥大小为96-1024位
  56. keyPairGen.initialize(1024,new SecureRandom());
  57. // 生成一个密钥对,保存在keyPair中
  58. KeyPair keyPair = keyPairGen.generateKeyPair();
  59. // 得到私钥
  60. RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
  61. // 得到公钥
  62. RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
  63. //生成秘钥
  64. byte[] pubks=publicKey.getEncoded();
  65. byte[] priKeys=privateKey.getEncoded();
  66. if(keyType== KeyStoreFileType.BINARY){//直接以二进制方式存储秘钥
  67. FileOutputStream pubfos=null;
  68. FileOutputStream prifos=null;
  69. try{
  70. pubfos=new FileOutputStream(basePath+"/public.key");
  71. pubfos.write(pubks, 0, pubks.length);
  72. pubfos.flush();
  73. prifos=new FileOutputStream(basePath+"/private.key");
  74. prifos.write(priKeys, 0, priKeys.length);
  75. prifos.flush();
  76. }catch(Exception e){
  77. }finally{
  78. if(pubfos!=null){
  79. try {
  80. pubfos.close();
  81. } catch (IOException e) {
  82. // TODO Auto-generated catch block
  83. e.printStackTrace();
  84. }
  85. }
  86. if(prifos!=null){
  87. try {
  88. prifos.close();
  89. } catch (IOException e) {
  90. // TODO Auto-generated catch block
  91. e.printStackTrace();
  92. }
  93. }
  94. }
  95. }else if(keyType== KeyStoreFileType.BASE64){
  96. BufferedWriter pubbw=null;
  97. BufferedWriter pribw=null;
  98. try{
  99. pubbw = new BufferedWriter(new FileWriter(basePath + "/public.key"));
  100. pribw = new BufferedWriter(new FileWriter(basePath + "/private.key"));
  101. pubbw.write(Base64.encodeBase64String(pubks));
  102. pribw.write(Base64.encodeBase64String(priKeys));
  103. pubbw.flush();
  104. pribw.flush();
  105. }catch(Exception e){
  106. }finally{
  107. if(pubbw!=null){
  108. try {
  109. pubbw.close();
  110. } catch (IOException e) {
  111. // TODO Auto-generated catch block
  112. e.printStackTrace();
  113. }
  114. }
  115. if(pribw!=null){
  116. try {
  117. pribw.close();
  118. } catch (IOException e) {
  119. // TODO Auto-generated catch block
  120. e.printStackTrace();
  121. }
  122. }
  123. }
  124. }else{
  125. throw new UnexpectedException("文件类型不正确");
  126. }
  127. }
  128. /**
  129. * 根据秘钥内容生成公钥
  130. * @param publicKey 公钥字节
  131. * @return
  132. * @throws Exception
  133. */
  134. public static RSAPublicKey generateRSAPubKey(byte[] publicKey){
  135. try {
  136. KeyFactory keyFactory = KeyFactory.getInstance("RSA");
  137. X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey);
  138. return (RSAPublicKey) keyFactory.generatePublic(keySpec);
  139. } catch (NoSuchAlgorithmException e) {
  140. throw new UnexpectedException("无此算法");
  141. } catch (InvalidKeySpecException e) {
  142. throw new UnexpectedException("公钥非法");
  143. } catch (NullPointerException e) {
  144. throw new UnexpectedException("公钥数据为空");
  145. }
  146. }
  147. /**
  148. * 根据秘钥文件生成公钥
  149. * @param keyStoreFile 公钥字节
  150. * @return
  151. * @throws Exception
  152. */
  153. public static RSAPublicKey generateRSAPubKey(String keyStoreFile,KeyStoreFileType type){
  154. try {
  155. KeyFactory keyFactory = KeyFactory.getInstance("RSA");
  156. X509EncodedKeySpec keySpec = new X509EncodedKeySpec(loadKeyByFile(keyStoreFile,type));
  157. return (RSAPublicKey) keyFactory.generatePublic(keySpec);
  158. } catch (NoSuchAlgorithmException e) {
  159. throw new UnexpectedException("无此算法");
  160. } catch (InvalidKeySpecException e) {
  161. throw new UnexpectedException("公钥非法");
  162. } catch (NullPointerException e) {
  163. throw new UnexpectedException("公钥数据为空");
  164. }
  165. }
  166. /**
  167. * 根据私钥内容生成私钥
  168. * @param privateKey 私钥字节
  169. * @return
  170. * @throws Exception
  171. */
  172. public static RSAPrivateKey generateRSAPriKey(byte[] privateKey){
  173. try {
  174. KeyFactory keyFactory = KeyFactory.getInstance("RSA");
  175. PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKey);
  176. return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
  177. } catch (NoSuchAlgorithmException e) {
  178. throw new UnexpectedException("无此算法");
  179. } catch (InvalidKeySpecException e) {
  180. throw new UnexpectedException("私钥非法");
  181. } catch (NullPointerException e) {
  182. throw new UnexpectedException("私钥数据为空");
  183. }
  184. }
  185. /**
  186. * 根据私钥文件生成私钥
  187. * @param privateKey 私钥字节
  188. * @return
  189. * @throws Exception
  190. */
  191. public static RSAPrivateKey generateRSAPriKey(String keyStoreFile,KeyStoreFileType type) {
  192. try {
  193. KeyFactory keyFactory = KeyFactory.getInstance("RSA");
  194. PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(loadKeyByFile(keyStoreFile,type));
  195. return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
  196. } catch (NoSuchAlgorithmException e) {
  197. throw new UnexpectedException("无此算法");
  198. } catch (InvalidKeySpecException e) {
  199. throw new UnexpectedException("私钥非法");
  200. } catch (NullPointerException e) {
  201. throw new UnexpectedException("私钥数据为空");
  202. }
  203. }
  204. /**
  205. * 加载二进制文件的key
  206. * @param file 文件路径
  207. * @param
  208. * @return
  209. * @throws Exception
  210. */
  211. public static byte[] loadKeyByFile(String file,KeyStoreFileType type) {
  212. try {
  213. FileInputStream fis = new FileInputStream(file);
  214. byte[] bs=new byte[fis.available()];
  215. fis.read(bs);
  216. fis.close();
  217. if(type== KeyStoreFileType.BASE64){
  218. bs=Base64.decodeBase64(bs);
  219. }
  220. return bs;
  221. } catch (IOException e) {
  222. throw new UnexpectedException("密钥数据流读取错误");
  223. } catch (NullPointerException e) {
  224. throw new UnexpectedException("密钥输入流为空");
  225. }
  226. }
  227. /**
  228. * 根据私钥生成数字签名
  229. * @param msgBytes 要签名的消息的字节数组
  230. * @param priKey 加密的私钥
  231. * @return
  232. */
  233. public static byte[] signature(byte[] msgBytes,PrivateKey priKey){
  234. try{
  235. Signature sig = Signature.getInstance("MD5WithRSA");//数字签名算法
  236. sig.initSign(priKey);// sig对象得到私钥
  237. // 签名对象得到原始数据
  238. sig.update(msgBytes);// sig对象得到原始数据(现实中用的是原始数据的摘要,摘要的是单向的,即摘要算法后无法解密)
  239. return sig.sign();// sig对象用私钥对原始数据进行签名,签名后得到签名signature
  240. }catch(Exception e){
  241. throw new UnexpectedException(e);
  242. }
  243. }
  244. /**
  245. * 验证签名
  246. * @param msgBytes 签名的消息对应的字节数组
  247. * @param signature 签名后的字节数组
  248. * @param pubKey 公钥
  249. * @return
  250. * @throws Exception
  251. */
  252. public static boolean verifySignature(byte[] msgBytes,byte[] signature,PublicKey pubKey){
  253. Signature sig =null;
  254. try{
  255. sig = Signature.getInstance("MD5WithRSA");//数字签名算法,
  256. // 使用公钥验证
  257. sig.initVerify(pubKey);// sig对象得到公钥
  258. // 签名对象得到原始信息
  259. sig.update(msgBytes);// sig对象得到原始数据(现实中是摘要)
  260. }catch(Exception e){
  261. throw new UnexpectedException(e);
  262. }
  263. try {
  264. return sig.verify(signature);
  265. } catch (SignatureException e) {
  266. return false;
  267. }
  268. }
  269. /**
  270. * 测试方法,待删除
  271. * @param args
  272. * @throws Exception
  273. */
  274. public static void main(String[] args) throws Exception {
  275. String pubFile="d:/keys/pubk";
  276. String priFile="d:/keys/prik";
  277. String testStr="fjsldfjlsdjl;safdsfds";
  278. RSAPublicKey pubKey=generateRSAPubKey(loadKeyByFile(pubFile, KeyStoreFileType.BINARY));
  279. RSAPrivateKey priKey=generateRSAPriKey(loadKeyByFile(priFile, KeyStoreFileType.BINARY));
  280. byte[] sig=signature(testStr.getBytes(),priKey);
  281. System.out.println(Base64.encodeBase64String(sig));
  282. boolean r=verifySignature(testStr.getBytes(),sig,pubKey);
  283. System.out.println(r);
  284. // String s="11111111";
  285. // System.out.println(Base64.encodeBase64String(s.getBytes()));
  286. }
  287. /**
  288. * 秘钥文件类型
  289. * @author xiaosf
  290. * @date 2017年6月16日
  291. */
  292. public static enum KeyStoreFileType{
  293. BINARY,BASE64
  294. }
  295. }