13. 国密信创
提示
完美适配国产化软硬件环境,支持国产中间件、国产数据库、麒麟操作系统、Windows、Linux部署使用;集成国密加解密插件,使用SM2、SM3、SM4等国密算法进行签名、数据完整性保护;软件层面全面遵循等级保护测评要求,完全符合等保、密评要求。
提示
Admin.NET 密码相关默认开启SM2国密加密传输和存储。MD5、SM2、SM4 任意切换。
有计划换掉 MD5 密码加密,采用 PBKDF2 加密。
var pbkdf2Hash = PBKDF2Encryption.Encrypt("Admin.NET"); // 加密
PBKDF2Encryption.Compare("Admin.NET", pbkdf2Hash); // 比较
"Cryptogram": {
"StrongPassword": false, // 是否开启密码强度验证
"PasswordStrengthValidation": "(?=^.{6,16}$)(?=.*\\d)(?=.*\\W+)(?=.*[A-Z])(?=.*[a-z])(?!.*\\n).*$", // 密码强度验证正则表达式,必须须包含大小写字母、数字和特殊字符的组合,长度在6-16之间
"PasswordStrengthValidationMsg": "密码必须包含大小写字母、数字和特殊字符的组合,长度在6-16之间", // 密码强度验证消息提示
"CryptoType": "SM2", // 密码加密算法:MD5、SM2、SM4
"PublicKey": "0484C7466D950E120E5ECE5DD85D0C90EAA85081A3A2BD7C57AE6DC822EFCCBD66620C67B0103FC8DD280E36C3B282977B722AAEC3C56518EDCEBAFB72C5A05312", // 公钥
"PrivateKey": "8EDB615B1D48B8BE188FC0F18EC08A41DF50EA731FA28BF409E6552809E3A111" // 私钥
}
系统已经封装 SM2、SM3、SM4 国密算法,具体调用方法如下:
1、GMUtil.SM2Encrypt() 进行SM2加密
2、GMUtil.SM2Decrypt() 进行SM2解密
3、GMUtil.SM4EncryptECB() 进行SM4加密(ECB)
4、GMUtil.SM4DecryptECB() 进行SM4解密(ECB)
5、GMUtil.SM4EncryptCBC() 进行SM4加密(CBC)
6、GMUtil.SM4DecryptCBC() 进行SM4解密(CBC)
具体实现类 Admin.NET.Core/Util/GM/GMUtil.cs
/// <summary>
/// GM工具类
/// </summary>
public class GMUtil
{
/// <summary>
/// SM2加密
/// </summary>
/// <param name="publicKeyHex"></param>
/// <param name="data_string"></param>
/// <returns></returns>
public static string SM2Encrypt(string publicKeyHex, string data_string)
{
// 如果是130位公钥,.NET使用的话,把开头的04截取掉
if (publicKeyHex.Length == 130)
{
publicKeyHex = publicKeyHex.Substring(2, 128);
}
// 公钥X,前64位
string x = publicKeyHex.Substring(0, 64);
// 公钥Y,后64位
string y = publicKeyHex.Substring(64);
// 获取公钥对象
AsymmetricKeyParameter publicKey1 = GM.GetPublickeyFromXY(new BigInteger(x, 16), new BigInteger(y, 16));
// Sm2Encrypt: C1C3C2
// Sm2EncryptOld: C1C2C3
byte[] digestByte = GM.Sm2Encrypt(Encoding.UTF8.GetBytes(data_string), publicKey1);
string strSM2 = Hex.ToHexString(digestByte);
return strSM2;
}
/// <summary>
/// SM2解密
/// </summary>
/// <param name="privateKey_string"></param>
/// <param name="encryptedData_string"></param>
/// <returns></returns>
public static string SM2Decrypt(string privateKey_string, string encryptedData_string)
{
if (!encryptedData_string.StartsWith("04"))
encryptedData_string = "04" + encryptedData_string;
BigInteger d = new(privateKey_string, 16);
// 先拿到私钥对象,用ECPrivateKeyParameters 或 AsymmetricKeyParameter 都可以
// ECPrivateKeyParameters bcecPrivateKey = GmUtil.GetPrivatekeyFromD(d);
AsymmetricKeyParameter bcecPrivateKey = GM.GetPrivatekeyFromD(d);
byte[] byToDecrypt = Hex.Decode(encryptedData_string);
byte[] byDecrypted = GM.Sm2Decrypt(byToDecrypt, bcecPrivateKey);
string strDecrypted = Encoding.UTF8.GetString(byDecrypted);
return strDecrypted;
}
/// <summary>
/// SM4加密(ECB)
/// </summary>
/// <param name="key_string"></param>
/// <param name="plainText"></param>
/// <returns></returns>
public static string SM4EncryptECB(string key_string, string plainText)
{
byte[] key = Hex.Decode(key_string);
byte[] bs = GM.Sm4EncryptECB(key, Encoding.UTF8.GetBytes(plainText), GM.SM4_ECB_PKCS7PADDING);//NoPadding 的情况下需要校验数据长度是16的倍数. 使用 HandleSm4Padding 处理
return Hex.ToHexString(bs);
}
/// <summary>
/// SM4解密(ECB)
/// </summary>
/// <param name="key_string"></param>
/// <param name="cipherText"></param>
/// <returns></returns>
public static string SM4DecryptECB(string key_string, string cipherText)
{
byte[] key = Hex.Decode(key_string);
byte[] bs = GM.Sm4DecryptECB(key, Hex.Decode(cipherText), GM.SM4_ECB_PKCS7PADDING);
return Encoding.UTF8.GetString(bs);
}
/// <summary>
/// SM4加密(CBC)
/// </summary>
/// <param name="key_string"></param>
/// <param name="iv_string"></param>
/// <param name="plainText"></param>
/// <returns></returns>
public static string SM4EncryptCBC(string key_string, string iv_string, string plainText)
{
byte[] key = Hex.Decode(key_string);
byte[] iv = Hex.Decode(iv_string);
byte[] bs = GM.Sm4EncryptCBC(key, Encoding.UTF8.GetBytes(plainText), iv, GM.SM4_CBC_PKCS7PADDING);
return Hex.ToHexString(bs);
}
/// <summary>
/// SM4解密(CBC)
/// </summary>
/// <param name="key_string"></param>
/// <param name="iv_string"></param>
/// <param name="cipherText"></param>
/// <returns></returns>
public static string SM4DecryptCBC(string key_string, string iv_string, string cipherText)
{
byte[] key = Hex.Decode(key_string);
byte[] iv = Hex.Decode(iv_string);
byte[] bs = GM.Sm4DecryptCBC(key, Hex.Decode(cipherText), iv, GM.SM4_CBC_PKCS7PADDING);
return Encoding.UTF8.GetString(bs);
}
/// <summary>
/// 补足 16 进制字符串的 0 字符,返回不带 0x 的16进制字符串
/// </summary>
/// <param name="input"></param>
/// <param name="mode">1表示加密,0表示解密</param>
/// <returns></returns>
private static byte[] HandleSm4Padding(byte[] input, int mode)
{
if (input == null)
{
return null;
}
byte[] ret = (byte[])null;
if (mode == 1)
{
int p = 16 - input.Length % 16;
ret = new byte[input.Length + p];
Array.Copy(input, 0, ret, 0, input.Length);
for (int i = 0; i < p; i++)
{
ret[input.Length + i] = (byte)p;
}
}
else
{
int p = input[input.Length - 1];
ret = new byte[input.Length - p];
Array.Copy(input, 0, ret, 0, input.Length - p);
}
return ret;
}
}
系统内置了获取国密公钥私钥对实现和接口 Admin.NET.Core/Service/Common/SysCommonService.cs,保证公匙前后端一致才行。接口地址 /api/sysCommon/smKeyPair
/// <summary>
/// 获取国密公钥私钥对 🏆
/// </summary>
/// <returns></returns>
[DisplayName("获取国密公钥私钥对")]
public SmKeyPairOutput GetSmKeyPair()
{
var kp = GM.GenerateKeyPair();
var privateKey = Hex.ToHexString(((ECPrivateKeyParameters)kp.Private).D.ToByteArray()).ToUpper();
var publicKey = Hex.ToHexString(((ECPublicKeyParameters)kp.Public).Q.GetEncoded()).ToUpper();
return new SmKeyPairOutput
{
PrivateKey = privateKey,
PublicKey = publicKey,
};
}
前端公匙路径在 Web/.env。
# port 端口号
VITE_PORT = 8888
# open 运行 npm run dev 时自动打开浏览器
VITE_OPEN = false
# 打包是否开启 cdn(源文件 utils/build.ts),可自行修改
VITE_OPEN_CDN = false
# public path 配置线上环境路径(打包)、本地通过 http-server 访问时,请置空即可
VITE_PUBLIC_PATH =
# SM公钥
VITE_SM_PUBLIC_KEY = "0484C7466D950E120E5ECE5DD85D0C90EAA85081A3A2BD7C57AE6DC822EFCCBD66620C67B0103FC8DD280E36C3B282977B722AAEC3C56518EDCEBAFB72C5A05312"
前端密码加密传输应用:Web/src/views/login/component/account.vue
// SM2加密密码
// const keys = SM2.generateKeyPair(); // 生成密匙对
const publicKey = window.__env__.VITE_SM_PUBLIC_KEY;
const password = sm2.doEncrypt(state.ruleForm.password, publicKey, 1);