SHA256withRSA 完美工具类 RSAUtils

ゞ 浴缸里的玫瑰 2021-12-03 18:29 728阅读 0赞

SHA256withRSA 完美工具类 RSAUtils,包含:

  1. 1、签名
  2. 2、验签
  3. 3、公钥加密》私钥解密
  4. 4、私钥加密》公钥解密

代码:RSAUtils.java

  1. import java.io.File;
  2. import java.io.FileInputStream;
  3. import java.io.FileNotFoundException;
  4. import java.io.IOException;
  5. import java.io.InputStream;
  6. import java.io.UnsupportedEncodingException;
  7. import java.security.InvalidKeyException;
  8. import java.security.Key;
  9. import java.security.KeyFactory;
  10. import java.security.KeyPair;
  11. import java.security.KeyPairGenerator;
  12. import java.security.KeyStore;
  13. import java.security.NoSuchAlgorithmException;
  14. import java.security.PrivateKey;
  15. import java.security.PublicKey;
  16. import java.security.SecureRandom;
  17. import java.security.Signature;
  18. import java.security.cert.CertificateException;
  19. import java.security.cert.CertificateFactory;
  20. import java.security.cert.X509Certificate;
  21. import java.security.interfaces.RSAPrivateKey;
  22. import java.security.interfaces.RSAPublicKey;
  23. import java.security.spec.InvalidKeySpecException;
  24. import java.security.spec.PKCS8EncodedKeySpec;
  25. import java.security.spec.X509EncodedKeySpec;
  26. import java.util.Enumeration;
  27. import java.util.HashMap;
  28. import java.util.Map;
  29. import javax.crypto.BadPaddingException;
  30. import javax.crypto.Cipher;
  31. import javax.crypto.IllegalBlockSizeException;
  32. import javax.crypto.NoSuchPaddingException;
  33. import org.apache.commons.codec.binary.Base64;
  34. import org.apache.commons.lang3.ArrayUtils;
  35. import org.slf4j.Logger;
  36. import org.slf4j.LoggerFactory;
  37. /**
  38. * SHA256withRSA
  39. *
  40. * @author 单红宇
  41. * @date 2019年7月18日
  42. *
  43. */
  44. public class RSAUtils {
  45. private static final Logger logger = LoggerFactory.getLogger(RSAUtils.class);
  46. // MAX_DECRYPT_BLOCK应等于密钥长度/8(1byte=8bit),所以当密钥位数为2048时,最大解密长度应为256.
  47. // 128 对应 1024,256对应2048
  48. private static final int KEYSIZE = 2048;
  49. // RSA最大加密明文大小
  50. private static final int MAX_ENCRYPT_BLOCK = 117;
  51. // RSA最大解密密文大小
  52. private static final int MAX_DECRYPT_BLOCK = 128;
  53. // 不仅可以使用DSA算法,同样也可以使用RSA算法做数字签名
  54. private static final String KEY_ALGORITHM = "RSA";
  55. private static final String SIGNATURE_ALGORITHM = "SHA256withRSA";
  56. public static final String DEFAULT_SEED = "$%^*%^()(ED47d784sde78"; // 默认种子
  57. public static final String PUBLIC_KEY = "PublicKey";
  58. public static final String PRIVATE_KEY = "PrivateKey";
  59. /**
  60. *
  61. * 生成密钥
  62. *
  63. * @param seed 种子
  64. *
  65. * @return 密钥对象
  66. * @throws Exception
  67. *
  68. */
  69. public static Map<String, Key> initKey(String seed) throws Exception {
  70. logger.info("生成密钥");
  71. KeyPairGenerator keygen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
  72. SecureRandom secureRandom = new SecureRandom();
  73. // 如果指定seed,那么secureRandom结果是一样的,所以生成的公私钥也永远不会变
  74. // secureRandom.setSeed(seed.getBytes());
  75. // Modulus size must range from 512 to 1024 and be a multiple of 64
  76. keygen.initialize(KEYSIZE, secureRandom);
  77. KeyPair keys = keygen.genKeyPair();
  78. PrivateKey privateKey = keys.getPrivate();
  79. PublicKey publicKey = keys.getPublic();
  80. Map<String, Key> map = new HashMap<>(2);
  81. map.put(PUBLIC_KEY, publicKey);
  82. map.put(PRIVATE_KEY, privateKey);
  83. return map;
  84. }
  85. /**
  86. *
  87. * 生成默认密钥
  88. *
  89. *
  90. * @return 密钥对象
  91. * @throws Exception
  92. *
  93. */
  94. public static Map<String, Key> initKey() throws Exception {
  95. return initKey(DEFAULT_SEED);
  96. }
  97. /**
  98. *
  99. * 取得私钥
  100. *
  101. * @param keyMap
  102. *
  103. * @return
  104. * @throws Exception
  105. *
  106. */
  107. public static String getPrivateKey(Map<String, Key> keyMap) throws Exception {
  108. Key key = (Key) keyMap.get(PRIVATE_KEY);
  109. return encryptBASE64(key.getEncoded()); // base64加密私钥
  110. }
  111. /**
  112. *
  113. * 取得公钥
  114. *
  115. * @param keyMap
  116. *
  117. * @return
  118. * @throws Exception
  119. *
  120. */
  121. public static String getPublicKey(Map<String, Key> keyMap) throws Exception {
  122. Key key = (Key) keyMap.get(PUBLIC_KEY);
  123. return encryptBASE64(key.getEncoded()); // base64加密公钥
  124. }
  125. /**
  126. *
  127. * 用私钥对信息进行数字签名
  128. *
  129. * @param data 加密数据
  130. *
  131. * @param privateKey 私钥-base64加密的
  132. *
  133. * @return
  134. *
  135. * @throws Exception
  136. *
  137. */
  138. public static String signByPrivateKey(byte[] data, String privateKey) throws Exception {
  139. logger.info("用私钥对信息进行数字签名");
  140. byte[] keyBytes = decryptBASE64(privateKey);
  141. PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
  142. KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM);
  143. PrivateKey priKey = factory.generatePrivate(keySpec);// 生成私钥
  144. // 用私钥对信息进行数字签名
  145. Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
  146. signature.initSign(priKey);
  147. signature.update(data);
  148. return encryptBASE64(signature.sign());
  149. }
  150. /**
  151. *
  152. * BASE64Encoder 加密
  153. *
  154. * @param data 要加密的数据
  155. *
  156. * @return 加密后的字符串
  157. *
  158. */
  159. private static String encryptBASE64(byte[] data) {
  160. // BASE64Encoder encoder = new BASE64Encoder();
  161. // String encode = encoder.encode(data);
  162. // return encode;
  163. return new String(Base64.encodeBase64(data));
  164. }
  165. private static byte[] decryptBASE64(String data) {
  166. // BASE64Decoder 每76个字符换行
  167. // BASE64Decoder decoder = new BASE64Decoder();
  168. // byte[] buffer = decoder.decodeBuffer(data);
  169. // return buffer;
  170. // codec 的 Base64 不换行
  171. return Base64.decodeBase64(data);
  172. }
  173. public static boolean verifyByPublicKey(byte[] data, String publicKey, String sign) throws Exception {
  174. byte[] keyBytes = decryptBASE64(publicKey);
  175. X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
  176. KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
  177. PublicKey pubKey = keyFactory.generatePublic(keySpec);
  178. Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
  179. signature.initVerify(pubKey);
  180. signature.update(data);
  181. return signature.verify(decryptBASE64(sign)); // 验证签名
  182. }
  183. /**
  184. * RSA公钥加密
  185. *
  186. * @param str 加密字符串
  187. * @param publicKey 公钥
  188. * @return 密文
  189. * @throws NoSuchAlgorithmException
  190. * @throws InvalidKeySpecException
  191. * @throws NoSuchPaddingException
  192. * @throws InvalidKeyException
  193. * @throws UnsupportedEncodingException
  194. * @throws BadPaddingException
  195. * @throws IllegalBlockSizeException
  196. * @throws Exception 加密过程中的异常信息
  197. */
  198. public static String encryptByPublicKey(String str, String publicKey)
  199. throws InvalidKeySpecException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
  200. IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
  201. // base64编码的公钥
  202. byte[] keyBytes = decryptBASE64(publicKey);
  203. RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance(KEY_ALGORITHM)
  204. .generatePublic(new X509EncodedKeySpec(keyBytes));
  205. // RSA加密
  206. Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
  207. cipher.init(Cipher.ENCRYPT_MODE, pubKey);
  208. byte[] data = str.getBytes("UTF-8");
  209. // 加密时超过117字节就报错。为此采用分段加密的办法来加密
  210. byte[] enBytes = null;
  211. for (int i = 0; i < data.length; i += MAX_ENCRYPT_BLOCK) {
  212. // 注意要使用2的倍数,否则会出现加密后的内容再解密时为乱码
  213. byte[] doFinal = cipher.doFinal(ArrayUtils.subarray(data, i, i + MAX_ENCRYPT_BLOCK));
  214. enBytes = ArrayUtils.addAll(enBytes, doFinal);
  215. }
  216. String outStr = encryptBASE64(enBytes);
  217. return outStr;
  218. }
  219. /**
  220. * RSA私钥加密
  221. *
  222. * @param str 加密字符串
  223. * @param privateKey 公钥
  224. * @return 密文
  225. * @throws NoSuchAlgorithmException
  226. * @throws InvalidKeySpecException
  227. * @throws NoSuchPaddingException
  228. * @throws InvalidKeyException
  229. * @throws UnsupportedEncodingException
  230. * @throws BadPaddingException
  231. * @throws IllegalBlockSizeException
  232. * @throws Exception 加密过程中的异常信息
  233. */
  234. public static String encryptByPrivateKey(String str, String privateKey)
  235. throws InvalidKeySpecException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
  236. IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
  237. // base64编码的公钥
  238. byte[] keyBytes = decryptBASE64(privateKey);
  239. RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance(KEY_ALGORITHM)
  240. .generatePrivate(new PKCS8EncodedKeySpec(keyBytes));
  241. // RSA加密
  242. Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
  243. cipher.init(Cipher.ENCRYPT_MODE, priKey);
  244. byte[] data = str.getBytes("UTF-8");
  245. // 加密时超过117字节就报错。为此采用分段加密的办法来加密
  246. byte[] enBytes = null;
  247. for (int i = 0; i < data.length; i += MAX_ENCRYPT_BLOCK) {
  248. // 注意要使用2的倍数,否则会出现加密后的内容再解密时为乱码
  249. byte[] doFinal = cipher.doFinal(ArrayUtils.subarray(data, i, i + MAX_ENCRYPT_BLOCK));
  250. enBytes = ArrayUtils.addAll(enBytes, doFinal);
  251. }
  252. String outStr = encryptBASE64(enBytes);
  253. return outStr;
  254. }
  255. /**
  256. * 读取公钥
  257. *
  258. * @param publicKeyPath
  259. * @return
  260. */
  261. public static PublicKey readPublic(String publicKeyPath) {
  262. if (publicKeyPath != null) {
  263. try (FileInputStream bais = new FileInputStream(publicKeyPath)) {
  264. CertificateFactory certificatefactory = CertificateFactory.getInstance("X.509");
  265. X509Certificate cert = (X509Certificate) certificatefactory.generateCertificate(bais);
  266. return cert.getPublicKey();
  267. } catch (CertificateException e) {
  268. logger.error(e.getMessage(), e);
  269. } catch (FileNotFoundException e) {
  270. logger.error(e.getMessage(), e);
  271. } catch (IOException e) {
  272. logger.error(e.getMessage(), e);
  273. }
  274. }
  275. return null;
  276. }
  277. /**
  278. * 读取私钥
  279. *
  280. * @param path
  281. * @return
  282. */
  283. public static PrivateKey readPrivate(String privateKeyPath, String privateKeyPwd) {
  284. if (privateKeyPath == null || privateKeyPwd == null) {
  285. return null;
  286. }
  287. try (InputStream stream = new FileInputStream(new File(privateKeyPath));) {
  288. // 获取JKS 服务器私有证书的私钥,取得标准的JKS的 KeyStore实例
  289. KeyStore store = KeyStore.getInstance("JKS");// JKS,二进制格式,同时包含证书和私钥,一般有密码保护;PKCS12,二进制格式,同时包含证书和私钥,一般有密码保护。
  290. // jks文件密码,根据实际情况修改
  291. store.load(stream, privateKeyPwd.toCharArray());
  292. // 获取jks证书别名
  293. Enumeration<String> en = store.aliases();
  294. String pName = null;
  295. while (en.hasMoreElements()) {
  296. String n = (String) en.nextElement();
  297. if (store.isKeyEntry(n)) {
  298. pName = n;
  299. }
  300. }
  301. // 获取证书的私钥
  302. PrivateKey key = (PrivateKey) store.getKey(pName, privateKeyPwd.toCharArray());
  303. return key;
  304. } catch (Exception e) {
  305. logger.error(e.getMessage(), e);
  306. }
  307. return null;
  308. }
  309. /**
  310. * RSA私钥解密
  311. *
  312. * @param encryStr 加密字符串
  313. * @param privateKey 私钥
  314. * @return 铭文
  315. * @throws NoSuchAlgorithmException
  316. * @throws InvalidKeySpecException
  317. * @throws NoSuchPaddingException
  318. * @throws BadPaddingException
  319. * @throws IllegalBlockSizeException
  320. * @throws InvalidKeyException
  321. * @throws Exception 解密过程中的异常信息
  322. */
  323. public static String decryptByPrivateKey(String encryStr, String privateKey)
  324. throws InvalidKeySpecException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException,
  325. BadPaddingException, InvalidKeyException {
  326. // base64编码的私钥
  327. byte[] decoded = decryptBASE64(privateKey);
  328. RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance(KEY_ALGORITHM)
  329. .generatePrivate(new PKCS8EncodedKeySpec(decoded));
  330. // RSA解密
  331. Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
  332. cipher.init(Cipher.DECRYPT_MODE, priKey);
  333. // 64位解码加密后的字符串
  334. byte[] data = decryptBASE64(encryStr);
  335. // 解密时超过128字节报错。为此采用分段解密的办法来解密
  336. StringBuilder sb = new StringBuilder();
  337. for (int i = 0; i < data.length; i += MAX_DECRYPT_BLOCK) {
  338. byte[] doFinal = cipher.doFinal(ArrayUtils.subarray(data, i, i + MAX_DECRYPT_BLOCK));
  339. sb.append(new String(doFinal));
  340. }
  341. return sb.toString();
  342. }
  343. /**
  344. * RSA公钥解密
  345. *
  346. * @param encryStr 加密字符串
  347. * @param privateKey 私钥
  348. * @return 铭文
  349. * @throws NoSuchAlgorithmException
  350. * @throws InvalidKeySpecException
  351. * @throws NoSuchPaddingException
  352. * @throws BadPaddingException
  353. * @throws IllegalBlockSizeException
  354. * @throws InvalidKeyException
  355. * @throws Exception 解密过程中的异常信息
  356. */
  357. public static String decryptByPublicKey(String encryStr, String publicKey)
  358. throws InvalidKeySpecException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException,
  359. BadPaddingException, InvalidKeyException {
  360. // base64编码的私钥
  361. byte[] decoded = decryptBASE64(publicKey);
  362. RSAPublicKey priKey = (RSAPublicKey) KeyFactory.getInstance(KEY_ALGORITHM)
  363. .generatePublic(new X509EncodedKeySpec(decoded));
  364. // RSA解密
  365. Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
  366. cipher.init(Cipher.DECRYPT_MODE, priKey);
  367. // 64位解码加密后的字符串
  368. byte[] data = decryptBASE64(encryStr);
  369. // 解密时超过128字节报错。为此采用分段解密的办法来解密
  370. StringBuilder sb = new StringBuilder();
  371. for (int i = 0; i < data.length; i += MAX_DECRYPT_BLOCK) {
  372. byte[] doFinal = cipher.doFinal(ArrayUtils.subarray(data, i, i + MAX_DECRYPT_BLOCK));
  373. sb.append(new String(doFinal));
  374. }
  375. return sb.toString();
  376. }
  377. /**
  378. * main方法测试 第一种用法:公钥加密,私钥解密。---用于加解密 第二种用法:私钥签名,公钥验签。---用于签名
  379. *
  380. * @param args
  381. * @throws Exception
  382. */
  383. public static void main(String[] args) throws Exception {
  384. String ss = "hello";
  385. byte[] data = ss.getBytes();
  386. Map<String, Key> keyMap = initKey();// 构建密钥
  387. PublicKey publicKey = (PublicKey) keyMap.get(PUBLIC_KEY);
  388. PrivateKey privateKey = (PrivateKey) keyMap.get(PRIVATE_KEY);
  389. logger.info("私钥format:{}", privateKey.getFormat());
  390. logger.info("公钥format:{}", publicKey.getFormat());
  391. logger.info("私钥string:{}", getPrivateKey(keyMap));
  392. logger.info("公钥string:{}", getPublicKey(keyMap));
  393. // 产生签名
  394. String sign = signByPrivateKey(data, getPrivateKey(keyMap));
  395. logger.info("签名sign={}", sign);
  396. // 验证签名
  397. boolean verify1 = verifyByPublicKey(ss.getBytes(), getPublicKey(keyMap), sign);
  398. logger.info("经验证数据和签名匹配:{} ", verify1);
  399. boolean verify = verifyByPublicKey(data, getPublicKey(keyMap), sign);
  400. logger.error("经验证数据和签名匹配:{} ", verify);
  401. // logger.info("数字签名为"+sign);
  402. String s = "单红宇测试,e8986ae53e76e7514ebc7e8a42e81e6cea5b6280fb5d3259d5f0a46f9f6e090c";
  403. String encryStr = encryptByPublicKey(s, getPublicKey(keyMap));
  404. logger.info("字符串 {} 的公钥加密结果为:{}", s, encryStr);
  405. String decryStr = decryptByPrivateKey(encryStr, getPrivateKey(keyMap));
  406. logger.info("私钥解密结果为:{}", decryStr);
  407. logger.info("========================================================================================");
  408. String s2 = "单红宇测试222,e8986ae53e76e7514ebc7e8a42e81e6cea5b6280fb5d3259d5f0a46f9f6e090c";
  409. String encryStr2 = encryptByPrivateKey(s, getPrivateKey(keyMap));
  410. logger.info("字符串 {} 的私钥加密结果为:{}", s2, encryStr2);
  411. String decryStr2 = decryptByPublicKey(encryStr2, getPublicKey(keyMap));
  412. logger.info("公钥解密结果为:{}", decryStr2);
  413. }
  414. }

(END)

发表评论

表情:
评论列表 (有 0 条评论,728人围观)

还没有评论,来说两句吧...

相关阅读

    相关 SHA256WithRSA

    在[上文][Link 1]中了解到SHA和RSA,工作中恰好用到扩展应用:SHA256WithRSA,本文总结下学习过程,备忘の 再提供另外一种方法,实现Java版pem密