|
@@ -0,0 +1,253 @@
|
|
|
|
+package cn.com.qmth.examcloud.starters.crypto.utils;
|
|
|
|
+
|
|
|
|
+import cn.com.qmth.examcloud.starters.crypto.common.CryptoConstant;
|
|
|
|
+import cn.com.qmth.examcloud.starters.crypto.common.CryptoException;
|
|
|
|
+import org.apache.commons.codec.binary.Base64;
|
|
|
|
+import org.slf4j.Logger;
|
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
|
+
|
|
|
|
+import javax.crypto.BadPaddingException;
|
|
|
|
+import javax.crypto.Cipher;
|
|
|
|
+import javax.crypto.IllegalBlockSizeException;
|
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
|
+import java.security.*;
|
|
|
|
+import java.security.interfaces.RSAPrivateKey;
|
|
|
|
+import java.security.interfaces.RSAPublicKey;
|
|
|
|
+import java.security.spec.InvalidKeySpecException;
|
|
|
|
+import java.security.spec.PKCS8EncodedKeySpec;
|
|
|
|
+import java.security.spec.X509EncodedKeySpec;
|
|
|
|
+import java.util.Arrays;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ * RSA加、解密
|
|
|
|
+ */
|
|
|
|
+public class RsaUtil {
|
|
|
|
+
|
|
|
|
+ private static final Logger log = LoggerFactory.getLogger(RsaUtil.class);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ * 算法
|
|
|
|
+ */
|
|
|
|
+ private static final String ALGORITHM = "RSA";
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ * 签名算法
|
|
|
|
+ */
|
|
|
|
+ private static final String SIGN_ALGORITHM = "SHA1WithRSA";
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ * 默认密钥长度
|
|
|
|
+ */
|
|
|
|
+ private static final int DEFAULT_KEY_SIZE = 1024;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ * RSA加密最大明文长度
|
|
|
|
+ * 注:RSA加密对明文的长度有限制,最大长度 = 密钥长度 - 11
|
|
|
|
+ * 即:1024位 / 8位 - 11 = 117(字节)
|
|
|
|
+ */
|
|
|
|
+ private static final int MAX_ENCRYPT_BLOCK = 117;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ * RSA解密最大密文长度
|
|
|
|
+ * 注:RSA解密对密文的长度有限制,RSA加密时内容字节不足时会使用填充模式
|
|
|
|
+ * 即:1024位 / 8位 = 128(字节)
|
|
|
|
+ */
|
|
|
|
+ private static final int MAX_DECRYPT_BLOCK = 128;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ * 公钥加密
|
|
|
|
+ */
|
|
|
|
+ public static String publicEncrypt(String str, RSAPublicKey publicKey) {
|
|
|
|
+ try {
|
|
|
|
+ Cipher cipher = Cipher.getInstance(ALGORITHM);
|
|
|
|
+ cipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
|
|
|
+
|
|
|
|
+ byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
|
|
|
|
+ byte[] result = cipherResult(cipher, bytes, MAX_ENCRYPT_BLOCK);
|
|
|
|
+
|
|
|
|
+ return Base64.encodeBase64String(result);
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ log.error(e.getMessage());
|
|
|
|
+ throw new CryptoException(CryptoConstant.ENCRYPT_ERROR, e);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ * 公钥解密
|
|
|
|
+ */
|
|
|
|
+ public static String publicDecrypt(String str, RSAPublicKey publicKey) {
|
|
|
|
+ try {
|
|
|
|
+ Cipher cipher = Cipher.getInstance(ALGORITHM);
|
|
|
|
+ cipher.init(Cipher.DECRYPT_MODE, publicKey);
|
|
|
|
+
|
|
|
|
+ byte[] bytes = Base64.decodeBase64(str);
|
|
|
|
+ byte[] result = cipherResult(cipher, bytes, MAX_DECRYPT_BLOCK);
|
|
|
|
+
|
|
|
|
+ return new String(result, StandardCharsets.UTF_8);
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ log.error(e.getMessage());
|
|
|
|
+ throw new CryptoException(CryptoConstant.DECRYPT_ERROR, e);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ * 私钥加密
|
|
|
|
+ */
|
|
|
|
+ public static String privateEncrypt(String str, RSAPrivateKey privateKey) {
|
|
|
|
+ try {
|
|
|
|
+ Cipher cipher = Cipher.getInstance(ALGORITHM);
|
|
|
|
+ cipher.init(Cipher.ENCRYPT_MODE, privateKey);
|
|
|
|
+
|
|
|
|
+ byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
|
|
|
|
+ byte[] result = cipherResult(cipher, bytes, MAX_ENCRYPT_BLOCK);
|
|
|
|
+
|
|
|
|
+ return Base64.encodeBase64String(result);
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ log.error(e.getMessage());
|
|
|
|
+ throw new CryptoException(CryptoConstant.ENCRYPT_ERROR, e);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ * 私钥解密
|
|
|
|
+ */
|
|
|
|
+ public static String privateDecrypt(String str, RSAPrivateKey privateKey) {
|
|
|
|
+ try {
|
|
|
|
+ Cipher cipher = Cipher.getInstance(ALGORITHM);
|
|
|
|
+ cipher.init(Cipher.DECRYPT_MODE, privateKey);
|
|
|
|
+
|
|
|
|
+ byte[] bytes = Base64.decodeBase64(str);
|
|
|
|
+ byte[] result = cipherResult(cipher, bytes, MAX_DECRYPT_BLOCK);
|
|
|
|
+
|
|
|
|
+ return new String(result, StandardCharsets.UTF_8);
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ log.error(e.getMessage());
|
|
|
|
+ throw new CryptoException(CryptoConstant.DECRYPT_ERROR, e);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ * 对数据分段加密或解密
|
|
|
|
+ */
|
|
|
|
+ private static byte[] cipherResult(Cipher cipher, byte[] bytes, int maxBlock)
|
|
|
|
+ throws IllegalBlockSizeException, BadPaddingException {
|
|
|
|
+ int strLength = bytes.length;
|
|
|
|
+ int offset = 0;
|
|
|
|
+
|
|
|
|
+ byte[] result = {}, cache;
|
|
|
|
+ while (strLength - offset > 0) {
|
|
|
|
+ if (strLength - offset > maxBlock) {
|
|
|
|
+ cache = cipher.doFinal(bytes, offset, maxBlock);
|
|
|
|
+ offset += maxBlock;
|
|
|
|
+ } else {
|
|
|
|
+ cache = cipher.doFinal(bytes, offset, strLength - offset);
|
|
|
|
+ offset = strLength;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ result = Arrays.copyOf(result, result.length + cache.length);
|
|
|
|
+ System.arraycopy(cache, 0, result, result.length - cache.length, cache.length);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return result;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ * 私钥签名
|
|
|
|
+ */
|
|
|
|
+ public static String sign(String str, PrivateKey privateKey) {
|
|
|
|
+ try {
|
|
|
|
+ Signature signature = Signature.getInstance(SIGN_ALGORITHM);
|
|
|
|
+
|
|
|
|
+ signature.initSign(privateKey);
|
|
|
|
+ signature.update(str.getBytes(StandardCharsets.UTF_8));
|
|
|
|
+
|
|
|
|
+ byte[] result = signature.sign();
|
|
|
|
+ return Base64.encodeBase64String(result);
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ log.error(e.getMessage());
|
|
|
|
+ throw new CryptoException("签名失败!", e);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ * 公钥验证签名
|
|
|
|
+ */
|
|
|
|
+ public static boolean verifySign(String str, String signStr, PublicKey publicKey) {
|
|
|
|
+ try {
|
|
|
|
+ Signature verifySign = Signature.getInstance(SIGN_ALGORITHM);
|
|
|
|
+
|
|
|
|
+ verifySign.initVerify(publicKey);
|
|
|
|
+ verifySign.update(str.getBytes(StandardCharsets.UTF_8));
|
|
|
|
+
|
|
|
|
+ byte[] bytes = Base64.decodeBase64(signStr);
|
|
|
|
+ return verifySign.verify(bytes);
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ log.error(e.getMessage(), e);
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ * 随机生成公、私钥
|
|
|
|
+ */
|
|
|
|
+ public static KeyPair randomKey() {
|
|
|
|
+ try {
|
|
|
|
+ KeyPairGenerator generator = KeyPairGenerator.getInstance(ALGORITHM);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ generator.initialize(DEFAULT_KEY_SIZE, new SecureRandom());
|
|
|
|
+
|
|
|
|
+ return generator.generateKeyPair();
|
|
|
|
+ } catch (NoSuchAlgorithmException e) {
|
|
|
|
+ log.error(e.getMessage());
|
|
|
|
+ throw new RuntimeException(e);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ * 获取RSA公钥
|
|
|
|
+ */
|
|
|
|
+ public static RSAPublicKey getPublicKey(String publicKeyStr) {
|
|
|
|
+ KeyFactory keyFactory;
|
|
|
|
+ try {
|
|
|
|
+ keyFactory = KeyFactory.getInstance(ALGORITHM);
|
|
|
|
+ } catch (NoSuchAlgorithmException e) {
|
|
|
|
+ log.error(e.getMessage());
|
|
|
|
+ throw new RuntimeException(e);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ byte[] bytes = Base64.decodeBase64(publicKeyStr);
|
|
|
|
+ try {
|
|
|
|
+
|
|
|
|
+ X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
|
|
|
|
+ return (RSAPublicKey) keyFactory.generatePublic(keySpec);
|
|
|
|
+ } catch (InvalidKeySpecException e) {
|
|
|
|
+ log.error(e.getMessage());
|
|
|
|
+ throw new CryptoException(CryptoConstant.KEY_ERROR, e);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ * 获取RSA私钥
|
|
|
|
+ */
|
|
|
|
+ public static RSAPrivateKey getPrivateKey(String privateKeyStr) {
|
|
|
|
+ KeyFactory keyFactory;
|
|
|
|
+ try {
|
|
|
|
+ keyFactory = KeyFactory.getInstance(ALGORITHM);
|
|
|
|
+ } catch (NoSuchAlgorithmException e) {
|
|
|
|
+ log.error(e.getMessage());
|
|
|
|
+ throw new RuntimeException(e);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ byte[] bytes = Base64.decodeBase64(privateKeyStr);
|
|
|
|
+ try {
|
|
|
|
+
|
|
|
|
+ PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
|
|
|
|
+ return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
|
|
|
|
+ } catch (InvalidKeySpecException e) {
|
|
|
|
+ log.error(e.getMessage());
|
|
|
|
+ throw new CryptoException(CryptoConstant.KEY_ERROR, e);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+}
|