jdk默认带了一些常见的加解密方式,当我们常见的加解密不能满足时,就需要用到一些第三方的库了,bouncycastle就是其中一种。
但是bouncycastle文档比较少。简单介绍一下写法
1.导入依赖
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.69</version>
</dependency>
2.写代码
常见的有两种方式,一种使用BouncyCastleProvider,另一种使用BlockCipherEngine
BouncyCastleProvider使用方式跟原生jdk类似,多数getInstance的地方指定一下provider就行
BouncyCastleProvider方式DES加解密代码如下
package com.vvvtimes.demo.util.endecrypt;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
@Slf4j
public class BcDesUtil {
private static final BouncyCastleProvider provider;
//BouncyCastle与JDK加解密类区别
//KeyFactory.getInstance("RSA"); +provider-->KeyFactory.getInstance("RSA", provider)
//Cipher.getInstance("RSA"); +provider-->Cipher.getInstance("RSA", provider)
//Signature.getInstance("SHA1withRSA"); +provider-->Signature.getInstance("SHA1withRSA", provider);
//KeyGenerator.getInstance("DES") ; +provider-->KeyGenerator.getInstance("DES", provider); 或者KeyGenerator.getInstance("DES","BC")
/**
* 偏移变量,固定占8位字节
*/
private final static String IV_PARAMETER = "12345678";
/*
* 生成key
*/
public byte[] generateKey() {
KeyGenerator keyGenerator = null;
try {
keyGenerator = KeyGenerator.getInstance("DES",provider);
keyGenerator.init(56);
SecretKey secretKey = keyGenerator.generateKey();
byte[] encoded = secretKey.getEncoded();
return encoded;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
/**
* 生成key
*
* @param password 密钥字符串
* @return 密钥对象
* @throws Exception
*/
private static Key convertKey(byte[] password) throws Exception {
DESKeySpec dks = new DESKeySpec(password);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES",provider);
return keyFactory.generateSecret(dks);
}
/**
* DES加密
*/
public static byte[] encrypt(byte[] data, byte[] password) {
if (password == null || password.length < 8) {
throw new RuntimeException("加密失败,key不能小于8位");
}
if (data == null)
return null;
try {
Key secretKey = convertKey(password);
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding",provider);
IvParameterSpec iv = new IvParameterSpec(IV_PARAMETER.getBytes("utf-8"));
cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
byte[] bytes = cipher.doFinal(data);
return bytes;
} catch (Exception e) {
e.printStackTrace();
return data;
}
}
/**
* DES解密解密字符串
*/
public static byte[] decrypt(byte[] data, byte[] password) {
if (password == null || password.length < 8) {
throw new RuntimeException("加密失败,key不能小于8位");
}
if (data == null)
return null;
try {
Key secretKey = convertKey(password);
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding",provider);
IvParameterSpec iv = new IvParameterSpec(IV_PARAMETER.getBytes("utf-8"));
cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
byte[] bytes = cipher.doFinal(data);
return bytes;
} catch (Exception e) {
e.printStackTrace();
return data;
}
}
/**
* byte数组转十六进制
*
* @param bytes
* @return
*/
public static String byte2HexString(byte[] bytes) {
StringBuilder hex = new StringBuilder();
if (bytes != null) {
for (Byte b : bytes) {
hex.append(String.format("%02X", b.intValue() & 0xFF));
}
}
return hex.toString();
}
//测试
public static void main(String[] args) throws Exception {
String source = "admin测试信息1234!@#$%^&*()_+";
System.out.println("原 文: " + source);
String password = "lw112190@2023";
byte[] encryptDataBytes = encrypt(source.getBytes("utf-8"), password.getBytes("utf-8"));
String encryptData = byte2HexString(encryptDataBytes);
System.out.println("加密后: " + encryptData);
byte[] decryptDataBytes = decrypt(encryptDataBytes, password.getBytes("utf-8"));
String decryptData = new String(decryptDataBytes, "utf-8");
;
System.out.println("解密后: " + decryptData);
}
static {
provider = new BouncyCastleProvider();
}
}
BlockCipherEngine方式的DES加解密代码如下
package com.vvvtimes.demo.util.endecrypt;
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.BufferedBlockCipher;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.engines.DESEngine;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.crypto.paddings.PKCS7Padding;
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.bouncycastle.crypto.params.DESParameters;
import org.bouncycastle.crypto.params.ParametersWithIV;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
public class BcDesEngineUtil {
private final static BlockCipher engine;
private static final BouncyCastleProvider provider;
/**
* 偏移变量,固定占8位字节
*/
private final static String IV_PARAMETER = "12345678";
/**
* 生成key
*
* @param password 密钥字符串
* @return 密钥对象
* @throws Exception
*/
private static byte[] convertKeyEncoded(byte[] password) {
byte[] result = null;
try {
DESKeySpec dks = new DESKeySpec(password);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES",provider);
SecretKey secretKey = keyFactory.generateSecret(dks);
return secretKey.getEncoded();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
return result;
}
private static byte[] encrypt( byte[] ptBytes,byte[] key) throws InvalidCipherTextException, UnsupportedEncodingException {
BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(engine), new PKCS7Padding());
cipher.init(true, new ParametersWithIV(new DESParameters(key), IV_PARAMETER.getBytes("utf-8")));
byte[] rv = new byte[cipher.getOutputSize(ptBytes.length)];
int tam = cipher.processBytes(ptBytes, 0, ptBytes.length, rv, 0);
cipher.doFinal(rv, tam);
return rv;
}
private static byte[] decrypt( byte[] cipherText,byte[] key) throws InvalidCipherTextException, UnsupportedEncodingException {
BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(engine), new PKCS7Padding());
cipher.init(false, new ParametersWithIV(new DESParameters( key),IV_PARAMETER.getBytes("utf-8")));
byte[] rv = new byte[cipher.getOutputSize(cipherText.length)];
int tam = cipher.processBytes(cipherText, 0, cipherText.length, rv, 0);
cipher.doFinal(rv, tam);
return rv;
}
/**
* byte数组转十六进制
*
* @param bytes
* @return
*/
public static String byte2HexString(byte[] bytes) {
StringBuilder hex = new StringBuilder();
if (bytes != null) {
for (Byte b : bytes) {
hex.append(String.format("%02X", b.intValue() & 0xFF));
}
}
return hex.toString();
}
//测试
public static void main(String[] args) throws Exception {
String source = "admin测试信息1234!@#$%^&*()_+";
System.out.println("原 文: " + source);
String password = "lw112190@2023";
//String password ="geffzhan";
//String password ="lw112190";
byte[] keyEncoded = convertKeyEncoded(password.getBytes("utf-8"));
byte[] encryptDataBytes = encrypt(source.getBytes("utf-8"), keyEncoded);
String encryptData = byte2HexString(encryptDataBytes);
System.out.println("加密后: " + encryptData);
byte[] decryptDataBytes = decrypt(encryptDataBytes, keyEncoded);
String decryptData = new String(decryptDataBytes, "utf-8");
;
System.out.println("解密后: " + decryptData);
/*
*原 文: admin测试信息1234!@#$%^&*()_+
加密后: 1D5C21B694A9085A69BE7EA37C197D1632239545298613B944C3AC272750A519F66FB43EFEC55C89
解密后: admin测试信息1234!@#$%^&*()_+
*/
}
static {
engine = new DESEngine();
provider = new BouncyCastleProvider();
}
}
3.其他示例
AES加解密
package com.vvvtimes.demo.util.endecrypt;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.AlgorithmParameters;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidParameterSpecException;
@Slf4j
public class BcAesUtil {
private static final BouncyCastleProvider provider;
/**
* 偏移变量,固定占8位字节
*/
private final static String IV_PARAMETER = "1234567890123456";
/**
* AES加密
*/
public static byte[] encrypt(byte[] data, byte[] password, byte[] iv) {
if (data == null)
return null;
try {
Key secretKey = new SecretKeySpec(password,"AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding",provider);
AlgorithmParameters generateIV = generateIV(iv);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, generateIV);
byte[] bytes = cipher.doFinal(data);
return bytes;
} catch (Exception e) {
e.printStackTrace();
return data;
}
}
/**
* AES解密解密字符串
*/
public static byte[] decrypt(byte[] data, byte[] password, byte[] iv) {
if (data == null)
return null;
try {
Key secretKey = new SecretKeySpec(password,"AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding",provider);
AlgorithmParameters generateIV = generateIV(iv);
cipher.init(Cipher.DECRYPT_MODE, secretKey, generateIV);
byte[] bytes = cipher.doFinal(data);
return bytes;
} catch (Exception e) {
e.printStackTrace();
return data;
}
}
public static AlgorithmParameters generateIV(byte[] iv){
AlgorithmParameters params = null;
try {
params = AlgorithmParameters.getInstance("AES");
params.init(new IvParameterSpec(iv));
} catch (NoSuchAlgorithmException | InvalidParameterSpecException e) {
e.printStackTrace();
}
return params;
}
/**
* byte数组转十六进制
*
* @param bytes
* @return
*/
public static String byte2HexString(byte[] bytes) {
StringBuilder hex = new StringBuilder();
if (bytes != null) {
for (Byte b : bytes) {
hex.append(String.format("%02X", b.intValue() & 0xFF));
}
}
return hex.toString();
}
//测试
public static void main(String[] args) throws Exception {
String source = "admin测试信息1234!@#$%^&*()_+";
System.out.println("原 文: " + source);
String password = "passwordpassword";
byte[] encryptDataBytes = encrypt(source.getBytes("utf-8"), password.getBytes("utf-8"),IV_PARAMETER.getBytes("utf-8"));
String encryptData = byte2HexString(encryptDataBytes);
System.out.println("加密后: " + encryptData);
byte[] decryptDataBytes = decrypt(encryptDataBytes, password.getBytes("utf-8"),IV_PARAMETER.getBytes("utf-8"));
String decryptData = new String(decryptDataBytes, "utf-8");
System.out.println("解密后: " + decryptData);
}
static {
provider = new BouncyCastleProvider();
}
}
RSA私钥解密 签名
package com.vvvtimes.demo.util.endecrypt;
import cn.hutool.core.codec.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.nio.charset.Charset;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
public class BcRsaUtil {
private static final BouncyCastleProvider provider;
private static PrivateKey getPrivateKey(String pkcs8Key) {
byte[] pkcs8Keybytes = Base64.decode(pkcs8Key.getBytes(Charset.forName("UTF-8")));
final PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(pkcs8Keybytes);
try {
return KeyFactory.getInstance("RSA", provider).generatePrivate(pkcs8EncodedKeySpec);
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
/**
* RSA私钥解密
*
* @param inputByte 待解密字节数组
* @param pkcs8Key 私钥
* @return 明文
*/
public static byte[] decrypt(byte[] inputByte, String pkcs8Key) {
byte[] outputeByte = null;
try {
PrivateKey privateKey = getPrivateKey(pkcs8Key);
//RSA解密
Cipher cipher = Cipher.getInstance("RSA", provider);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
outputeByte = cipher.doFinal(inputByte);
} catch (NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException | NoSuchAlgorithmException e) {
e.printStackTrace();
}
return outputeByte;
}
public static byte[] sign(final byte[] array, String pkcs8Key) {
try {
PrivateKey privateKey = getPrivateKey(pkcs8Key);
final Signature instance = Signature.getInstance("SHA1withRSA", provider);
instance.initSign(privateKey);
instance.update(array);
return instance.sign();
} catch (GeneralSecurityException ex) {
throw new RuntimeException("License Server installation error 0000000F2", ex);
}
}
static {
provider = new BouncyCastleProvider();
}
}
实际上bouncycastle还支持部分国密算法,这一部分不用自己写实现了。