RSA
RSA是一種非對稱加密的算法,是很早之前就出來的,聽說是法國的發明。
算法的核心思想是:加解密 、 驗籤
加解密是爲了數據傳遞的安全性,驗籤是爲了數據傳遞過程中防止被篡改
1、加解密
說明:加解密
-------------私鑰加密,公鑰解密; 公鑰加密,私鑰解密;---------------
解釋:RSA算法,會生成一對密鑰,包括私鑰和公鑰;私鑰和公鑰一般甲方和乙方只保留一個,甲方擁有公鑰,乙方就持有私鑰, 反之亦然。
具體實現過程:設:甲方持有私鑰,乙方持有公鑰。
甲方先將數據用私鑰加密之後,通過互聯網傳送給乙方。(加密後的數據一般是base64格式)。乙方收到數據後,用公鑰解密,得到想要的數據。。乙方得到數據後,經過處理,把處理後的數據經過公鑰加密,通過互聯網傳遞給甲方,甲方用私鑰解密,得到數據。。這樣,就實現了數據傳遞的安全性,因爲即便黑客得到的傳遞的數據,也不過是加密的數據,沒有解密的密鑰,是得不到有用的數據的。但是問題來了:
黑客得不到數據,氣急敗壞,將錯誤的數據發送給甲方或者乙方,怎麼辦,甲方或者乙方還以爲是正常的數據,正常處理了,這樣不是導致數據錯誤了嗎?
這時候,驗籤功能很好的解決了這個問題
2、簽名 、驗證簽名
說明:驗籤
-----------私鑰簽名,公鑰驗籤; 公鑰簽名,私鑰驗籤 -------------------------
解釋:簽名和驗證簽名 通俗易懂,就是驗證傳過來的數據是不是原始的,沒有被改動過的。。具體的原理不懂,實現還是明白的
具體實現:設:甲方持有私鑰,乙方持有公鑰
甲方通過 (私鑰 + 原始數據 ) 得到 簽名 sign , 之後,把 加密數據 、sign 發送給乙方。。。乙方收到之後,解密數據之後,得到原始數據,通過(公鑰 + 原始數據 + sign) 判斷數據是否被改動過。
true 表示驗籤通過 ,false 表示失敗
3、code
(1)簽名和驗籤
package com.zd.test;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
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.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
public class JavaMD5RSASign {
private static String src = "i look";
public static void main(String[] args) {
MD5RSASign();
}
public static void MD5RSASign(){
try {
// 生成一對密鑰
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); //獲取密鑰生成器實例
keyPairGenerator.initialize(512); // 初始化長度
KeyPair keyPair = keyPairGenerator.generateKeyPair();
RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();//生成公鑰
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate(); // 生成私鑰
//用私鑰進行簽名
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded()); //私鑰轉換成pkcs8格式
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec); // 用key工廠對象生成私鑰
Signature signature = Signature.getInstance("MD5withRSA"); // md5 RSA簽名對象
signature.initSign(privateKey); //初始化簽名
signature.update(src.getBytes());
byte[] result = signature.sign(); //對消息進行簽名
System.out.println("簽名結果:"+result);
//用公鑰進行驗證
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(rsaPublicKey.getEncoded());
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
signature.initVerify(publicKey);
signature.update(src.getBytes());
boolean verify = signature.verify(result);
System.out.println("驗證結果:"+verify);
} catch (Exception e) {
e.printStackTrace();
}
}
}
(2)RSAUtil.java 工具類
package com.zd.util;
import java.io.ByteArrayOutputStream;
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.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
/**
* Created by huangxp on 2017/8/15 0015.
*/
import javax.crypto.Cipher;
public class RsaUtil {
/**
* 定義加密方式
*/
private final static String KEY_RSA = "RSA";
public static final String ECB_PKCS1_PADDING = "RSA/ECB/PKCS1Padding";//加密填充方式
/**
* 定義簽名算法
*/
private final static String KEY_RSA_SIGNATURE = "MD5withRSA";
/**
* 定義公鑰算法
*/
private final static String KEY_RSA_PUBLICKEY = "RSAPublicKey";
/**
* 定義私鑰算法
*/
private final static String KEY_RSA_PRIVATEKEY = "RSAPrivateKey";
/**
* RSA最大加密明文大小
*/
private static final int MAX_ENCRYPT_BLOCK = 117;
/**
* RSA最大解密密文大小
*/
private static final int MAX_DECRYPT_BLOCK = 128;
/**
* RSA最大解密密文大小
*/
private static final int MAX_DECRYPT_BLOCK_256 = 256;
private RsaUtil() {
}
/**
* 創建密鑰
*
* @return
*/
public static Map<String, Object> generateKey() {
Map<String, Object> map = null;
try {
KeyPairGenerator generator = KeyPairGenerator.getInstance(KEY_RSA);
generator.initialize(1024);
KeyPair keyPair = generator.generateKeyPair();
// 公鑰
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
// 私鑰
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
// 將密鑰封裝爲map
map = new HashMap<String, Object>();
map.put(KEY_RSA_PUBLICKEY, publicKey);
map.put(KEY_RSA_PRIVATEKEY, privateKey);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
return map;
}
/**
* 用私鑰對信息生成數字簽名
*
* @param data 加密數據
* @param privateKey 私鑰
* @return
*/
public static String sign(String privateKey, byte[] data) {
String str = "";
try {
// 解密由base64編碼的私鑰
byte[] bytes = decryptBase64(privateKey);
// 構造PKCS8EncodedKeySpec對象
PKCS8EncodedKeySpec pkcs = new PKCS8EncodedKeySpec(bytes);
// 指定的加密算法
KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
// 取私鑰對象
PrivateKey key = factory.generatePrivate(pkcs);
// 用私鑰對信息生成數字簽名
Signature signature = Signature.getInstance(KEY_RSA_SIGNATURE);
signature.initSign(key);
signature.update(data);
str = encryptBase64(signature.sign());
} catch (Exception e) {
throw new RuntimeException(e);
}
return str;
}
/**
* 用私鑰對信息生成數字簽名
*
* @param privateKey
* @param dataStr
* @return
*/
public static String sign(String privateKey, String dataStr) {
String str = "";
try {
byte[] data = dataStr.getBytes("UTF-8");
return sign(privateKey, data);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static String signPublicKey(String publicKey, String dataStr) {
String str = "";
try {
byte[] data = dataStr.getBytes("UTF-8");
return signPublicKey(publicKey, data);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 用私鑰對信息生成數字簽名
*
* @param data 加密數據
* @param publicKey 私鑰
* @return
*/
public static String signPublicKey(String publicKey, byte[] data) {
String str = "";
try {
// 對公鑰解密
byte[] bytes = decryptBase64(publicKey);
// 取得公鑰
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
PublicKey key = factory.generatePublic(keySpec);
} catch (Exception e) {
throw new RuntimeException(e);
}
return str;
}
/**
* 校驗數字簽名
*
* @param data 加密數據
* @param publicKey 公鑰
* @param sign 數字簽名
* @return 校驗成功返回true,失敗返回false
*/
public static boolean verify(String publicKey, byte[] data, String sign) {
boolean flag = false;
try {
// 解密由base64編碼的公鑰
byte[] bytes = decryptBase64(publicKey);
// 構造X509EncodedKeySpec對象
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
// 指定的加密算法
KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
// 取公鑰對象
PublicKey key = factory.generatePublic(keySpec);
// 用公鑰驗證數字簽名
Signature signature = Signature.getInstance(KEY_RSA_SIGNATURE);
signature.initVerify(key);
signature.update(data);
flag = signature.verify(decryptBase64(sign));
} catch (Exception e) {
throw new RuntimeException(e);
}
return flag;
}
public static boolean verify(String publicKey, String dataStr, String sign) {
try {
byte[] data = dataStr.getBytes("UTF-8");
return verify(publicKey, data, sign);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 公鑰加密
*
* @param key 公鑰
* @param data 待加密數據
* @return
*/
public static byte[] encryptByPublicKey(String key, byte[] data) {
byte[] result = null;
try {
// 獲取公鑰字符串時,進行了encryptBase64操作,因此此處需對公鑰鑰解密
byte[] bytes = decryptBase64(key);
// 取得公鑰
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
PublicKey publicKey = factory.generatePublic(keySpec);
// 對數據加密
Cipher cipher = Cipher.getInstance(factory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
int inputLen = data.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 對數據分段加密
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
} else {
cache = cipher.doFinal(data, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_ENCRYPT_BLOCK;
}
byte[] encryptedData = out.toByteArray();
out.close();
return encryptedData;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static String encryptByPublicKey(String key, String dataStr) {
try {
byte[] result = encryptByPublicKey(key, dataStr.getBytes("UTF-8"));
return encryptBase64(result);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
/**
* 私鑰解密
*
* @param data 加密數據
* @param key 私鑰
* @return
*/
public static byte[] decryptByPrivateKey(String key, byte[] data,int maxDecryptBlock) {
byte[] result = null;
try {
// 獲取私鑰字符串時,進行了encryptBase64操作,因此此處需對私鑰解密
byte[] bytes = decryptBase64(key);
// 取得私鑰
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
PrivateKey privateKey = factory.generatePrivate(keySpec);
// 對數據解密
Cipher cipher = Cipher.getInstance(ECB_PKCS1_PADDING);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
int inputLen = data.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 對數據分段解密
while (inputLen - offSet > 0) {
if (inputLen - offSet > maxDecryptBlock) {
cache = cipher
.doFinal(data, offSet, maxDecryptBlock);
} else {
cache = cipher
.doFinal(data, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * maxDecryptBlock;
}
byte[] decryptedData = out.toByteArray();
out.close();
return decryptedData;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static String decryptByPrivateKey256(String key, String dataStr) {
try {
byte[] result = decryptByPrivateKey(key, decryptBase64(dataStr),MAX_DECRYPT_BLOCK_256);
return new String(result);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
public static String decryptByPrivateKey(String key, String dataStr) {
try {
byte[] result = decryptByPrivateKey(key, decryptBase64(dataStr),MAX_DECRYPT_BLOCK);
return new String(result);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
/**
* 私鑰加密
*
* @param data 待加密數據
* @param key 私鑰
* @return
*/
public static byte[] encryptByPrivateKey(String key, byte[] data) {
byte[] result = null;
try {
byte[] bytes = decryptBase64(key);
// 取得私鑰
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
PrivateKey privateKey = factory.generatePrivate(keySpec);
// 對數據加密
Cipher cipher = Cipher.getInstance(ECB_PKCS1_PADDING);
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
int inputLen = data.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 對數據分段加密
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
} else {
cache = cipher.doFinal(data, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_ENCRYPT_BLOCK;
}
byte[] encryptedData = out.toByteArray();
out.close();
return encryptedData;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static String encryptByPrivateKey(String key, String dataStr) {
try {
byte[] result = encryptByPrivateKey(key, dataStr.getBytes("UTF-8"));
return encryptBase64(result).replace("\n","");
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
/**
* 公鑰鑰解密
*
* @param key 公鑰
* @param data 加密數據
* @return
*/
public static byte[] decryptByPublicKey(String key, byte[] data) {
byte[] result = null;
try {
// 對公鑰解密
byte[] bytes = decryptBase64(key);
// 取得公鑰
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
PublicKey publicKey = factory.generatePublic(keySpec);
// 對數據解密
Cipher cipher = Cipher.getInstance(factory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, publicKey);
int inputLen = data.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 對數據分段解密
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
cache = cipher
.doFinal(data, offSet, MAX_DECRYPT_BLOCK);
} else {
cache = cipher
.doFinal(data, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_DECRYPT_BLOCK;
}
byte[] decryptedData = out.toByteArray();
out.close();
return decryptedData;
//result = cipher.doFinal(data);
} catch (Exception e) {
throw new RuntimeException(e);
}
// return result;
}
public static String decryptByPublicKey(String key, String dataStr) {
try {
byte[] result = decryptByPublicKey(key, decryptBase64(dataStr));
return new String(result,"UTF-8");
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
/**
* 獲取公鑰
*
* @param map
* @return
*/
public static String getPublicKey(Map<String, Object> map) {
String str = "";
try {
Key key = (Key) map.get(KEY_RSA_PUBLICKEY);
str = encryptBase64(key.getEncoded());
} catch (Exception e) {
throw new RuntimeException(e);
}
return str;
}
/**
* 獲取私鑰
*
* @param map
* @return
*/
public static String getPrivateKey(Map<String, Object> map) {
String str = "";
try {
Key key = (Key) map.get(KEY_RSA_PRIVATEKEY);
str = encryptBase64(key.getEncoded());
} catch (Exception e) {
throw new RuntimeException(e);
}
return str;
}
/**
* BASE64 解密
*
* @param key 需要解密的字符串
* @return 字節數組
* @throws Exception
*/
public static byte[] decryptBase64(String key) {
// return javax.xml.bind.DatatypeConverter.parseBase64Binary(key);
// return Base64.decode(key, Base64.DEFAULT);
return Base64.getDecoder().decode(key);
}
/**
* BASE64 加密
*
* @param key 需要加密的字節數組
* @return 字符串
* @throws Exception
*/
public static String encryptBase64(byte[] key) {
return Base64.getEncoder().encodeToString(key);
}
}
總結:數據如果敏感,建議使用RSA加密,比較安全。。設置初始的字節爲1024很安全,聽說一般人破解不了。2048,賊安全
送給自己:人總要有點理想,就算沒有用,起碼算個信仰,這個信仰在一些時候總會莫名其妙的給你一股力量。堅持你走完最難的路。。即便感動不了別人,也能感動自己。。