import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import com.ykx.orderCenter.dubbo.security.StreamUtil;
import sun.misc.BASE64Decoder;
/**
* 類名稱:util
* 類描述:
* 建立人:Administrator
* 建立時間:2019年7月23日 下午4:22:13
* 修改人:Administrator
* 修改時間:2019年7月23日 下午4:22:13
* 修改備注:
* @version
*/
public class RSASignUtil {
/** 簽名算法 */
private static final String SIGN_SHA256RSA_ALGORITHMS = "SHA256WithRSA";
/** 簽名類型*/
private static final String SIGN_TYPE_RSA = "RSA";
/** 算法長度,預設2048*/
public static final int KEY_SIZE = 2048;
/**
* 初始化RSA算法密鑰對
*
* @param keysize RSA1024已經不安全了,建議2048
* @return 經過Base64編碼後的公私鑰Map, 鍵名分别為publicKey和privateKey
*/
public static Map<String, String> initRSAKey(int keysize) {
if (keysize != KEY_SIZE) {
throw new IllegalArgumentException("RSA1024已經不安全了,請使用" + KEY_SIZE + "初始化RSA密鑰對");
}
//為RSA算法建立一個KeyPairGenerator對象
KeyPairGenerator kpg;
try {
kpg = KeyPairGenerator.getInstance(SIGN_TYPE_RSA);
} catch (NoSuchAlgorithmException e) {
throw new IllegalArgumentException("No such algorithm-->[" + SIGN_TYPE_RSA + "]");
}
//初始化KeyPairGenerator對象,不要被initialize()源碼表面上欺騙,其實這裡聲明的size是生效的
kpg.initialize(KEY_SIZE);
//生成密匙對
KeyPair keyPair = kpg.generateKeyPair();
//得到公鑰
Key publicKey = keyPair.getPublic();
String publicKeyStr = java.util.Base64.getEncoder().encodeToString(publicKey.getEncoded());
//得到私鑰
Key privateKey = keyPair.getPrivate();
String privateKeyStr = java.util.Base64.getEncoder().encodeToString(privateKey.getEncoded());
Map<String, String> keyPairMap = new HashMap<String, String>();
keyPairMap.put("publicKey", publicKeyStr);
keyPairMap.put("privateKey", privateKeyStr);
return keyPairMap;
}
/**
*
* @Description: 字元串轉公鑰方法1
* @param:@param key
* @param:@return
* @param:@throws Exception
* @return:PublicKey
* @throws:
*
* @version: v1.0.0
* @author: Administrator
* @date: 2019年7月24日 上午11:06:36
*/
public static PublicKey getPublicKeyFromX509(String key) throws Exception {
InputStream ins=new ByteArrayInputStream(key.getBytes());
KeyFactory keyFactory = KeyFactory.getInstance(SIGN_TYPE_RSA);
StringWriter writer = new StringWriter();
StreamUtil.io(new InputStreamReader(ins), writer);
byte[] encodedKey = writer.toString().getBytes();
encodedKey = Base64.decodeBase64(encodedKey);
return keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
}
/**
*
* @Description: 字元串轉公鑰方法2
* @param:@param key
* @param:@return
* @param:@throws Exception
* @return:PublicKey
* @throws:
*
* @version: v1.0.0
* @author: Administrator
* @date: 2019年7月24日 上午11:06:36
*/
public static PublicKey getPublicKey(String key) throws Exception {
byte[] keyBytes;
keyBytes = (new BASE64Decoder()).decodeBuffer(key);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(SIGN_TYPE_RSA);
PublicKey publicKey = keyFactory.generatePublic(keySpec);
return publicKey;
}
/**
*
* @Description: 字元串轉私鑰方法1
* @param:@param key
* @param:@return
* @param:@throws Exception
* @return:PrivateKey
* @throws:
*
* @version: v1.0.0
* @author: Administrator
* @date: 2019年7月24日 上午11:06:39
*/
public static PrivateKey getPrivateKey(String key) throws Exception {
byte[] keyBytes;
keyBytes = (new BASE64Decoder()).decodeBuffer(key);
// 通過PKCS#8編碼的Key指令獲得私鑰對象
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(SIGN_TYPE_RSA);
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
return privateKey;
}
/**
*
* @Description: TODO字元串轉私鑰方法2
* @param:@param key
* @param:@return
* @param:@throws Exception
* @return:PrivateKey
* @throws:
* @version: v1.0.0
* @author: Administrator
* @date: 2019年11月12日 下午4:56:50
*/
public static PrivateKey getPrivateKeyFromPKCS8(String key) throws Exception {
InputStream ins=new ByteArrayInputStream(key.getBytes());
if (ins == null || StringUtils.isEmpty(SIGN_TYPE_RSA)) {
return null;
}
KeyFactory keyFactory = KeyFactory.getInstance(SIGN_TYPE_RSA);
byte[] encodedKey = StreamUtil.readText(ins).getBytes();
encodedKey = Base64.decodeBase64(encodedKey);
return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encodedKey));
}
/**
*
* @Description: 處理待加密資料處理為URL鍵值對的格式(即key1=value1&key2=value2…)拼接成字元串stringA。
* 特别注意以下重要規則:
* ◆ 參數名ASCII碼從小到大排序(字典序);
* ◆ 如果參數的值為空不參與簽名;
* ◆ 參數名區分大小寫;
* @param:@param params
* @param:@return
* @return:String
* @throws:
* @version: v1.0.0
* @author: Administrator
* @date: 2019年11月12日 下午2:09:36
*/
public static String getSignCheckContent(Map<String, String> params) {
if (params == null) {
return null;
}
StringBuffer content = new StringBuffer();
List<String> keys = new ArrayList<String>(params.keySet());
Collections.sort(keys);
for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
String value = params.get(key);
content.append((i == 0 ? "" : "&") + key + "=" + value);
}
return content.toString();
}
/**
* 私鑰簽名
*
* @param data 待簽名的明文字元串
* @param privateKey RSA私鑰字元串
* @return RSA私鑰簽名後的經過Base64編碼的字元串
* @throws Exception
*/
@SuppressWarnings("unused")
private static String sign(String data, String privateKey,String charset){
try {
PrivateKey priKey =getPrivateKey(privateKey);
Signature signature = Signature.getInstance(SIGN_SHA256RSA_ALGORITHMS);
signature.initSign(priKey);
if (StringUtils.isEmpty(charset)) {
signature.update(data.getBytes());
} else {
signature.update(data.getBytes(charset));
}
return new String(Base64.encodeBase64(signature.sign()));
// return Base64.getEncoder().encodeToString(signature.sign());
} catch (Exception e) {
throw new RuntimeException("簽名字元串[" + data + " ]時遇到異常", e);
}
}
/**
* 公鑰 驗簽
* @param srcData 原始字元串
* @param publicKey 公鑰
* @param sign 簽名
* @return 是否驗簽通過
*/
@SuppressWarnings("unused")
private static boolean verify(String data, String publicKey, String sign,String charset){
try {
PublicKey pubKey = getPublicKey(publicKey);
Signature signature = Signature.getInstance(SIGN_SHA256RSA_ALGORITHMS);
signature.initVerify(pubKey);
if (StringUtils.isEmpty(charset)) {
signature.update(data.getBytes());
} else {
signature.update(data.getBytes(charset));
}
return signature.verify(Base64.decodeBase64(sign.getBytes()));
} catch (Exception e) {
throw new RuntimeException("驗簽字元串[" + data + " ]時遇到異常", e);
}
}
/**
*
* @Description: 公鑰驗簽
* @param:@param params
* @param:@param publicKey
* @param:@param charset
* @param:@param sign
* @param:@return
* @return:boolean
* @throws:
* @version: v1.0.0
* @author: Administrator
* @date: 2019年11月12日 下午2:12:38
*/
public static boolean rsa256Check(Map<String, String> params, String publicKey, String charset,String sign) {
String content = getSignCheckContent(params);
return verify(content, sign, publicKey, charset);
}
}