package com.upex.utils.crypto;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.springframework.util.Base64Utils;
import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
@Slf4j
public class RSAUtil {
private static final String CHAR_ENCODING = "UTF-8";
private static final String RSA_ALGORITHM = "RSA/ECB/PKCS1Padding";
private static int KEYSIZE = 1024;
public static Map<String, String> generateKeyPair() throws Exception {
SecureRandom sr = new SecureRandom();
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(KEYSIZE, sr);
KeyPair kp = kpg.generateKeyPair();
Key publicKey = kp.getPublic();
byte[] publicKeyBytes = publicKey.getEncoded();
String pub = new String(Base64.encodeBase64(publicKeyBytes), CHAR_ENCODING);
Key privateKey = kp.getPrivate();
byte[] privateKeyBytes = privateKey.getEncoded();
String pri = new String(Base64.encodeBase64(privateKeyBytes), CHAR_ENCODING);
Map<String, String> map = new HashMap<String, String>();
map.put("publicKey", pub);
map.put("privateKey", pri);
return map;
}
public static String encryptByPublicKey(String source, String publicKey) throws Exception {
Key key = getPublicKey(publicKey);
return encrypt(source, key);
}
private static String encrypt(String source, Key key) throws Exception {
Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] b = source.getBytes();
int MAX_ENCRYPT_BLOCK = 117;
int offSet = 0;
byte[] resultBytes = {};
byte[] cache = {};
int inputLength = b.length;
while (inputLength - offSet > 0) {
if (inputLength - offSet > MAX_ENCRYPT_BLOCK) {
cache = cipher.doFinal(b, offSet, MAX_ENCRYPT_BLOCK);
offSet += MAX_ENCRYPT_BLOCK;
} else {
cache = cipher.doFinal(b, offSet, inputLength - offSet);
offSet = inputLength;
}
resultBytes = Arrays.copyOf(resultBytes, resultBytes.length + cache.length);
System.arraycopy(cache, 0, resultBytes, resultBytes.length - cache.length, cache.length);
}
return new String(Base64.encodeBase64(resultBytes), CHAR_ENCODING);
}
public static String decryptByPrivateKey(String cryptograph, String privateKey) throws Exception {
Key key = getPrivateKey(privateKey);
return decrypt(cryptograph, key);
}
private static String decrypt(String cryptograph, Key key) throws Exception {
Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] bytes = Base64.decodeBase64(cryptograph.getBytes());
int inputLen = bytes.length;
int offLen = 0;
int i = 0;
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
while (inputLen - offLen > 0) {
byte[] cache;
if (inputLen - offLen > 128) {
cache = cipher.doFinal(bytes, offLen, 128);
} else {
cache = cipher.doFinal(bytes, offLen, inputLen - offLen);
}
byteArrayOutputStream.write(cache);
i++;
offLen = 128 * i;
}
byteArrayOutputStream.close();
byte[] byteArray = byteArrayOutputStream.toByteArray();
return new String(byteArray);
}
private static PublicKey getPublicKey(String key) throws Exception {
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.decodeBase64(key.getBytes()));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(keySpec);
return publicKey;
}
private static PrivateKey getPrivateKey(String key) throws Exception {
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(key.getBytes()));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePrivate(keySpec);
}
public static String sign(String content, String privateKey) {
try {
PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey.getBytes()));
KeyFactory keyf = KeyFactory.getInstance("RSA");
PrivateKey priKey = keyf.generatePrivate(priPKCS8);
Signature signature = Signature.getInstance("SHA1WithRSA");
signature.initSign(priKey);
signature.update(content.getBytes(CHAR_ENCODING));
return new String(Base64.encodeBase64(signature.sign()));
} catch (Exception e) {
log.error("create sign failed", e);
}
return null;
}
public static boolean checkSign(String content, String sign, String publicKey) {
try {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] encodedKey = Base64.decodeBase64(publicKey);
PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
Signature signature = Signature.getInstance("SHA1WithRSA");
signature.initVerify(pubKey);
signature.update(content.getBytes("utf-8"));
return signature.verify(Base64.decodeBase64(sign));
} catch (Exception e) {
log.error("checkSign failed", e);
}
return false;
}
public static String encryptByPrivateKey(String source, String privateKey) throws Exception {
Key key = getPrivateKey(privateKey);
return encrypt(source, key);
}
public static String decryptByPublicKey(String cryptograph, String publicKey) throws Exception {
Key key = getPublicKey(publicKey);
return decrypt(cryptograph, key);
}
public static String signByMap(TreeMap content, String privateKey) {
try {
PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64Utils.decodeFromString(privateKey));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey priKey = keyFactory.generatePrivate(priPKCS8);
Signature signature = Signature.getInstance("SHA1WithRSA");
signature.initSign(priKey);
signature.update(JSON.toJSONString(content).getBytes(StandardCharsets.UTF_8));
return Base64Utils.encodeToString(signature.sign());
} catch (Exception e) {
throw new RuntimeException("create sign failed", e);
}
}
public static boolean checkSignByMap(TreeMap content, String sign, String publicKey) {
try {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(Base64Utils.decodeFromString(publicKey)));
Signature signature = Signature.getInstance("SHA1WithRSA");
signature.initVerify(pubKey);
signature.update(JSON.toJSONString(content).getBytes(StandardCharsets.UTF_8));
return signature.verify(Base64Utils.decodeFromString(sign));
} catch (Exception e) {
log.error("verifySign failed", e);
return false;
}
}
public static boolean checkUrlSign(String content, String sign, String publicKey) {
try {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] encodedKey = Base64.decodeBase64(publicKey);
PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
Signature signature = Signature.getInstance("SHA1WithRSA");
signature.initVerify(pubKey);
signature.update(content.getBytes("utf-8"));
return signature.verify(Base64.decodeBase64(sign));
} catch (Exception e) {
log.error("checkSign failed", e);
}
return true;
}
}