RSA簽名驗籤通用類
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
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.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.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.crypto.Cipher;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RsaUtils {
private static final Logger logger = LoggerFactory.getLogger(RsaUtils.class);
private static final int DEFAULT_BUFFER_SIZE = 8192;
/**
* RSA最大加密明文大小
*/
private static final int MAX_ENCRYPT_BLOCK = 117;
/**
* RSA最大解密密文大小
*/
private static final int MAX_DECRYPT_BLOCK = 128;
/**
*
* RSA2簽名
* @param content 待簽名的字符串
* @param privateKey rsa私鑰字符串
* @param charset 字符集編碼
* @return 簽名結果
*/
public static String rsaSign(String content, String privateKey, String charset) {
try {
PrivateKey priKey = getPrivateKeyFromPKCS8("RSA", new ByteArrayInputStream(privateKey.getBytes()));
Signature signature = Signature.getInstance("SHA256WithRSA");
signature.initSign(priKey);
if (StringUtils.isBlank(charset)) {
signature.update(content.getBytes());
} else {
signature.update(content.getBytes(charset));
}
byte[] signed = signature.sign();
return new String(Base64.encodeBase64(signed));
} catch (Exception e) {
logger.error("RSA簽名異常:{}", e.getMessage(), e);
return null;
}
}
/**
* RSA2驗籤
*
* @param content 被簽名的內容
* @param sign 簽名後的結果
* @param publicKey rsa公鑰
* @param charset 字符集編碼
* @return 驗簽結果
*/
public static boolean doCheck(String content, String sign, String publicKey, String charset) {
try {
PublicKey pubKey = getPublicKeyFromX509("RSA", new ByteArrayInputStream(publicKey.getBytes()));
Signature signature = Signature.getInstance("SHA256WithRSA");
signature.initVerify(pubKey);
signature.update(getContentBytes(content, charset));
return signature.verify(Base64.decodeBase64(sign.getBytes()));
} catch (Exception e) {
logger.error("RSA驗籤異常:{}", e.getMessage(), e);
return false;
}
}
/**
*
* RSA公鑰加密
* @param content 待加密的內容
* @param publicKey 公鑰
* @param charset 字符集編碼
* @return 密文
*/
public static String rsaEncrypt(String content, String publicKey, String charset) {
ByteArrayOutputStream out = null;
try {
PublicKey pubKey = getPublicKeyFromX509("RSA", new ByteArrayInputStream(publicKey.getBytes()));
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
int inputLen = content.getBytes().length;
out = new ByteArrayOutputStream();
int offset = 0;
byte[] cache;
int i = 0;
// 對數據分段加密
while (inputLen - offset > 0) {
if (inputLen - offset > MAX_ENCRYPT_BLOCK) {
cache = cipher.doFinal(content.getBytes(charset), offset, MAX_ENCRYPT_BLOCK);
} else {
cache = cipher.doFinal(content.getBytes(charset), offset, inputLen - offset);
}
out.write(cache, 0, cache.length);
i++;
offset = i * MAX_ENCRYPT_BLOCK;
}
byte[] encryptedData = out.toByteArray();
return Base64.encodeBase64String(encryptedData);
} catch (Exception e) {
logger.error("RSA公鑰加密異常:{}", e.getMessage(), e);
return null;
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {
logger.error("RSA公鑰加密IOException異常:{}", e.getMessage(), e);
}
}
}
}
/**
*
* RSA私鑰解密
* @param content 加密字符串
* @param privateKey 私鑰
* @param charset 字符集編碼
* @return 明文
*/
public static String rsaDecrypt(String content, String privateKey, String charset) {
ByteArrayOutputStream out = null;
try {
PrivateKey priKey = getPrivateKeyFromPKCS8("RSA", new ByteArrayInputStream(privateKey.getBytes()));
// RSA解密
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, priKey);
byte[] dataBytes = Base64.decodeBase64(content);
int inputLen = dataBytes.length;
out = new ByteArrayOutputStream();
int offset = 0;
byte[] cache;
int i = 0;
// 對數據分段解密
while (inputLen - offset > 0) {
if (inputLen - offset > MAX_DECRYPT_BLOCK) {
cache = cipher.doFinal(dataBytes, offset, MAX_DECRYPT_BLOCK);
} else {
cache = cipher.doFinal(dataBytes, offset, inputLen - offset);
}
out.write(cache, 0, cache.length);
i++;
offset = i * MAX_DECRYPT_BLOCK;
}
byte[] decryptedData = out.toByteArray();
// 解密後的內容
return new String(decryptedData, charset);
} catch (Exception e) {
logger.error("RSA私鑰解密異常:{}", e.getMessage(), e);
return null;
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {
logger.error("RSA私鑰解密IOException異常:{}", e.getMessage(), e);
}
}
}
}
/**
*
* 獲取私鑰對象
* @param algorithm 簽名方式
* @param ins 私鑰流
* @return
* @throws Exception
*/
private static PrivateKey getPrivateKeyFromPKCS8(String algorithm, InputStream ins) throws Exception {
if (ins == null || StringUtils.isEmpty(algorithm)) {
return null;
}
KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
byte[] encodedKey = readText(ins, "utf-8", true).getBytes();
encodedKey = Base64.decodeBase64(encodedKey);
return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encodedKey));
}
/**
*
* 獲取公鑰對象
* @param algorithm 簽名方式
* @param ins 公鑰流
* @return
* @throws NoSuchAlgorithmException
*/
private static PublicKey getPublicKeyFromX509(String algorithm, InputStream ins) {
try {
KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
StringWriter writer = new StringWriter();
io(new InputStreamReader(ins), writer, true, true);
byte[] encodedKey = writer.toString().getBytes();
// 先base64解碼
encodedKey = Base64.decodeBase64(encodedKey);
return keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
} catch (InvalidKeySpecException e) {
logger.error("獲取公鑰對象InvalidKeySpecException異常:{}", e.getMessage(), e);
} catch (NoSuchAlgorithmException e) {
logger.error("獲取公鑰對象NoSuchAlgorithmException異常:{}", e.getMessage(), e);
}
return null;
}
/**
*
* 生成RSA公、私鑰對
* @return 公私鑰對map
* @throws Exception
*/
public static Map<String, String> generateRSAKeyPairs() throws Exception {
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
keyPairGen.initialize(1024);
KeyPair keyPair = keyPairGen.generateKeyPair();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
Map<String, String> keyMap = new HashMap<String, String>(2);
keyMap.put("publicKey", Base64.encodeBase64String(publicKey.getEncoded()));
keyMap.put("privateKey", Base64.encodeBase64String(privateKey.getEncoded()));
return keyMap;
}
/**
*
* 獲取字符串對應編碼的字節
* @param content 字符串內容
* @param charset 字符集編碼
* @return
* @throws UnsupportedEncodingException
*/
private static byte[] getContentBytes(String content, String charset) throws UnsupportedEncodingException {
if (StringUtils.isEmpty(charset)) {
return content.getBytes();
}
return content.getBytes(charset);
}
/**
*
* 將指定輸入流的所有文本全部讀出到一個字符串中
* @param in 輸入流
* @param charset 字符集編碼
* @param closeIn 是否關閉流
* @return
* @throws IOException
*/
private static String readText(InputStream in, String charset, boolean closeIn) throws IOException {
Reader reader = charset == null ? new InputStreamReader(in) : new InputStreamReader(in, charset);
return readText(reader, closeIn);
}
/**
*
* 將指定<code>Reader</code>的所有文本全部讀出到一個字符串中
* @param in 輸入流
* @param closeIn 是否關閉流
* @return
* @throws IOException
*/
private static String readText(Reader in, boolean closeIn) throws IOException {
StringWriter out = new StringWriter();
io(in, out, closeIn, true);
return out.toString();
}
/**
*
* 從輸入流讀取內容,寫入到輸出流中
* @param in 輸入流
* @param out 輸出流
* @param closeIn 是否關閉流
* @param closeOut 是否關閉流
* @throws IOException
*/
private static void io(Reader in, Writer out, boolean closeIn, boolean closeOut) {
int bufferSize = DEFAULT_BUFFER_SIZE >> 1;
char[] buffer = new char[bufferSize];
int amount;
try {
while ((amount = in.read(buffer)) >= 0) {
out.write(buffer, 0, amount);
}
out.flush();
} catch (Exception e) {
logger.error("從輸入流讀取內容,寫入到輸出流中異常:{}", e.getMessage(), e);
} finally {
if (closeIn) {
try {
in.close();
} catch (IOException e) {
logger.error("從輸入流讀取內容,寫入到輸出流中異常:{}", e.getMessage(), e);
}
}
if (closeOut) {
try {
out.close();
} catch (IOException e) {
logger.error("從輸入流讀取內容,寫入到輸出流中異常:{}", e.getMessage(), e);
}
}
}
}
/**
*
* 除去數組中的空值和簽名參數
* @param params 簽名參數對象
* @return 去掉空值與簽名參數後的新簽名參數組
*/
public static Map<String, String> paraFilter(Map<String, String> params) {
Map<String, String> result = new HashMap<String, String>();
if (params == null || params.size() <= 0) {
return result;
}
for (String key : params.keySet()) {
String value = params.get(key);
if (value == null || value.equals("") || key.equalsIgnoreCase("sign") || key.equalsIgnoreCase("sign_type")) {
continue;
}
result.put(key, value);
}
return result;
}
/**
*
* 把數組所有元素排序,並按照“參數=參數值”的模式用“&”字符拼接成字符串
* @param params 需要排序並參與字符拼接的參數對象
* @return 拼接後字符串
*/
public static String createLinkString(Map<String, String> params) {
List<String> keys = new ArrayList<String>(params.keySet());
Collections.sort(keys);
String prestr = "";
for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
String value = params.get(key);
if (i == keys.size() - 1) {
prestr = prestr + key + "=" + value;
} else {
prestr = prestr + key + "=" + value + "&";
}
}
return prestr;
}
}