使用JAVA默認和bouncycastle實現,
訪問連接
https://github.com/squall8234/squallSecure
主要源碼如下:
package squall.secure;
import java.security.Key;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
/**
* 加密解密驗籤工具類,內置了支持JCE和BC
*
* @author squall
*
*/
public class SecureUtil {
/**
* 空構造後續必須SET transformation
*/
public SecureUtil() {
}
/**
*
* @param transformation
*/
public SecureUtil(String transformation) {
setTransformation(transformation);;
}
/**
* 轉換格式 算法/模式/填充方式,如果只填入算法則根據當前Provider此算法的默認模式和填充實現 如
* "RSA/ECB/Pkcs1padding",只填算法如"RSA"
*/
private String transformation;
/*
* 懶得再次設置,直接從transformation從獲取
*/
private String algorithm;
/**
* 設置使用的加密算法的Provider,注意此處目前如果是默認使用BouncyCastle,
* 傳遞BouncyCastleProvider.PROVIDER_NAME 不設置默認JCE現實
*/
private String cipherProvider;
/**
* 設置使用的加密使用的祕鑰的Provider, 不設置默認JCE現實
*/
private String keyProvider;
static {
/* 注入BouncyCastleProvider */
Security.addProvider(new BouncyCastleProvider());
}
/**
* 使用私鑰對數據進行加密
*
* @param privateKey 私鑰的對象
* @param data 待加密數據
* @return 加密後的數據
* @throws Exception 太多了,如果以後需要有特殊處理的實現,會在內部進行處理以容錯
*/
public byte[] encryptByPrivateKey(PrivateKey privateKey, byte[] data) throws Exception {
Cipher cipher = null;
if (cipherProvider != null && !"".equals(cipherProvider)) {
cipher = Cipher.getInstance(transformation, cipherProvider);
} else {
cipher = Cipher.getInstance(transformation);
}
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
return cipher.doFinal(data);
}
/**
* 使用私鑰對數據進行解密
*
* @param privateKey 私鑰的對象
* @param data 待解密數據
* @return 解密後的數據
* @throws Exception 太多了,如果以後需要有特殊處理的實現,會在內部進行處理以容錯
*/
public byte[] decryptByPrivateKey(PrivateKey privateKey, byte[] data) throws Exception {
Cipher cipher = null;
if (cipherProvider != null && !"".equals(cipherProvider)) {
cipher = Cipher.getInstance(transformation, cipherProvider);
} else {
cipher = Cipher.getInstance(transformation);
}
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(data);
}
/**
* 使用公鑰對數據進行加密
*
* @param publicKey 公鑰的對象
* @param data 待加密數據
* @return 加密後的數據
* @throws Exception 太多了,如果以後需要有特殊處理的實現,會在內部進行處理以容錯
*/
public byte[] encryptByPublicKey(PublicKey publicKey, byte[] data) throws Exception {
Cipher cipher = null;
if (cipherProvider != null && !"".equals(cipherProvider)) {
cipher = Cipher.getInstance(transformation, cipherProvider);
} else {
cipher = Cipher.getInstance(transformation);
}
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(data);
}
/**
* 使用公鑰對數據進行解密
*
* @param publicKey 公鑰的對象
* @param data 待解密數據
* @return 解密後的數據
* @throws Exception 太多了,如果以後需要有特殊處理的實現,會在內部進行處理以容錯
*/
public byte[] decryptByPublicKey(PublicKey publicKey, byte[] data) throws Exception {
Cipher cipher = null;
if (cipherProvider != null && !"".equals(cipherProvider)) {
cipher = Cipher.getInstance(transformation, cipherProvider);
} else {
cipher = Cipher.getInstance(transformation);
}
cipher.init(Cipher.DECRYPT_MODE, publicKey);
return cipher.doFinal(data);
}
/**
* 使用祕鑰的字節數組對數據進行加密,注意此處的數據應該能用於構建PKCS8EncodedKeySpec對象
*
* @param keyData 私鑰的數據
* @param data 待加密數據
* @return 加密後的數據
* @throws Exception 太多了,如果以後需要有特殊處理的實現,會在內部進行處理以容錯
*/
public byte[] encryptByPrivateKey(byte[] keyData, byte[] data) throws Exception {
PrivateKey privateKey = getPrivateKeyByData(keyData);
return encryptByPrivateKey(privateKey, data);
}
/**
* 使用祕鑰的字節數組對數據進行解密,注意此處的數據應該能用於構建PKCS8EncodedKeySpec對象
*
* @param keyData 私鑰的數據
* @param data 待解密數據
* @return 加密後的數據
* @throws Exception 太多了,如果以後需要有特殊處理的實現,會在內部進行處理以容錯
*/
public byte[] decryptByPrivateKey(byte[] keyData, byte[] data) throws Exception {
PrivateKey privateKey = getPrivateKeyByData(keyData);
return decryptByPrivateKey(privateKey, data);
}
/**
* 使用公鑰的字節數組對數據進行加密,注意此處的數據應該能用於構建X509EncodedKeySpec對象
*
* @param keyData 公鑰的數據
* @param data 待加密的數據
* @return 加密後的數據
* @throws Exception 太多了,如果以後需要有特殊處理的實現,會在內部進行處理以容錯
*/
public byte[] encryptByPublicKey(byte[] keyData, byte[] data) throws Exception {
PublicKey publicKey = getPublicKeyByData(keyData);
return encryptByPublicKey(publicKey, data);
}
/**
* 使用公鑰的字節數組對數據進行解密,注意此處的數據應該能用於構建X509EncodedKeySpec對象
*
* @param keyData 公鑰的數據
* @param data 待解密的數據
* @return 解密後的數據
* @throws Exception 太多了,如果以後需要有特殊處理的實現,會在內部進行處理以容錯
*/
public byte[] decryptByPublicKey(byte[] keyData, byte[] data) throws Exception {
PublicKey publicKey = getPublicKeyByData(keyData);
return decryptByPublicKey(publicKey, data);
}
/**
* 使用祕鑰的字節數組的BASE64編碼數據對數據進行加密,注意此處的keyDataStr decodeBase64後的
* 數據應該能用於構建PKCS8EncodedKeySpec對象
*
* @param keyDataStr 私鑰的數據的BASE64編碼
* @param data 待加密數據BASE64編碼
* @return 加密後的數據BASE64編碼
* @throws Exception 太多了,如果以後需要有特殊處理的實現,會在內部進行處理以容錯
*/
public String encryptByPrivateKey(String keyDataStr, String dataStr) throws Exception {
byte[] keyData = Base64.decodeBase64(keyDataStr);
byte[] data = Base64.decodeBase64(dataStr);
return Base64.encodeBase64String(encryptByPrivateKey(keyData, data));
}
/**
* 使用祕鑰的字節數組的BASE64編碼數據對數據進行解密,注意此處的keyDataStr decodeBase64後的
* 數據應該能用於構建PKCS8EncodedKeySpec對象
*
* @param keyDataStr 私鑰的數據的BASE64編碼
* @param data 待解密數據BASE64編碼
* @return 解密後的數據BASE64編碼
* @throws Exception 太多了,如果以後需要有特殊處理的實現,會在內部進行處理以容錯
*/
public String decryptByPrivateKey(String keyDataStr, String dataStr) throws Exception {
byte[] keyData = Base64.decodeBase64(keyDataStr);
byte[] data = Base64.decodeBase64(dataStr);
return Base64.encodeBase64String(decryptByPrivateKey(keyData, data));
}
/**
* 使用公鑰的字節數組的BASE64編碼數據對數據進行加密,注意此處的keyDataStr decodeBase64後的
* 數據應該能用於構建X509EncodedKeySpec對象
*
* @param keyDataStr 公鑰的數據的BASE64編碼
* @param data 待加密數據BASE64編碼
* @return 加密後的數據BASE64編碼
* @throws Exception 太多了,如果以後需要有特殊處理的實現,會在內部進行處理以容錯
*/
public String encryptByPublicKey(String keyDataStr, String dataStr) throws Exception {
byte[] keyData = Base64.decodeBase64(keyDataStr);
byte[] data = Base64.decodeBase64(dataStr);
return Base64.encodeBase64String(encryptByPublicKey(keyData, data));
}
/**
* 使用公鑰的字節數組的BASE64編碼數據對數據進行解密,注意此處的keyDataStr decodeBase64後的
* 數據應該能用於構建X509EncodedKeySpec對象
*
* @param keyDataStr 公鑰的數據的BASE64編碼
* @param data 待解密數據BASE64編碼
* @return 加密後的數據BASE64編碼
* @throws Exception 太多了,如果以後需要有特殊處理的實現,會在內部進行處理以容錯
*/
public String decryptByPublicKey(String keyDataStr, String dataStr) throws Exception {
byte[] keyData = Base64.decodeBase64(keyDataStr);
byte[] data = Base64.decodeBase64(dataStr);
return Base64.encodeBase64String(decryptByPublicKey(keyData, data));
}
/**
* 對稱加密算法加密
*
* @param key 對稱祕鑰對象
* @param data 待加密數據
* @param ivData iv的數據,ECB模式則不傳
* @return 加密後的數據
* @throws Exception 太多了,如果以後需要有特殊處理的實現,會在內部進行處理以容錯
*/
public byte[] encryptByKey(Key key, byte[] data, byte[]... ivData) throws Exception {
Cipher cipher = null;
if (cipherProvider != null && !"".equals(cipherProvider)) {
cipher = Cipher.getInstance(transformation, cipherProvider);
} else {
cipher = Cipher.getInstance(transformation);
}
if (ivData.length != 0) {
IvParameterSpec iv = new IvParameterSpec(ivData[0]);
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
} else {
cipher.init(Cipher.ENCRYPT_MODE, key);
}
return cipher.doFinal(data);
}
/**
* 對稱加密算法解密
*
* @param key 對稱祕鑰對象
* @param data 待解密數據
* @param ivData iv的數據,ECB模式則不傳
* @return 解密後的數據
* @throws Exception 太多了,如果以後需要有特殊處理的實現,會在內部進行處理以容錯
*/
public byte[] decryptByKey(Key key, byte[] data, byte[]... ivData) throws Exception {
Cipher cipher = null;
if (cipherProvider != null && !"".equals(cipherProvider)) {
cipher = Cipher.getInstance(transformation, cipherProvider);
} else {
cipher = Cipher.getInstance(transformation);
}
if (ivData.length != 0) {
IvParameterSpec iv = new IvParameterSpec(ivData[0]);
cipher.init(Cipher.DECRYPT_MODE, key, iv);
} else {
cipher.init(Cipher.DECRYPT_MODE, key);
}
return cipher.doFinal(data);
}
/**
* 對稱加密算法加密
*
* @param keyData 對稱祕鑰字節數組,用於構造SecretKey
* @param data 待加密數據
* @param ivData iv的數據,ECB模式則不傳
* @return 加密後的數據
* @throws Exception 太多了,如果以後需要有特殊處理的實現,會在內部進行處理以容錯
*/
public byte[] encryptByKey(byte[] keyData, byte[] data, byte[]... ivData) throws Exception {
SecretKey key = new SecretKeySpec(keyData, algorithm);
if(ivData.length == 0)
return encryptByKey(key, data);
else
return encryptByKey(key, data, ivData);
}
/**
* 對稱加密算法解密
*
* @param keyData 對稱祕鑰字節數組,用於構造SecretKey
* @param data 待解密數據
* @param ivData iv的數據,ECB模式則不傳
* @return 解密後的數據
* @throws Exception 太多了,如果以後需要有特殊處理的實現,會在內部進行處理以容錯
*/
public byte[] decryptByKey(byte[] keyData, byte[] data, byte[]... ivData) throws Exception {
SecretKey key = new SecretKeySpec(keyData, algorithm);
if(ivData.length == 0)
return decryptByKey(key, data);
else
return decryptByKey(key, data, ivData);
}
/**
* 對稱加密算法加密
*
* @param keyDataStr 對稱祕鑰字節數組BASE64編碼,用於構造SecretKey
* @param data 待加密數據BASE64編碼
* @param ivDataStr iv數據的BASE64編碼
* @return 加密後的數據BASE64編碼
* @throws Exception 太多了,如果以後需要有特殊處理的實現,會在內部進行處理以容錯
*/
public String encryptByKey(String keyDataStr, String dataStr, String... ivDataStr) throws Exception {
byte[] keyData = Base64.decodeBase64(keyDataStr);
byte[] data = Base64.decodeBase64(dataStr);
byte[] ivData = null;
if (ivDataStr != null) {
ivData = Base64.decodeBase64(ivDataStr[0]);
}
return Base64.encodeBase64String(encryptByKey(keyData, data, ivData));
}
/**
* 對稱解密算法解密
*
* @param keyDataStr 對稱祕鑰字節數組BASE編碼,用於構造SecretKey
* @param dataStr 待解密數據BASE編碼
* @param ivDataStr iv數據的BASE64編碼
* @return 解密後的數據BASE64編碼
* @throws Exception 太多了,如果以後需要有特殊處理的實現,會在內部進行處理以容錯
*/
public String decryptByKey(String keyDataStr, String dataStr, String... ivDataStr) throws Exception {
byte[] keyData = Base64.decodeBase64(keyDataStr);
byte[] data = Base64.decodeBase64(dataStr);
byte[] ivData = null;
if (ivDataStr != null) {
ivData = Base64.decodeBase64(ivDataStr[0]);
}
return Base64.encodeBase64String(decryptByKey(keyData, data, ivData));
}
/**
* 使用私鑰簽名
* @param signAlgorithm 簽名算法
* @param key 私鑰對象
* @param data 待簽名數據
* @return 簽名後的數據
* @throws NoSuchAlgorithmException
*/
public byte[] signByPrivateKey(String signAlgorithm, PrivateKey key, byte[] data) throws Exception {
Signature sig = Signature.getInstance(signAlgorithm);
sig.initSign(key);
sig.update(data);
return sig.sign();
}
/**
* 使用公鑰驗籤
* @param signAlgorithm 簽名算法
* @param key 公鑰對象
* @param data 原始數據
* @param signData 需要驗證的簽名數據
* @return true表示驗證成功,false表示驗證失敗
*/
public boolean verifyByPublicKey(String signAlgorithm, PublicKey key, byte[] data, byte[] signData) throws Exception{
Signature sig = Signature.getInstance(signAlgorithm);
sig.initVerify(key);
sig.update(data);
return sig.verify(signData);
}
/**
* 使用私鑰字符數組簽名
* @param signAlgorithm 簽名算法
* @param keyData 私鑰字符數組符合PKCS8EncodedKeySpec
* @param data 待簽名數據
* @return 簽名後的數據
* @throws NoSuchAlgorithmException
*/
public byte[] signByPrivateKey(String signAlgorithm, byte[] keyData, byte[] data) throws Exception {
PrivateKey key = getPrivateKeyByData(keyData);
return signByPrivateKey(signAlgorithm,key,data);
}
/**
* 使用公鑰驗籤
* @param signAlgorithm 簽名算法
* @param key 公鑰對象
* @param data 原始數據
* @param signData 需要驗證的簽名數據
* @return true表示驗證成功,false表示驗證失敗
*/
public boolean verifyByPublicKey(String signAlgorithm, byte[] keyData, byte[] data, byte[] signData) throws Exception{
PublicKey key = getPublicKeyByData(keyData);
return verifyByPublicKey(signAlgorithm,key,data,signData);
}
/**
* 設置轉換格式 算法/模式/填充方式,如果只填入算法則根據當前Provider此算法的默認模式和填充實現
*
* @param transformation 如"RSA/ECB/Pkcs1padding",只填算法如"RSA"
*/
public void setTransformation(String transformation) {
int idx = transformation.indexOf('/');
if (idx == -1) {
this.algorithm = transformation;
} else {
this.algorithm = transformation.substring(0, idx);
}
this.transformation = transformation;
}
/**
* 使用私鑰的字節數組構造私鑰,需要符合PKCS8EncodedKeySpec格式
* @param keyData 私鑰的字節數組
* @return 私鑰對象
* @throws Exception 一堆異常可能,如果要處理以後補充
*/
public PrivateKey getPrivateKeyByData(byte[] keyData) throws Exception {
KeyFactory keyFactory = null;
if (keyProvider != null && !"".equals(keyProvider)) {
keyFactory = KeyFactory.getInstance(algorithm, keyProvider);
} else {
keyFactory = KeyFactory.getInstance(algorithm);
}
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyData);
return keyFactory.generatePrivate(pkcs8KeySpec);
}
/**
* 使用私鑰的字節數組構造私鑰,需要符合X509EncodedKeySpec格式
* @param keyData 私鑰的字節數組
* @return 私鑰對象
* @throws Exception 一堆異常可能,如果要處理以後補充
*/
public PublicKey getPublicKeyByData(byte[] keyData) throws Exception{
KeyFactory keyFactory = null;
if (keyProvider != null && !"".equals(keyProvider)) {
keyFactory = KeyFactory.getInstance(algorithm, keyProvider);
} else {
keyFactory = KeyFactory.getInstance(algorithm);
}
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyData);
return keyFactory.generatePublic(x509KeySpec);
}
/**
* 設置加解密使用的Provider,如果不設置默認JCE,JCE沒有的話會嘗試BC
*
* @param cipherProvider
*/
public void setCipherProvider(String cipherProvider) {
this.cipherProvider = cipherProvider;
}
/**
* 設置祕鑰使用的Provider,如果不設置默認JCE
*
* @param keyProvider
*/
public void setKeyProvider(String keyProvider) {
this.keyProvider = keyProvider;
}
}
測試類代碼如下:
import java.io.UnsupportedEncodingException;
import java.util.UUID;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import squall.secure.SecureUtil;
public class MyTest {
public static void main(String[] args) throws Exception {
byte[] messageByte = "你好啊".getBytes("UTF-8");
System.out.println(Base64.encodeBase64String(messageByte));
/*生成隨機祕鑰*/
String key = UUID.randomUUID().toString().replaceAll("-", "").toLowerCase();
System.out.println(key);
/*獲得隨機祕鑰byte[]*/
byte[] aesKey = Hex.decodeHex(key);
byte[] privteKey = Base64.decodeBase64("MIICXAIBAAKBgQCzQfNPqLEjsfaXEu3qlKYJ9uVkFtPy9Ryl/Flxo9Kw/88LUDR/" +
"S9g2mnDjIfaGCxSVJb4KCDMxVOy024HR521PtaKD4SVAKupB0mnDDt6DguZ39ziH" +
"mSvY+fHJm8ic+3a/JQWqZADinEz//b5uepYTxE5OIQs0mmlkKVMFkLgI4QIDAQAB" +
"AoGAIbDkB5VHkdNpatSKddvxZw8J5ylpNZE/DK1krDijqVOy+MfezgwVu5GEZRQl" +
"juT3Pd8FnEIVSRDSml1lRWvPPepSXEsjpo8hJt9nFCTL+hYmu1dFspxxXNueNiHV" +
"Y9n1Qn/qnjdsGKY1mSBScY/x5LI3NiVliQRJkmDzGU+eUwkCQQDzS6DbY8VYY6fp" +
"8wcMvEtZmZ02l3b2aKQ5U0K6CF/o6+ZNMXaNkWtBXeNtV4+cBNeCG6l4Gmy+w6rC" +
"O0nw4mf9AkEAvJ5D35E/aDbQRBlX0wkwKtzc9JZCkKkjK4cemZnLtlrpMiwNI1aI" +
"9nuHJKi3BPyG5mjhZbPNy5xw44td1aZ/tQJBAK554x7Smxj7RtUA42Jfuo3EGzmm" +
"P7sQag1uR2EQVm+8lQlw2ntF+SwEf+/PJn8V/dMhsVQfZzMbMV9fk3Q7eaUCQHub" +
"6HUqVfhw+5m1VhXqTpO4fGEZ2/O7tF3BRi95V8Rg3bRQpCeFfWqy14URwCdXavyy" +
"vQwOgo6uLlkgq1TpsYUCQHJnc7n+uCUUN9L7K5mjnDDrl0dZLgZVuXYmW/RzTwBk" +
"SdDMSXlHuvnOdqW7BiG30EkeWXg7PlP7f3u6nJQ4dc8=");
SecureUtil aesUtil = new SecureUtil("AES/CTR/PKCS7Padding");
//aesUtil.setTransformation("AES/CTR/PKCS7Padding");
byte[] iv = Hex.decodeHex("12121212121212121212121212121212");
/*對稱加密*/
byte[] messM = aesUtil.encryptByKey(aesKey, messageByte, iv);
System.out.println(Base64.encodeBase64String(messM));
SecureUtil rsaUtil = new SecureUtil("RSA/ECB/PKCS1Padding");
//rsaUtil.setTransformation("RSA/ECB/PKCS1Padding");
/*加密對稱祕鑰*/
byte[] aesMkey = rsaUtil.encryptByPrivateKey(privteKey, aesKey);
/*生成簽名*/
byte[] signData = rsaUtil.signByPrivateKey("SHA1withRSA", privteKey, messageByte);
byte[] publicKey = Base64.decodeBase64("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCzQfNPqLEjsfaXEu3qlKYJ9uVk" +
"FtPy9Ryl/Flxo9Kw/88LUDR/S9g2mnDjIfaGCxSVJb4KCDMxVOy024HR521PtaKD" +
"4SVAKupB0mnDDt6DguZ39ziHmSvY+fHJm8ic+3a/JQWqZADinEz//b5uepYTxE5O" +
"IQs0mmlkKVMFkLgI4QIDAQAB");
/*解密對稱祕鑰*/
byte[] aesMMkey = rsaUtil.decryptByPublicKey(publicKey, aesMkey);
System.out.println(Hex.encodeHex(aesMMkey));
/*對稱祕鑰解密報文*/
byte[] message = aesUtil.decryptByKey(aesMMkey, messM, iv);
System.out.println(Base64.encodeBase64String(message));
System.out.println(new String(message,"UTF-8"));
/*驗籤*/
System.out.println(rsaUtil.verifyByPublicKey("SHA1withRSA", publicKey, messageByte, signData));
}
}
如果轉載請全文轉載,標註出處。。。謝謝