09-crypt
1. Encrypt
1. sm4双向加密
1. 前端
var encryptedText = SmUtils.encryptTest(encryptText, 'sm4Key')
{
"sm4": "045cda898fc466b8526ac121e7db57b71fde6ed2ae",
"sm2": "392b4f156c2424217a68f68294"
}
2. 后端
Map<String, String> map = gson.<Map<String, String>>fromJson(encryptedText, HashMap.class);
String sm2 = map.get("sm2");
String sm4 = map.get("sm4");
String decrypt = SmUtils.decrypt(sm2, sm4, "sm4Key");
2. aes双向加密
1. 前端Ase.js
import CryptoJS from 'crypto-js'
/**
* @word 要加密的内容
* @keyWord String 服务器随机返回的关键字
*/
export function aesEncrypt(word, keyWord = "67192fb8b12e0bd073308c19ae8e8fee") {
const key = CryptoJS.enc.Utf8.parse(keyWord);
const srcs = CryptoJS.enc.Utf8.parse(word);
const encrypted = CryptoJS.AES.encrypt(srcs, key, {mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7});
return encrypted.toString();
}
import {aesEncrypt} from '../utils/Ase'
sqlText = aesEncrypt(sqlText)
2. 后端
/**
* AES解密
*
* @param encryptStr 密文
* @param decryptKey 秘钥,必须为16个字符组成
* @return 明文
*/
private String aesDecrypt(String encryptStr, String decryptKey) throws Exception {
if (StringUtils.isEmpty(encryptStr) || StringUtils.isEmpty(decryptKey)) {
return null;
}
byte[] encryptByte = Base64.getDecoder().decode(encryptStr);
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(decryptKey.getBytes(), "AES"));
byte[] decryptBytes = cipher.doFinal(encryptByte);
return new String(decryptBytes);
}
String sql = this.aesDecrypt(encryptSql, sm4GenerateKey);
3. postman
var secretKey = '67192fb8b12e0bd073308c19ae8e8fee';
let key = CryptoJS.enc.Utf8.parse(secretKey);
// var content = request.data["sql"];
var content = "select 1";
let srcs = CryptoJS.enc.Utf8.parse(content);
let aesDecrypt = CryptoJS.AES.encrypt(srcs, key, { mode:CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 });
postman.setGlobalVariable("encryptSql", aesDecrypt);
2. crypt
1. rsa非对称加密
1. jsencrypt项目
1. js前端
引入这个文件即可 jsencrypt.min.js
// 加密:公钥加密 + 私钥解密
// Encrypt with the public key...
var encrypt = new JSEncrypt();
encrypt.setPublicKey($('#pubkey').val());
var encrypted = encrypt.encrypt($('#input').val());
// Decrypt with the private key...
var decrypt = new JSEncrypt();
decrypt.setPrivateKey($('#privkey').val());
var uncrypted = decrypt.decrypt(encrypted);
// 签名:私钥签名 + 公钥验签
// Sign with the private key...
var sign = new JSEncrypt();
sign.setPrivateKey($('#privkey').val());
var signature = sign.sign($('#input').val(), CryptoJS.SHA256, "sha256");
// Verify with the public key...
var verify = new JSEncrypt();
verify.setPublicKey($('#pubkey').val());
var verified = verify.verify($('#input').val(), signature, CryptoJS.SHA256);
2. vue前端
sudo cnpm install jsencrypt --dep
- vue项目用到了
lib
文件夹
<script>
import { JSEncrypt } from 'jsencrypt'
import RsaApi from './RsaApi'
export default {
data() {
return {
pubKey: 'MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgGiyBQovCstb9hb+d0IsbQrg2k+3eNBTeGBzkHfcXAsqWg8ExZYhNQwmssaf3fO6opVjA+cZ61yexM+NYmILw8hcas313ucl62FDGpmuE0Mhhpvo9lJOLcvQirUFp3jihgQa4lYtR+mSP1CQNmPcp6E2OEq1e8rmGGjFDD9Fm4OvAgMBAAE=',
mobile: '19910769053',
encryptStr: ''
}
},
methods: {
send() {
const crypt = new JSEncrypt()
crypt.setPublicKey(this.pubKey)
RsaApi.rsa({
'appId': crypt.encrypt(this.mobile)
}).then(res => {
}).catch(err => {
console.log(err)
})
}
}
}
</script>
2. hutool
String PRIVATE_KEY = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAIL7pbQ+5KKGYRhw7jE31hmA"
+ "f8Q60ybd+xZuRmuO5kOFBRqXGxKTQ9TfQI+aMW+0lw/kibKzaD/EKV91107xE384qOy6IcuBfaR5lv39OcoqNZ"
+ "5l+Dah5ABGnVkBP9fKOFhPgghBknTRo0/rZFGI6Q1UHXb+4atP++LNFlDymJcPAgMBAAECgYBammGb1alndta"
+ "xBmTtLLdveoBmp14p04D8mhkiC33iFKBcLUvvxGg2Vpuc+cbagyu/NZG+R/WDrlgEDUp6861M5BeFN0L9O4hz"
+ "GAEn8xyTE96f8sh4VlRmBOvVdwZqRO+ilkOM96+KL88A9RKdp8V2tna7TM6oI3LHDyf/JBoXaQJBAMcVN7fKlYP"
+ "Skzfh/yZzW2fmC0ZNg/qaW8Oa/wfDxlWjgnS0p/EKWZ8BxjR/d199L3i/KMaGdfpaWbYZLvYENqUCQQCobjsuCW"
+ "nlZhcWajjzpsSuy8/bICVEpUax1fUZ58Mq69CQXfaZemD9Ar4omzuEAAs2/uee3kt3AvCBaeq05NyjAkBme8SwB0iK"
+ "kLcaeGuJlq7CQIkjSrobIqUEf+CzVZPe+AorG+isS+Cw2w/2bHu+G0p5xSYvdH59P0+ZT0N+f9LFAkA6v3Ae56OrI"
+ "wfMhrJksfeKbIaMjNLS9b8JynIaXg9iCiyOHmgkMl5gAbPoH/ULXqSKwzBw5mJ2GW1gBlyaSfV3AkA/RJC+adIjsRGg"
+ "JOkiRjSmPpGv3FOhl9fsBPjupZBEIuoMWOC8GXK/73DHxwmfNmN7C9+sIi4RBcjEeQ5F5FHZ";
RSA rsa = new RSA(PRIVATE_KEY, null);
String a = "2707F9FD4288CEF302C972058712F24A5F3EC62C5A14AD2FC59DAB93503AA0FA17113A020EE4EA35EB53F"
+ "75F36564BA1DABAA20F3B90FD39315C30E68FE8A1803B36C29029B23EB612C06ACF3A34BE815074F5EB5AA3A"
+ "C0C8832EC42DA725B4E1C38EF4EA1B85904F8B10B2D62EA782B813229F9090E6F7394E42E6F44494BB8";
byte[] aByte = HexUtil.decodeHex(a);
byte[] decrypt = rsa.decrypt(aByte, KeyType.PrivateKey);
// Junit单元测试
Assertions.assertEquals("虎头闯杭州,多抬头看天,切勿只管种地", StrUtil.str(decrypt, CharsetUtil.CHARSET_UTF_8));
String decryptStr = rsa.decryptStr(a, KeyType.PrivateKey);
2. 新版国密SM
1. sm2 sm3 sm4后端
public class JunitSm {
static final String pubKey = "3059301306072a8648ce3d020106082a811ccf5501822d0342000401cebfe224b122b3682e7683b3e449df919ef09dcc762cb107f1c2e7a39ecbb73dad92c94279252bdd97cc58666fa9483a804a785dc935d29ec12c2971ded43e";
static final String priKey = "308193020100301306072a8648ce3d020106082a811ccf5501822d047930770201010420aea516cb710b634e4b6e4ebe650d3c8d168e735f69fbc36aa4b5ef3ae6e5e13ba00a06082a811ccf5501822da1440342000401cebfe224b122b3682e7683b3e449df919ef09dcc762cb107f1c2e7a39ecbb73dad92c94279252bdd97cc58666fa9483a804a785dc935d29ec12c2971ded43e";
static final String pubKeyQ = "0401cebfe224b122b3682e7683b3e449df919ef09dcc762cb107f1c2e7a39ecbb73dad92c94279252bdd97cc58666fa9483a804a785dc935d29ec12c2971ded43e";
static final String priKeyD = "00aea516cb710b634e4b6e4ebe650d3c8d168e735f69fbc36aa4b5ef3ae6e5e13b";
static final String sm2_vue_ciphertext = "73cfe0a7c50949db28377c25d0459ff29d5eaafddc890149c248c717d3c518d5eb1bbd78a4e92fec21def5aebb20752c5aebc7919cfe9787c7931925c4c1363bc57d7cefe396e03ec1816a52b3e1c41321fc3d5a96a1c6e107c98f1c6890f414d38f374817e1";
static final String sm3_vue = "b65e9d49ad52f48947b191eab56eef91412f0e2b9d6be918df19a2c64dd178a6";
static final String sm4_key = "cf9fcc051a78c53f634e421b71fb0af8";
/**
* 后端生成,前端可用
*/
@Test
public void sm2Key() {
SM2 sm2 = SmUtil.sm2();
// sm2的加解密时有两种形式即 C1C2C3、 C1C3C2
sm2.setMode(SM2Engine.Mode.C1C3C2);
// 生成公钥
String pubKey = HexUtil.encodeHexStr(sm2.getPublicKey().getEncoded());
System.out.println(pubKey);
// 生成私钥
String priKey = HexUtil.encodeHexStr(sm2.getPrivateKey().getEncoded());
System.out.println(priKey);
// 生成公钥Q,以Q值直接做为js端的加密公钥(以04开头,表示未压缩)
String pubKeyQ = HexUtil.encodeHexStr(((BCECPublicKey) sm2.getPublicKey()).getQ().getEncoded(false));
System.out.println(pubKeyQ);
// 生成私钥D,以D值做为js端的解密私钥
// ((BCECPrivateKey) privateKey).getD().toByteArray();
String priKeyD = HexUtil.encodeHexStr(BCUtil.encodeECPrivateKey(sm2.getPrivateKey()));
System.out.println(priKeyD);
}
/**
* 前端加密,后端解密(密文需要加04未压缩标识)
* 后端加密,前端解密(密文需要去掉04未压缩标识)
*/
@Test
public void sm2() {
SM2 sm2 = SmUtil.sm2(priKey, pubKey);
// sm2的加解密时有两种方式:1-C1C2C3,2-C1C3C2
sm2.setMode(SM2Engine.Mode.C1C3C2);
// 后端解密
String plaintext = sm2.decryptStr("04" + sm2_vue_ciphertext, KeyType.PrivateKey);
System.out.println(plaintext);
// 公钥加密plaintext,生成16进制ciphertext。去掉04传前端
String ciphertext = sm2.encryptHex(plaintext, KeyType.PublicKey);
System.out.println("vue_ciphertext: " + ciphertext.substring(2));
}
@Test
public void sm3() {
String sm3_digest = SmUtil.sm3("sm3_plaintext");
boolean flag = sm3_vue.equalsIgnoreCase(sm3_digest);
System.out.println(flag);
}
@Test
public void sm4() {
// 无参:生成key,有参:指定key
// SymmetricCrypto sm4 = SmUtil.sm4();
SymmetricCrypto sm4 = SmUtil.sm4(HexUtil.decodeHex(sm4_key));
// sm4_key 16进制字符串
String sm4_key = HexUtil.encodeHexStr(sm4.getSecretKey().getEncoded());
System.out.println(sm4_key);
// 加密
String sm4_ciphertext = sm4.encryptHex("hello sm4!");
System.out.println(sm4_ciphertext);
// 解密
String sm4_plaintext = sm4.decryptStr(sm4_ciphertext, CharsetUtil.CHARSET_UTF_8);
System.out.println(sm4_plaintext);
}
/**
* sm2 签名、验签,不能和前端联动
*/
@Test
public void sign() {
// 两种构造都可以
// SM2 sm2 = new SM2(priKeyD, pubKeyQ);
SM2 sm2 = new SM2(priKey, pubKey);
String content = "sign_plaintext";
String sm2_sign = sm2.signHex(HexUtil.encodeHexStr(content));
System.out.println("sm2_sign: " + sm2_sign);
boolean verify = sm2.verifyHex(HexUtil.encodeHexStr(content), sm2_sign);
System.out.println(verify);
}
}
2. sm2 sm3 sm4前端
<script>
export default {
data() {
return {
pubKeyQ: '0401cebfe224b122b3682e7683b3e449df919ef09dcc762cb107f1c2e7a39ecbb73dad92c94279252bdd97cc58666fa9483a804a785dc935d29ec12c2971ded43e',
priKeyD: '00aea516cb710b634e4b6e4ebe650d3c8d168e735f69fbc36aa4b5ef3ae6e5e13b'
}
},
methods: {
sm() {
// 04未压缩标识。hutool的默认实现是压缩过,js端是未压缩的
const sm2 = require('sm-crypto').sm2
// 1-C1C3C2,0-C1C2C3,默认为1
const cipherMode = 1
// sm2
// 验证pubKey
let verifyPubKeyQ = sm2.verifyPublicKey(this.pubKeyQ)
console.log('verifyPubKeyQ:', verifyPubKeyQ)
// 加密结果(后端加上04,进行解密)
let ciphertext = sm2.doEncrypt('明文', this.pubKeyQ, cipherMode)
console.log('sm2_ciphertext: ', ciphertext)
// 解密结果(去掉04,前端解密)
let plaintext = sm2.doDecrypt(ciphertext, this.priKeyD, cipherMode)
console.log('sm2_plaintext: ', plaintext)
// sm3
const sm3 = require('sm-crypto').sm3
let sm3_ciphertext = sm3('sm3_plaintext')
console.log('sm3_ciphertext: ', sm3_ciphertext)
// sm4
const sm4 = require('sm-crypto').sm4
// utf8串或字节数组
const sm4Text = 'hello sm4!'
// 16进制串或字节数组,要求为 128 比特(后端生成)
const sm4_key = '45f9102170b0b719a524fbea17234eae'
// 加密,默认输出 16进制字符串,默认使用 pkcs#5 填充
let sm4_ciphertext = sm4.encrypt(sm4Text, sm4_key)
console.log('sm4_ciphertext: ', sm4_ciphertext)
let sm4_plaintext = sm4.decrypt(sm4_ciphertext, sm4_key)
console.log('sm4_plaintext: ', sm4_plaintext)
// sm2 签名、验签,不能和后端联动
let sm2_sign = sm2.doSignature('sign_plaintext', this.priKeyD)
console.log('sm2_sign: ', sm2_sign)
let verifyResult = sm2.doVerifySignature('sign_plaintext', sm2_sign, this.pubKeyQ)
console.log('verify_sm2_sign: ', verifyResult)
}
}
}
</script>