C# + Vue3采用SM4
引用

类库:
using Org.BouncyCastle.Crypto.IO; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities.Encoders;
public static class SM4Util_New
{
/// <summary>
/// 默认编码
/// </summary>
private static Encoding DefaultEncoding = Encoding.UTF8;
//"GB2312";
public const string ALGORITHM_NAME = "SM4";
//SM4/ECB/NoPadding
//SM4/CBC/NoPadding
//SM4/CBC/PKCS7Padding
/// <summary>
/// ECB模式 [pkcs7padding填充方式]
/// </summary>
public const string ALGORITHM_NAME_ECB_PADDING = "SM4/ECB/PKCS7Padding";
/// <summary>
/// CBC模式 [pkcs7padding填充方式]
/// </summary>
public const string ALGORITHM_NAME_CBC_PADDING = "SM4/CBC/PKCS7Padding";
//这个不需要 SM4默认就是128位的密钥
//public const int DEFAULT_KEY_SIZE = 128;
/// <summary>
/// 解密
/// </summary>
/// <param name="key">密钥</param>
/// <param name="passInput"></param>
/// <param name="encoding">编码</param>
/// <param name="algorithmMode">默认是ECB模式 [pkcs5padding填充方式]</param>
/// <returns></returns>
public static string DecryptEcb(string key, string passInput, Encoding encoding, string algorithmMode = ALGORITHM_NAME_ECB_PADDING)
{
encoding = encoding ?? Encoding.UTF8;
byte[] keyBytes = Hex.Decode(key);
byte[] input = Hex.Decode(passInput);
return encoding.GetString(DecryptEcb(keyBytes, input, algorithmMode));
}
/// <summary>
/// 解密
/// </summary>
/// <param name="key">密钥</param>
/// <param name="passInput"></param>
/// <param name="algorithmMode">默认是ECB模式 [pkcs5padding填充方式]</param>
/// <returns></returns>
public static string DecryptEcb(string key, string passInput, string algorithmMode = ALGORITHM_NAME_ECB_PADDING)
{
return DecryptEcb(key, passInput, DefaultEncoding, algorithmMode);
}
/// <summary>
/// 解密
/// </summary>
/// <param name="keyBytes">密钥</param>
/// <param name="passInput"></param>
/// <param name="algorithmMode">加密方式</param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public static byte[] DecryptEcb(byte[] keyBytes, byte[] passInput, string algorithmMode)
{
KeyParameter key = ParameterUtilities.CreateKeyParameter(ALGORITHM_NAME, keyBytes);
IBufferedCipher inCipher = CipherUtilities.GetCipher(algorithmMode);
//forEncryption位false表示解密
inCipher.Init(false, key);
MemoryStream bIn = new MemoryStream(passInput, false);
CipherStream cIn = new CipherStream(bIn, inCipher, null);
byte[] bytes = new byte[passInput.Length];
byte[] totalBytes;
try
{
#region 此代码一次性读取解密 可行
/*BinaryReader dIn = new BinaryReader(cIn);
byte[] extra = dIn.ReadBytes(passInput.Length);
Array.Copy(extra, 0, bytes, 0, extra.Length);*/
#endregion
#region 官方demo 是先处理一半 再处理剩下的 最后把剩下的复制到bytes剩余部分
BinaryReader dIn = new BinaryReader(cIn);
for (int i = 0; i != passInput.Length / 2; i++)
{
bytes[i] = dIn.ReadByte();
}
int remaining = bytes.Length - passInput.Length / 2;
byte[] extra = dIn.ReadBytes(remaining);
//把为了加密补位的部分去掉
if (extra.Length < remaining)
{
int len = passInput.Length / 2 + extra.Length;
totalBytes = new byte[len];
Array.Copy(bytes, 0, totalBytes, 0, passInput.Length / 2);
extra.CopyTo(totalBytes, passInput.Length / 2);
return totalBytes;
}
else
{
extra.CopyTo(bytes, passInput.Length / 2);
}
//throw new EndOfStreamException();
#endregion
}
catch (Exception e)
{
throw new Exception("SM4 failed encryption - " + e, e);
}
return bytes;
}
/// <summary>
/// 加密
/// </summary>
/// <param name="key">密钥</param>
/// <param name="text"></param>
/// <param name="encoding">编码</param>
/// <param name="algorithmMode">默认是ECB模式 [pkcs5padding填充方式]</param>
/// <returns></returns>
public static string EncryptEcb(string key, string text, Encoding encoding, string algorithmMode = ALGORITHM_NAME_ECB_PADDING)
{
encoding = encoding ?? Encoding.UTF8;
byte[] keyBytes = Hex.Decode(key);
byte[] input = encoding.GetBytes(text);
return Hex.ToHexString(EncryptEcb(keyBytes, input, algorithmMode));
}
/// <summary>
/// 加密
/// </summary>
/// <param name="key">密钥</param>
/// <param name="text"></param>
/// <param name="algorithmMode"></param>
/// <returns></returns>
public static string EncryptEcb(string key, string text, string algorithmMode = ALGORITHM_NAME_ECB_PADDING)
{
return EncryptEcb(key, text, DefaultEncoding, algorithmMode);
}
/// <summary>
/// 加密
/// </summary>
/// <param name="keyBytes">密钥</param>
/// <param name="input"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public static byte[] EncryptEcb(byte[] keyBytes, byte[] input, string algorithmMode)
{
KeyParameter key = ParameterUtilities.CreateKeyParameter(ALGORITHM_NAME, keyBytes);
IBufferedCipher outCipher = CipherUtilities.GetCipher(algorithmMode);
//forEncryption位true表示加密
outCipher.Init(true, key);
MemoryStream bOut = new MemoryStream();
CipherStream cOut = new CipherStream(bOut, null, outCipher);
try
{
//处理前一半
for (int i = 0; i != input.Length / 2; i++)
{
cOut.WriteByte(input[i]);
}
//处理后一半
cOut.Write(input, input.Length / 2, input.Length - input.Length / 2);
cOut.Close();
}
catch (IOException e)
{
throw new Exception("SM4 failed encryption - " + e, e);
}
byte[] bytes = bOut.ToArray();
return bytes;
}
}
调用:
var encrypt = SM4Util_New.EncryptEcb(SM4_KEY, "[{\"id\":\"4c5849f2.4369f8\",\"type\":\"tab\",\"label\":\"1111\",\"disabled\":false,\"info\":\"\"}]");
var decrypt = SM4Util_New.DecryptEcb(SM4_KEY,encrypt );
密钥生成方法:
var SM4_KEY = Guid.NewGuid().ToString("N");//生成key 32位 16进制字符串
解密方法:
public static String decrypt()
{
var iv = Hex.Decode("fedcba98765432100123456789abcdef");
//byte[] plain = Hex.Decode("0123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba9876543210");
byte[] key = Hex.Decode("0123456789abcdeffedcba9876543210");
var base64Str = Base64Util.Base64Decrypt("MGQ2Y2ZhNzNjODIzYjJhYzBkNmE5MmM1NjQxNzE4OTJmYTk1ZmE0Yjc1OTEwMzIwMjBjNGFhNDlkMmI0MmJjNQ==");
byte[] cipher = Hex.Decode(base64Str);
var bs = GmUtil.Sm4DecryptCBC(key, cipher, iv, GmUtil.SM4_CBC_PKCS7PADDING);
var encrypt = Encoding.UTF8.GetString(bs);
System.Console.Out.WriteLine(encrypt);
return encrypt;
//log.Info("testSm4EncEcb: " + Hex.ToHexString(bs)); ;
//bs = Sm4DecryptECB(key, bs, GmUtil.SM4_ECB_NOPADDING);
}
Vue3
npm install --save sm-crypto
--https://www.npmjs.com/package/sm-crypto
npm install --save js-base64
import { sm4, sm3, sm2 } from "sm-crypto";
import { Base64 } from "js-base64";
function doDecryptSm4() {
const encryptData =
"1118b5cec13c3bcd39e7006f9c155017948d2025fe716b45746e9b04559e77d52f2345cf9d1cf55abee0adca8f971a0693a7ea8a26f67a377a24a26a8d5f60c4f5c145149bd4de7144bbb1093374549f3c813d0b36b2284e33aacac91e5d2f62";
const key = "8abf369903e94857bcadbcf7068d68e3";
let decryptData = sm4.decrypt(encryptData, key); // 解密,不使用 padding
console.log(decryptData);
console.log(Base64.encode(decryptData));
}
function doEncryptSm4() {
//后端返回的数据格式
var json = [
{
id: "4c5849f2.4369f8",
type: "tab",
label: "1111",
disabled: false,
info: "",
},
];
const escapedJson = JSON.stringify(json);
console.log(escapedJson);
const msg = escapedJson;
//"{'urlquerystring':'partner=XunChaApplet&channel=ApiApplet&clientversion=1.0×tamp=1701956563','Sign':'0aa77898ea0181d2c0addbaff953a633'}"; // 可以为 utf8 串或字节数组
const key = "8abf369903e94857bcadbcf7068d68e3"; // 可以为 16 进制串或字节数组,要求为 128 比特
let encryptData = sm4.encrypt(msg, key); // 加密,默认输出 16 进制字符串,默认使用 pkcs#7 填充(传 pkcs#5 也会走 pkcs#7 填充) 默认走 ECB 模式
//let encryptData = sm4.encrypt(msg, key, {padding: 'none'}) // 加密,不使用 padding
//let encryptData = sm4.encrypt(msg, key, {padding: 'none', output: 'array'}) // 加密,不使用 padding,输出为字节数组
//let encryptData = sm4.encrypt(msg, key, { mode: "cbc",iv: "fedcba98765432100123456789abcdef", }); // 加密,cbc 模式 默认使用 pkcs#7 填充
console.log(encryptData);
console.log(Base64.encode(encryptData));
}

浙公网安备 33010602011771号