加密算法種類:
-
對稱加密
對稱加密,意味着加密和解密使用同一個秘鑰,安全級别相對于非對稱加密要低.
-
非對稱加密
非對稱加密,意味着加密和解密使用不同的秘鑰,安全級别相對于對稱加密要高.
-
hash算法
hash算法是一種單向算法,不可還原成加密之前的元字元.
常用的加密算法
常見的對稱加密算法
DES、3DES、DESX、Blowfish、IDEA、RC4、RC5、RC6和AES
常見的非對稱加密算法
RSA、ECC、Diffie-Hellman、El Gamal、DSA
常見的Hash算法
MD2、MD4、MD5、HAVAL、SHA、SHA-1、HMAC、HMAC-MD5、HMAC-SHA1
非對稱加密算法-RSA實作
依賴的POM:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
實作代碼:
import com.bruce.tool.common.exception.ExceptionUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Objects;
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class RSA {
private static final String KEY_ALGORITHM = "RSA";
private static final String RSA_SIGNATURE_ALGORITHM = "SHA1withRSA";
/**
* 初始化密鑰
*/
public static KeyPair init() {
try {
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
keyPairGen.initialize(1024);
return keyPairGen.generateKeyPair();
} catch (Exception e) {
ExceptionUtils.printStackTrace(e);
}
return null;
}
/**
* 取得公鑰
*/
public static String publicKey(KeyPair keyPair) {
if(Objects.isNull(keyPair) ){ return null; }
return Base64.encode(keyPair.getPublic().getEncoded());
}
/**
* 取得私鑰
*/
public static String privateKey(KeyPair keyPair) {
if(Objects.isNull(keyPair)){ return null; }
return Base64.encode(keyPair.getPrivate().getEncoded());
}
/**
* 用公鑰加密
* @param data 中繼資料位元組碼
* @param base64PublicKey base64編碼過的公鑰(publicKey)
* @return 加密結果
*/
public static byte[] encrypt(byte[] data, String base64PublicKey) {
try {
// 對公鑰解密
byte[] keyBytes = Base64.decode(base64PublicKey);
// 取得公鑰
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key publicKey = keyFactory.generatePublic(x509KeySpec);
// 對資料加密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(data);
} catch (Exception e) {
ExceptionUtils.printStackTrace(e);
}
return new byte[0];
}
/**
* 用私鑰解密
* @param data 中繼資料位元組碼
* @param base64PrivateKey base64編碼過的私鑰(privateKey)
* @return 解碼結果
*/
public static byte[] decrypt(byte[] data, String base64PrivateKey) {
try {
// 對密鑰解密
byte[] keyBytes = Base64.decode(base64PrivateKey);
// 取得私鑰
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
// 對資料解密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(data);
} catch (Exception e) {
ExceptionUtils.printStackTrace(e);
}
return new byte[0];
}
/**
* 簽名-私鑰簽名
* @param data 中繼資料位元組碼
* @param base64PrivateKey base64編碼過的私鑰
* @return 簽名結果
*/
public static byte[] sign(byte[] data, String base64PrivateKey){
try {
// Base64 --> Key
byte[] bytes = Base64.decode(base64PrivateKey);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
// Sign
Signature signature = Signature.getInstance(RSA_SIGNATURE_ALGORITHM);
signature.initSign(privateKey);
signature.update(data);
return signature.sign();
} catch (Exception e) {
ExceptionUtils.printStackTrace(e);
}
return new byte[0];
}
/**
* 驗簽-公鑰驗簽
*
* @param data 需要驗簽的字元串
* @param base64PublicKey base64編碼之後的公鑰
* @param sign 需要驗證的簽名
* @return
*/
public static boolean verify(byte[] data, String base64PublicKey, String sign) {
try {
// Base64 --> Key
byte[] bytes = Base64.decode(base64PublicKey);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
PublicKey publicKey = keyFactory.generatePublic(keySpec);
// verify
Signature signature = Signature.getInstance(RSA_SIGNATURE_ALGORITHM);
signature.initVerify(publicKey);
signature.update(data);
return signature.verify(Base64.decode(sign));
} catch (Exception e) {
ExceptionUtils.printStackTrace(e);
}
return false;
}
}
測試類:
import com.bruce.tool.common.util.LogUtils;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import java.security.KeyPair;
@Slf4j
public class RSATest {
/**生成簽名**/
@Test
public void createKeys() {
KeyPair keyPair = RSA.init();
LogUtils.info(log,RSA.publicKey(keyPair));
LogUtils.info(log,RSA.privateKey(keyPair));
}
/**簽名和驗簽**/
@Test
public void signAndVerify() {
KeyPair keyPair = RSA.init();
String publicKey = RSA.publicKey(keyPair));
String privateKey = RSA.privateKey(keyPair));
String payload = "a=1&b=2&c=3";
byte[] sign = RSA.sign(payload.getBytes(),privateKey);
LogUtils.info(log,Base64.encode(sign));
boolean verify = RSA.verify(payload.getBytes(),publicKey,Base64.encode(sign));
LogUtils.info(log,verify);
}
/**加密解密**/
@Test
public void encryptAndDecrypt() {
KeyPair keyPair = RSA.init();
String publicKey = RSA.publicKey(keyPair));
String privateKey = RSA.privateKey(keyPair));
String payload = "123456";
byte[] encrypts = RSA.encrypt(payload.getBytes(),publicKey);
LogUtils.info(log,Base64.encode(encrypts));
byte[] decrypts = RSA.decrypt(Base64.decode(Base64.encode(encrypts)),privateKey);
LogUtils.info(log,new String(decrypts));
}
}
補充說明
- 在做計算算法概念确定的時候,最初給加密算法想當然的給列了如下的種類:
在想說明一下MD5的時候,覺着不太精确,怕誤導大家,于是,到CSDN首頁查了一下,發現一篇文章MD5到底是不是加密算法,于是修改了關于算法的種類說明.1.不可逆加密(不可解密) 不可逆,意味着加密之後,不能被解密. 2.可逆加密(可解密) A.對稱加密 對稱加密,意味着加密和解密使用同一個秘鑰,安全級别相對于非對稱加密要低. B.非對稱加密 非對稱加密,意味着加密和解密使用不同的秘鑰,安全級别相對于對稱加密要高.
- 關于加密算法,還有許多知識點,在此并沒有細說,因為這片文章的目的是"開箱即用".
- 文章裡邊使用到lombok,使用ide的童鞋,請安裝對應的lombok插件.
- 文章裡邊使用到ExceptionUtils以及LogUtils是我自己封裝的工具類,大家用的時候,可以替換成自己的.
參考文獻
1.百度百科-算法種類說明
2.百度百科-RSA算法說明
3.部落格園-常用加密算法概述