一、對稱加密與非對稱加密
對稱加密:加密和解密使用的是同一個密鑰,加解密雙方必須使用同一個密鑰才能進行正常的溝通。
非對稱加密:需要兩個密鑰來進行加密和解密,公開密鑰(public key,簡稱公鑰)和私有密鑰(private key,簡稱私鑰) ,公鑰加密的信息只有私鑰才能解開,私鑰加密的信息只有公鑰才能解開。
需要注意的一點,這個公鑰和私鑰必須是一對的,如果用公鑰對數(shù)據(jù)進行加密,那么只有使用對應的私鑰才能解密,所以只要私鑰不泄露,那么我們的數(shù)據(jù)就是安全的。
常用的加密算法:
對稱加密:DES、3DES、TDEA、Blowfish、RC2、RC4、RC5、IDEA、SKIPJACK、AES。
非對稱加密:RSA、ECC(橢圓曲線加密算法)、Diffie-Hellman、El Gamal、DSA(數(shù)字簽名用)
Hash 算法:MD2、MD4、MD5、HAVAL、SHA-1、SHA256、SHA512、RipeMD、WHIRLPOOL、SHA3、HMAC
二、非對稱加密工作過程
甲乙雙方使用非對稱加密算法的方式進行數(shù)據(jù)傳輸
- 乙方生成一對密鑰(公鑰與私鑰),并將公鑰向甲方公開
- 甲方獲取到公鑰后,將需要傳輸?shù)臄?shù)據(jù)用公鑰進行加密發(fā)送給乙方
- 乙方獲取到甲方加密數(shù)據(jù)后,用私鑰進行解密
- 在數(shù)據(jù)傳輸過程中,即使數(shù)據(jù)被攻擊者截取并獲取了公鑰,攻擊者也無法破解密文,因為只有乙方的私鑰才能解密
三、非對稱加密中,究竟是公鑰加密還是私鑰加密?
- 對于加密:公鑰加密,私鑰加密。畢竟公鑰可以公開,但是私鑰只有你自已知道,你也同樣希望只有你自已才能解密
- 對于簽名:私鑰加密,公鑰解密。好比你的簽名只有你自已簽的才是真的,別人簽的都是假的。
四、RSA非對稱加密代碼示例
RSA 算法基于一個十分簡單的數(shù)論事實:將兩個大素數(shù)相乘十分容易,但是想要對其乘積進行因式分解卻極其困難,因此可以將乘積公開作為加密密鑰。
- 1、添加jar包
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.56</version>
</dependency>
- 2、RSAUtil.java
package com.kimeng.weipan.utils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Base64;
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.Security;
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.HashMap;
import java.util.Map;
import javax.crypto.Cipher;
/**
* @author: 會跳舞的機器人
* @date: 2017/9/18 15:00
* @description: RSA工具類
*/
public class RSAUtil {
/**
* 定義加密方式
*/
private final static String KEY_RSA = "RSA";
/**
* 定義簽名算法
*/
private final static String KEY_RSA_SIGNATURE = "MD5withRSA";
/**
* 定義公鑰算法
*/
private final static String KEY_RSA_PUBLICKEY = "RSAPublicKey";
/**
* 定義私鑰算法
*/
private final static String KEY_RSA_PRIVATEKEY = "RSAPrivateKey";
static {
Security.addProvider(new BouncyCastleProvider());
}
/**
* 初始化密鑰
*/
public static Map<String, Object> init() {
Map<String, Object> map = null;
try {
KeyPairGenerator generator = KeyPairGenerator.getInstance(KEY_RSA);
generator.initialize(2048);
KeyPair keyPair = generator.generateKeyPair();
// 公鑰
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
// 私鑰
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
// 將密鑰封裝為map
map = new HashMap<>();
map.put(KEY_RSA_PUBLICKEY, publicKey);
map.put(KEY_RSA_PRIVATEKEY, privateKey);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return map;
}
/**
* 公鑰加密
*
* @param data 待加密數(shù)據(jù)
* @param key 公鑰
*/
public static byte[] encryptByPublicKey(String data, String key) {
byte[] result = null;
try {
byte[] bytes = decryptBase64(key);
// 取得公鑰
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
PublicKey publicKey = factory.generatePublic(keySpec);
// 對數(shù)據(jù)加密
Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding", "BC");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encode = cipher.doFinal(data.getBytes());
// 再進行Base64加密
result = Base64.encode(encode);
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 私鑰解密
*
* @param data 加密數(shù)據(jù)
* @param key 私鑰
*/
public static String decryptByPrivateKey(byte[] data, String key) {
String result = null;
try {
// 對私鑰解密
byte[] bytes = decryptBase64(key);
// 取得私鑰
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
PrivateKey privateKey = factory.generatePrivate(keySpec);
// 對數(shù)據(jù)解密
Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding", "BC");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
// 先Base64解密
byte[] decoded = Base64.decode(data);
result = new String(cipher.doFinal(decoded));
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 獲取公鑰
*/
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) {
e.printStackTrace();
}
return str;
}
/**
* 獲取私鑰
*/
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) {
e.printStackTrace();
}
return str;
}
/**
* 用私鑰對信息生成數(shù)字簽名
*
* @param data 加密數(shù)據(jù)
* @param privateKey 私鑰
*/
public static String sign(byte[] data, String privateKey) {
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);
// 用私鑰對信息生成數(shù)字簽名
Signature signature = Signature.getInstance(KEY_RSA_SIGNATURE);
signature.initSign(key);
signature.update(data);
str = encryptBase64(signature.sign());
} catch (Exception e) {
e.printStackTrace();
}
return str;
}
/**
* 校驗數(shù)字簽名
*
* @param data 加密數(shù)據(jù)
* @param publicKey 公鑰
* @param sign 數(shù)字簽名
* @return 校驗成功返回true,失敗返回false
*/
public static boolean verify(byte[] data, String publicKey, 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);
// 用公鑰驗證數(shù)字簽名
Signature signature = Signature.getInstance(KEY_RSA_SIGNATURE);
signature.initVerify(key);
signature.update(data);
flag = signature.verify(decryptBase64(sign));
} catch (Exception e) {
e.printStackTrace();
}
return flag;
}
/**
* BASE64 解密
*
* @param key 需要解密的字符串
* @return 字節(jié)數(shù)組
*/
public static byte[] decryptBase64(String key) throws Exception {
return Base64.decode(key);
}
/**
* BASE64 加密
*
* @param key 需要加密的字節(jié)數(shù)組
* @return 字符串
*/
public static String encryptBase64(byte[] key) throws Exception {
return new String(Base64.encode(key));
}
public static void main(String[] args) throws Exception {
String publicKey = "";
String privateKey = "";
Map<String, Object> keyMap = RSAUtil.init();
publicKey = RSAUtil.getPublicKey(keyMap);
privateKey = RSAUtil.getPrivateKey(keyMap);
System.out.println("公鑰:\n\r" + publicKey);
System.out.println("私鑰:\n\r" + privateKey);
System.out.println("公鑰加密======私鑰解密");
String str = "會跳舞的機器人";
byte[] enStr = RSAUtil.encryptByPublicKey(str, publicKey);
String decStr = RSAUtil.decryptByPrivateKey(enStr, privateKey);
System.out.println("加密前:" + str + "\n\r解密后:" + decStr);
System.out.println("\n\r");
System.out.println("私鑰簽名======公鑰驗證");
String sign = RSAUtil.sign(str.getBytes(), privateKey);
System.out.println("簽名:\n\r" + sign);
boolean flag = RSAUtil.verify(str.getBytes(), publicKey, sign);
System.out.println("驗簽結果:\n\r" + flag);
}
}
輸出
公鑰:
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkmIH1vvK8A+EDak84WOuOrN2IgzlarfDu6vp4i/vv/4Edezr1J5kWGf9WpGx2lfpZPS80bN03nxeA1utRoktJvqu++oXkoU3oDLlm/MciTV2lpSiDf8BiZfZ298FKQsG7CKI1Tj9ii9MlHWCsIDHfEJBsQTYONgDSjM6yecfRu0Xg0ZCNklNNeDki60oFa20hiUdLthSopuCWmxAGQL7uuOwlj07xzBXGEJkh8ixGF9v+CDMQLLU6ezk8ZWnPsOwS7OiJZkndyw13NKx8PMmaHX+cOYL5b6Vi7UQ+yizpGejV36XuX0Zpxb2AZee/IZCRGt/cOg0QKmEcN5KeKG6qQIDAQAB
私鑰:
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCSYgfW+8rwD4QNqTzhY646s3YiDOVqt8O7q+niL++//gR17OvUnmRYZ/1akbHaV+lk9LzRs3TefF4DW61GiS0m+q776heShTegMuWb8xyJNXaWlKIN/wGJl9nb3wUpCwbsIojVOP2KL0yUdYKwgMd8QkGxBNg42ANKMzrJ5x9G7ReDRkI2SU014OSLrSgVrbSGJR0u2FKim4JabEAZAvu647CWPTvHMFcYQmSHyLEYX2/4IMxAstTp7OTxlac+w7BLs6IlmSd3LDXc0rHw8yZodf5w5gvlvpWLtRD7KLOkZ6NXfpe5fRmnFvYBl578hkJEa39w6DRAqYRw3kp4obqpAgMBAAECggEAcZ0onJGddylzwu6h1AX8Co+TluYPgf7TKmxKAUZXfNp5N9YFTGcLVxqPJ6aBNgiZm8PgcZopkS1SAqU7Hc4Gf4R+IAQW+5/uBqa6U4ojkdMvEbyW8uoDlXmInADDDpICc3ByZ5vuHTyM4YU7RCcPrb/3IJ+z+pqeIw8UB/Uc73yUkao+KwL1alpKY8YTkHGMvIwgQDzhRSrfw7Nc5ZLZlkulWfgPN6B51peAqi8ZHGlyECtheEaS/Ws5O/Ju3y7V50WIs/rKT9DFpUZ8nueUPyn1+m+arMFPP3fKd2+9lUotQIIFgkyhLCdX6j7fxhDy2mQk7F68RhZPcGehg86SSQKBgQDM4uK6LCJ8BNURaaOospuOw0nmxeRmDxGMtGDIuTiOLccxwYJPQDQadZ76bfQpn7WmWyQrJWeKmDuvPZ+Mi+RHSL1W0mJnY9/0nLkgsu7fFFq5TDDBnEfNgqfyrozHZa6Eg89exjfH7WQTDbBI2/JXiNHA1iRwRsLIe+RJM/QsYwKBgQC25tBsLoDNUdyaXL9tf2kCG6vepUfdOdfSpby1pU4zpdONJXMenZglh3wIAKWoLVlhchRn/us1ClNasDqJX2O6WgXYh1OL88wFY8B04VnpV3o73vSJhxibZnm6KOzdonHiDAaP5+p/2jVRKewOoEmMFCITzDgSLqcKhA35wxosgwKBgAPUZdqHAqoAyR7HM7juhbvYaKQ4pLlHpNNVd82osKbvsh56+H2UvKSV+D/EGGFCy/ltELMBwvqzN8Jhy36sCrtOX8OksRQvqLsAxvEWhyKCVePKycqEqk7sF0mQ+66qduWhNRoXaGmDRXCZu+bQvannM8x/9DRpDjEDJ9Q6dWDzAoGBAK5GdCYAkX4SGG+FHGnLU1VM5JE7T6R97yWqAovaPQ99XHxLSMvNQiHQXOCLLU14GIh/WO5WuetKMW5iKQSoPbBdAuD04SijXq1sBP/ZkgCC99eAc+VvMoUwOaCmSjxNAtJuvvnz8z9rvg3eMi0lka7FqErQ9kRs64Fbnq1zt8bdAoGABbMMrAgeDvfkQId/1GsFP/xdgUicnXrLhD/cn6NlAqcU9lAubsRDewIQtfw377OsutK6gzbFdrLnaigRDgwf+y0XACdhldE8vTVOPtBaUIqSjTSjuRlp4ZBN1vx2or6QBG7Om061EuaL625YguAjeHpSxTiAbk5tejBnICXPFhY=
公鑰加密======私鑰解密
加密前:會跳舞的機器人
解密后:會跳舞的機器人
私鑰簽名======公鑰驗證
簽名:
DqSegeOz0lIESAd7J7tlkYHsm/81vITAS9RWEmTtOtz5+NVtcD1RGgau2hMVDhNsIr7F0qP2SJSCu0SlAJxvN0pYYrRo5Cy1aLUCfsv/BEoLi32IcNN8cDClCxLa/uIDzyRd3+q8yMDuAhvX2eojiiu6cT3jwrajK4mtxncIbXvNFJ9/po36q8NYujvOhI0ujEFlDC5o5GwskXsJgk/gKf9raiGS9O7Pm8XejsSyDPITre86tuntWQppqWHIku/uN8Cf2n7AlD2HVBryQrma922iIxE3ykfNGoxF4wwof3AGXG4P12nC0rDB/V/7twFZvKmYBWAejni7bDJaV3+pUg==
驗簽結果:
true
五、RSA非對稱加密的缺點
加解密速度較慢,不太適用于高并發(fā)的業(yè)務場景,一般用它做少量的數(shù)據(jù)加密。