1、引入依賴
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.63</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.3.10</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>compile</scope>
</dependency>
2、加密工具相關類
1) SM2KeyPair.java
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* 描述:
* 時間: 2021/12/11 12:16 PM
*
* @author snake
*/
@Data
@AllArgsConstructor
public class SM2KeyPair {
/**
* 公鑰
*/
private String publicKey;
/*vue js端 公鑰*/
private String publicQKey;
/**
* 私鑰
*/
private String privateKey;
}
2)、SM2Util.java
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.SM2;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
/**
* 描述:
* 時間: 2021/12/11 12:16 PM
*
* @author snake
*/
public class SM2Util {
/*生成密鑰對*/
public static SM2KeyPair getSm2KeyPair() {
SM2 sm2= SmUtil.sm2();
/*公鑰*/
String publickey=sm2.getPublicKeyBase64();
/* js端公鑰 JS代碼實現 SM2的方案,都是直接使用的私鑰的d值和公鑰的q值直接進行的加解密所以後端口返回的最好是從公鑰裏面提取的q值,以q值做爲js端的加密公鑰*/
String publicQkey = HexUtil.encodeHexStr(((BCECPublicKey)sm2.getPublicKey()).getQ().getEncoded(false));
/*私鑰*/
String privatekey=sm2.getPrivateKeyBase64();
return new SM2KeyPair(publickey,publicQkey,privatekey);
}
/*公鑰加密*/
public static String encrypt(String data, String publickey) {
SM2 sm2=SmUtil.sm2(null,publickey);
String encryptStr = sm2.encryptBcd(data, KeyType.PublicKey);
return encryptStr;
}
/*私鑰解密 公鑰加密密文*/
public static String decrypt(String encryptStr, String privatekey){
if(!encryptStr.startsWith("04")){
encryptStr="04".concat(encryptStr);
}
SM2 sm2=SmUtil.sm2(privatekey,null);
String decryptStr = StrUtil.utf8Str(sm2.decryptFromBcd(encryptStr, KeyType.PrivateKey));
return decryptStr;
}
/** 私鑰簽名*/
public static String signByPrivateKey(String data, String privatekey){
SM2 sm2= SmUtil.sm2(privatekey,null);
String sign = sm2.signHex(HexUtil.encodeHexStr(data));
return sign;
}
/**公鑰驗籤*/
public static boolean verifyByPublicKey(String data, String publickey, String signature){
SM2 sm2= SmUtil.sm2(null,publickey);
boolean verify = sm2.verifyHex(HexUtil.encodeHexStr(data), signature);
return verify;
}
public static void main(String[] args) {
//生成一對公私鑰
SM2KeyPair sm2KeyPair = getSm2KeyPair();
String publicKey = sm2KeyPair.getPublicKey();
String privateKey = sm2KeyPair.getPrivateKey();
System.out.println("公鑰:"+sm2KeyPair.getPublicKey());
System.out.println("私鑰:"+sm2KeyPair.getPrivateKey());
String data = "123123";
String encrypt = encrypt(data, publicKey);
System.out.println("加密後內容:"+encrypt);
String decrypt = decrypt(encrypt, privateKey);
System.out.println("解密後內容:"+decrypt);
}
}
3、spring security 加密類適配
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
/**
* 描述:
* 時間: 2021/12/9 2:59 PM
*
* @author snake
*/
@Component
@ConditionalOnProperty(name = "passwordEncoder",havingValue = "bcrypt")
@Slf4j
public class DefaultPasswordEncoder extends BCryptPasswordEncoder implements PasswordEncoder {
}
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
/**
* 描述:
* 時間: 2021/12/8 10:18 PM
*
* @author snake
*/
@Component
@ConditionalOnProperty(name = "passwordEncoder",havingValue = "sm2")
@Slf4j
public class SM2PasswordEncoder implements PasswordEncoder {
@Value("${sm2.public.key}")
private String publicKey;
@Value("${sm2.private.key}")
private String privateKey;
@Override
public String encode(CharSequence charSequence) {
log.info("SM2PasswordEncoder encode............");
return SM2Util.encrypt(charSequence.toString(),publicKey);
}
@Override
public boolean matches(CharSequence charSequence, String s) {
log.info("SM2PasswordEncoder matches...........");
String decrypt = SM2Util.decrypt(s, privateKey);
return charSequence.toString().equals(decrypt);
}
}
4、application.properties外部配置加密方式
passwordEncoder=bcrypt
sm2.public.key=MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEB/yGrVu52u/Jqd1zrMullpTKitVsE7vsHbFLM3KcRL2qzF1x6HERPWVnYeoO/EmxETuPsJ9NBw3HrM5ux6yhKg==
sm2.private.key=MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgDVlZriDVsfMkOeZmC2Z2CrHkA78LXziQ5JvC+CXdZ+igCgYIKoEcz1UBgi2hRANCAAQH/IatW7na78mp3XOsy6WWlMqK1WwTu+wdsUszcpxEvarMXXHocRE9ZWdh6g78SbERO4+wn00HDceszm7HrKEq
5、在使用加密 的業務代碼塊注入PasswordEncoder