From a213bd1316a9e16777c4be52b677a383a60cbd4b Mon Sep 17 00:00:00 2001
From: NoahLan <6995syu@163.com>
Date: Fri, 23 Feb 2024 18:01:03 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=8A=A0=E5=AF=86?=
=?UTF-8?q?=E8=A7=A3=E5=AF=86=E7=AE=97=E6=B3=95=EF=BC=8C=E6=B7=BB=E5=8A=A0?=
=?UTF-8?q?upms?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
NPin.sln | 44 ++-
.../NPin.Framework.Core/Crypt/AES/AesCrypt.cs | 84 +++++
.../Crypt/AES/AesKeyEnum.cs | 17 +
.../Crypt/BCrypt/BCrypt.cs | 14 +
.../NPin.Framework.Core/Crypt/DES/DesCrypt.cs | 77 +++++
.../Crypt/DES/TripleDes.cs | 73 ++++
.../Crypt/Md5Extensions.cs | 36 ++
.../NPin.Framework.Core/Crypt/RC4/Rc4Crypt.cs | 48 +++
framework/NPin.Framework.Core/Crypt/README.md | 14 +
.../NPin.Framework.Core/Crypt/RSA/RsaCrypt.cs | 178 ++++++++++
.../Crypt/RSA/RsaKeyConverter.cs | 89 +++++
.../Crypt/RSA/RsaKeyLength.cs | 27 ++
.../Crypt/RSA/RsaSecretKey.cs | 49 +++
.../NPin.Framework.Core/Crypt/SM2/Sm2Crypt.cs | 157 +++++++++
.../NPin.Framework.Core/Crypt/SM3/Sm3Crypt.cs | 37 ++
.../NPin.Framework.Core/Crypt/SM4/Sm4.cs | 323 ++++++++++++++++++
.../Crypt/SM4/Sm4Context.cs | 19 ++
.../NPin.Framework.Core/Crypt/SM4/Sm4Crypt.cs | 116 +++++++
.../NPin.Framework.Core/Crypt/SM4/Sm4Mode.cs | 7 +
.../NPin.Framework.Core.csproj | 1 +
.../Data/IEnabled.cs | 6 +
.../Data/IOrderNum.cs | 9 +
.../ISqlSugarDbConnectionCreator.cs | 1 +
.../SqlSugarDbConnectionCreator.cs | 6 +
.../SqlSugarDbContext.cs | 20 +-
...ramework.Upms.Application.Contracts.csproj | 9 +
...FrameworkUpmsApplicationContractsModule.cs | 12 +
.../NPin.Framework.Upms.Application.csproj | 15 +
.../NPinFrameworkUpmsApplicationModule.cs | 22 ++
.../Caches/CaptchaPhoneCacheItem.cs | 26 ++
.../Consts/UserConst.cs | 16 +
.../Enums/DataScopeEnum.cs | 32 ++
.../Enums/GenderEnum.cs | 19 ++
.../Enums/JobTypeEnum.cs | 14 +
.../NPin.Framework.Upms.Domain.Shared.csproj | 16 +
.../NPinFrameworkUpmsDomainSharedModule.cs | 22 ++
.../OperLog/OperLogAttribute.cs | 31 ++
.../OperLog/OperTypeEnum.cs | 19 ++
.../Options/AliyunOptions.cs | 17 +
.../Options/JwtOptions.cs | 15 +
.../Options/RefreshJwtOptions.cs | 8 +
.../Options/UpmsOptions.cs | 32 ++
.../Authorization/IDataPermission.cs | 8 +
.../Entities/UserEntity.cs | 88 +++++
.../NPin.Framework.Upms.Domain.csproj | 18 +
.../NPinFrameworkUpmsDomainModule.cs | 32 ++
.../NPin.Framework.Upms.SqlSugarCore.csproj | 10 +
.../NPinFrameworkUpmsSqlSugarCoreModule.cs | 19 ++
.../NPinUpmsDbContext.cs | 49 +++
49 files changed, 1997 insertions(+), 4 deletions(-)
create mode 100644 framework/NPin.Framework.Core/Crypt/AES/AesCrypt.cs
create mode 100644 framework/NPin.Framework.Core/Crypt/AES/AesKeyEnum.cs
create mode 100644 framework/NPin.Framework.Core/Crypt/BCrypt/BCrypt.cs
create mode 100644 framework/NPin.Framework.Core/Crypt/DES/DesCrypt.cs
create mode 100644 framework/NPin.Framework.Core/Crypt/DES/TripleDes.cs
create mode 100644 framework/NPin.Framework.Core/Crypt/Md5Extensions.cs
create mode 100644 framework/NPin.Framework.Core/Crypt/RC4/Rc4Crypt.cs
create mode 100644 framework/NPin.Framework.Core/Crypt/README.md
create mode 100644 framework/NPin.Framework.Core/Crypt/RSA/RsaCrypt.cs
create mode 100644 framework/NPin.Framework.Core/Crypt/RSA/RsaKeyConverter.cs
create mode 100644 framework/NPin.Framework.Core/Crypt/RSA/RsaKeyLength.cs
create mode 100644 framework/NPin.Framework.Core/Crypt/RSA/RsaSecretKey.cs
create mode 100644 framework/NPin.Framework.Core/Crypt/SM2/Sm2Crypt.cs
create mode 100644 framework/NPin.Framework.Core/Crypt/SM3/Sm3Crypt.cs
create mode 100644 framework/NPin.Framework.Core/Crypt/SM4/Sm4.cs
create mode 100644 framework/NPin.Framework.Core/Crypt/SM4/Sm4Context.cs
create mode 100644 framework/NPin.Framework.Core/Crypt/SM4/Sm4Crypt.cs
create mode 100644 framework/NPin.Framework.Core/Crypt/SM4/Sm4Mode.cs
create mode 100644 framework/NPin.Framework.SqlSugarCore.Abstractions/Data/IEnabled.cs
create mode 100644 framework/NPin.Framework.SqlSugarCore.Abstractions/Data/IOrderNum.cs
create mode 100644 module/upms/NPin.Framework.Upms.Application.Contracts/NPin.Framework.Upms.Application.Contracts.csproj
create mode 100644 module/upms/NPin.Framework.Upms.Application.Contracts/NPinFrameworkUpmsApplicationContractsModule.cs
create mode 100644 module/upms/NPin.Framework.Upms.Application/NPin.Framework.Upms.Application.csproj
create mode 100644 module/upms/NPin.Framework.Upms.Application/NPinFrameworkUpmsApplicationModule.cs
create mode 100644 module/upms/NPin.Framework.Upms.Domain.Shared/Caches/CaptchaPhoneCacheItem.cs
create mode 100644 module/upms/NPin.Framework.Upms.Domain.Shared/Consts/UserConst.cs
create mode 100644 module/upms/NPin.Framework.Upms.Domain.Shared/Enums/DataScopeEnum.cs
create mode 100644 module/upms/NPin.Framework.Upms.Domain.Shared/Enums/GenderEnum.cs
create mode 100644 module/upms/NPin.Framework.Upms.Domain.Shared/Enums/JobTypeEnum.cs
create mode 100644 module/upms/NPin.Framework.Upms.Domain.Shared/NPin.Framework.Upms.Domain.Shared.csproj
create mode 100644 module/upms/NPin.Framework.Upms.Domain.Shared/NPinFrameworkUpmsDomainSharedModule.cs
create mode 100644 module/upms/NPin.Framework.Upms.Domain.Shared/OperLog/OperLogAttribute.cs
create mode 100644 module/upms/NPin.Framework.Upms.Domain.Shared/OperLog/OperTypeEnum.cs
create mode 100644 module/upms/NPin.Framework.Upms.Domain.Shared/Options/AliyunOptions.cs
create mode 100644 module/upms/NPin.Framework.Upms.Domain.Shared/Options/JwtOptions.cs
create mode 100644 module/upms/NPin.Framework.Upms.Domain.Shared/Options/RefreshJwtOptions.cs
create mode 100644 module/upms/NPin.Framework.Upms.Domain.Shared/Options/UpmsOptions.cs
create mode 100644 module/upms/NPin.Framework.Upms.Domain/Authorization/IDataPermission.cs
create mode 100644 module/upms/NPin.Framework.Upms.Domain/Entities/UserEntity.cs
create mode 100644 module/upms/NPin.Framework.Upms.Domain/NPin.Framework.Upms.Domain.csproj
create mode 100644 module/upms/NPin.Framework.Upms.Domain/NPinFrameworkUpmsDomainModule.cs
create mode 100644 module/upms/NPin.Framework.Upms.SqlSugarCore/NPin.Framework.Upms.SqlSugarCore.csproj
create mode 100644 module/upms/NPin.Framework.Upms.SqlSugarCore/NPinFrameworkUpmsSqlSugarCoreModule.cs
create mode 100644 module/upms/NPin.Framework.Upms.SqlSugarCore/NPinUpmsDbContext.cs
diff --git a/NPin.sln b/NPin.sln
index 4ca8e51..bd3bfd2 100644
--- a/NPin.sln
+++ b/NPin.sln
@@ -46,8 +46,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NPin.SqlSugarCore", "src\NP
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "audit-logging", "audit-logging", "{29EA07EB-E1D2-4BCA-9EA4-D69E28F14978}"
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "upms", "upms", "{CA0606BE-4146-4390-86CD-AD92FC161A9E}"
-EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tenant-management", "tenant-management", "{FFB03EF5-B008-4F84-83D8-2F4B5D821251}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NPin.Framework.AuditLogging.Domain", "module\audit-logging\NPin.Framework.AuditLogging.Domain\NPin.Framework.AuditLogging.Domain.csproj", "{734EF33E-028A-44C3-B83F-13DBFA8AC117}"
@@ -64,6 +62,20 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NPin.Framework.TenantManage
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NPin.Framework.TenantManagement.SqlSugarCore", "module\tenant-management\NPin.Framework.TenantManagement.SqlSugarCore\NPin.Framework.TenantManagement.SqlSugarCore.csproj", "{9B6CAF84-D53C-4595-93B7-231E771FAED3}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "upms", "upms", "{39C0CC7B-2185-48C6-8D22-F54212CA36D4}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "code-gen", "code-gen", "{0FBD3B80-E61E-4797-9599-98E8884E5798}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NPin.Framework.Upms.Domain.Shared", "module\upms\NPin.Framework.Upms.Domain.Shared\NPin.Framework.Upms.Domain.Shared.csproj", "{23E194C3-B1E2-49C9-A145-DFD3CDE724AD}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NPin.Framework.Upms.Domain", "module\upms\NPin.Framework.Upms.Domain\NPin.Framework.Upms.Domain.csproj", "{C159A479-5020-4E8D-9377-6E2F6EA06396}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NPin.Framework.Upms.SqlSugarCore", "module\upms\NPin.Framework.Upms.SqlSugarCore\NPin.Framework.Upms.SqlSugarCore.csproj", "{786A1422-C4BD-4742-B33D-EBB82762CC63}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NPin.Framework.Upms.Application.Contracts", "module\upms\NPin.Framework.Upms.Application.Contracts\NPin.Framework.Upms.Application.Contracts.csproj", "{028A9FD0-3C94-45D6-9A4D-68BD4985B176}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NPin.Framework.Upms.Application", "module\upms\NPin.Framework.Upms.Application\NPin.Framework.Upms.Application.csproj", "{A48B3BDD-5996-438B-951A-09C52E595FCB}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -158,6 +170,26 @@ Global
{9B6CAF84-D53C-4595-93B7-231E771FAED3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9B6CAF84-D53C-4595-93B7-231E771FAED3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9B6CAF84-D53C-4595-93B7-231E771FAED3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {23E194C3-B1E2-49C9-A145-DFD3CDE724AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {23E194C3-B1E2-49C9-A145-DFD3CDE724AD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {23E194C3-B1E2-49C9-A145-DFD3CDE724AD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {23E194C3-B1E2-49C9-A145-DFD3CDE724AD}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C159A479-5020-4E8D-9377-6E2F6EA06396}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C159A479-5020-4E8D-9377-6E2F6EA06396}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C159A479-5020-4E8D-9377-6E2F6EA06396}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C159A479-5020-4E8D-9377-6E2F6EA06396}.Release|Any CPU.Build.0 = Release|Any CPU
+ {786A1422-C4BD-4742-B33D-EBB82762CC63}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {786A1422-C4BD-4742-B33D-EBB82762CC63}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {786A1422-C4BD-4742-B33D-EBB82762CC63}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {786A1422-C4BD-4742-B33D-EBB82762CC63}.Release|Any CPU.Build.0 = Release|Any CPU
+ {028A9FD0-3C94-45D6-9A4D-68BD4985B176}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {028A9FD0-3C94-45D6-9A4D-68BD4985B176}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {028A9FD0-3C94-45D6-9A4D-68BD4985B176}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {028A9FD0-3C94-45D6-9A4D-68BD4985B176}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A48B3BDD-5996-438B-951A-09C52E595FCB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A48B3BDD-5996-438B-951A-09C52E595FCB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A48B3BDD-5996-438B-951A-09C52E595FCB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A48B3BDD-5996-438B-951A-09C52E595FCB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{088B4948-AE5B-45B3-A9FA-B853671CFA05} = {F2A0A89E-A2F9-48CF-AD38-0318B5ACD11C}
@@ -176,7 +208,6 @@ Global
{C4D324BB-01B6-436F-9AA6-136C7D5438F6} = {86F61EBB-4ACC-459C-AB3C-C8D486C3017D}
{DC8E2E59-589F-4521-95E2-9CE7E1DD5541} = {86F61EBB-4ACC-459C-AB3C-C8D486C3017D}
{29EA07EB-E1D2-4BCA-9EA4-D69E28F14978} = {EEAD0AD4-0F90-46D9-A775-D88AE07E2869}
- {CA0606BE-4146-4390-86CD-AD92FC161A9E} = {EEAD0AD4-0F90-46D9-A775-D88AE07E2869}
{FFB03EF5-B008-4F84-83D8-2F4B5D821251} = {EEAD0AD4-0F90-46D9-A775-D88AE07E2869}
{734EF33E-028A-44C3-B83F-13DBFA8AC117} = {29EA07EB-E1D2-4BCA-9EA4-D69E28F14978}
{70685213-B0C0-4589-B9ED-A67838227705} = {29EA07EB-E1D2-4BCA-9EA4-D69E28F14978}
@@ -185,5 +216,12 @@ Global
{FAB3D7AE-2260-4DC1-B2BB-E26C540056BF} = {FFB03EF5-B008-4F84-83D8-2F4B5D821251}
{6F3DF341-F4BB-416A-8772-F68B4626C0C8} = {FFB03EF5-B008-4F84-83D8-2F4B5D821251}
{9B6CAF84-D53C-4595-93B7-231E771FAED3} = {FFB03EF5-B008-4F84-83D8-2F4B5D821251}
+ {39C0CC7B-2185-48C6-8D22-F54212CA36D4} = {EEAD0AD4-0F90-46D9-A775-D88AE07E2869}
+ {0FBD3B80-E61E-4797-9599-98E8884E5798} = {EEAD0AD4-0F90-46D9-A775-D88AE07E2869}
+ {23E194C3-B1E2-49C9-A145-DFD3CDE724AD} = {39C0CC7B-2185-48C6-8D22-F54212CA36D4}
+ {C159A479-5020-4E8D-9377-6E2F6EA06396} = {39C0CC7B-2185-48C6-8D22-F54212CA36D4}
+ {786A1422-C4BD-4742-B33D-EBB82762CC63} = {39C0CC7B-2185-48C6-8D22-F54212CA36D4}
+ {028A9FD0-3C94-45D6-9A4D-68BD4985B176} = {39C0CC7B-2185-48C6-8D22-F54212CA36D4}
+ {A48B3BDD-5996-438B-951A-09C52E595FCB} = {39C0CC7B-2185-48C6-8D22-F54212CA36D4}
EndGlobalSection
EndGlobal
diff --git a/framework/NPin.Framework.Core/Crypt/AES/AesCrypt.cs b/framework/NPin.Framework.Core/Crypt/AES/AesCrypt.cs
new file mode 100644
index 0000000..2150c25
--- /dev/null
+++ b/framework/NPin.Framework.Core/Crypt/AES/AesCrypt.cs
@@ -0,0 +1,84 @@
+using System.Security.Cryptography;
+using System.Text;
+
+namespace NPin.Framework.Core.Crypt.AES;
+
+public static class AesCrypt
+{
+ ///
+ /// 盐
+ ///
+ private const string Slat = "Q+OFqu]luparUP;Xn^_ktHX^FoWiK4C#;daRV(b1bbT_;HrrAL";
+
+ ///
+ /// 处理key
+ ///
+ /// 输入的密码
+ /// Key和IV模式
+ ///
+ private static Tuple GetAesKey(string pwd, AesKeyEnum model = AesKeyEnum.AES256)
+ {
+ var hash1 = $"{pwd}-{Slat}".Md5();
+ switch (model)
+ {
+ case AesKeyEnum.AES256:
+ {
+ var hash2 = $"{hash1}-{Slat}".Md5();
+ var hash3 = $"{hash2}-{Slat}".To16Md5();
+ var key = Encoding.UTF8.GetBytes($"{hash1}{hash2}".Md5());
+ var iv = Encoding.UTF8.GetBytes(hash3);
+ return new(key, iv);
+ }
+ case AesKeyEnum.AES128:
+ {
+ var hash2 = $"{hash1}-{Slat}".To16Md5();
+ var key = Encoding.UTF8.GetBytes(hash1);
+ var iv = Encoding.UTF8.GetBytes(hash2);
+ return new(key, iv);
+ }
+ default: throw new("不支持的类型");
+ }
+ }
+
+ ///
+ /// AES加密
+ ///
+ /// 待加密数据
+ /// 密钥
+ /// Aes密钥模式
+ /// 加密模式
+ /// 填充模式
+ ///
+ public static byte[] Encrypt(byte[] content, string pwd, AesKeyEnum model, CipherMode mode = CipherMode.CBC, PaddingMode padding = PaddingMode.PKCS7)
+ {
+ var (Key, IV) = GetAesKey(pwd, model);
+ using var aes = Aes.Create();
+ aes.Key = Key;
+ aes.IV = IV;
+ aes.Mode = mode;
+ aes.Padding = padding;
+ var cTransform = aes.CreateEncryptor();
+ return cTransform.TransformFinalBlock(content, 0, content.Length);
+ }
+
+ ///
+ /// AES解密
+ ///
+ /// 待解密数据
+ /// 密钥
+ /// Aes密钥模式
+ /// 加密模式
+ /// 填充模式
+ ///
+ public static byte[] Decrypt(byte[] secret, string pwd, AesKeyEnum model, CipherMode mode = CipherMode.CBC, PaddingMode padding = PaddingMode.PKCS7)
+ {
+ var (key, iv) = GetAesKey(pwd, model);
+ using var aes = Aes.Create();
+ aes.Key = key;
+ aes.IV = iv;
+ aes.Mode = mode;
+ aes.Padding = padding;
+ var cTransform = aes.CreateDecryptor();
+ return cTransform.TransformFinalBlock(secret, 0, secret.Length);
+ }
+}
\ No newline at end of file
diff --git a/framework/NPin.Framework.Core/Crypt/AES/AesKeyEnum.cs b/framework/NPin.Framework.Core/Crypt/AES/AesKeyEnum.cs
new file mode 100644
index 0000000..f038e1d
--- /dev/null
+++ b/framework/NPin.Framework.Core/Crypt/AES/AesKeyEnum.cs
@@ -0,0 +1,17 @@
+namespace NPin.Framework.Core.Crypt.AES;
+
+///
+/// AES加密的密钥算法模式
+///
+public enum AesKeyEnum
+{
+ ///
+ /// AES128
+ ///
+ AES128,
+
+ ///
+ /// AES256
+ ///
+ AES256
+}
\ No newline at end of file
diff --git a/framework/NPin.Framework.Core/Crypt/BCrypt/BCrypt.cs b/framework/NPin.Framework.Core/Crypt/BCrypt/BCrypt.cs
new file mode 100644
index 0000000..ac6e9f6
--- /dev/null
+++ b/framework/NPin.Framework.Core/Crypt/BCrypt/BCrypt.cs
@@ -0,0 +1,14 @@
+using System.Text;
+
+namespace NPin.Framework.Core.Crypt.BCrypt;
+
+public static class BCrypt
+{
+ public static byte[] Generate(string password, string salt, int cost)
+ {
+ var passBytes = Encoding.UTF8.GetBytes(password);
+ var saltBytes = Encoding.UTF8.GetBytes(salt);
+
+ return Org.BouncyCastle.Crypto.Generators.BCrypt.Generate(passBytes, saltBytes, cost);
+ }
+}
\ No newline at end of file
diff --git a/framework/NPin.Framework.Core/Crypt/DES/DesCrypt.cs b/framework/NPin.Framework.Core/Crypt/DES/DesCrypt.cs
new file mode 100644
index 0000000..09de010
--- /dev/null
+++ b/framework/NPin.Framework.Core/Crypt/DES/DesCrypt.cs
@@ -0,0 +1,77 @@
+using System.Security.Cryptography;
+using System.Text;
+
+namespace NPin.Framework.Core.Crypt.DES;
+
+///
+/// DES加密解密(由于本库对密钥进行了hash算法处理.使用本库加密仅能用本库解密)
+///
+public static class DesCrypt
+{
+ ///
+ /// 盐
+ ///
+ private const string Slat = "Fo~@Ymf3w-!K+hYYoI^emXJeNt79pv@Sy,rpl0vXyIa-^jI{fU";
+
+ ///
+ /// 处理key
+ ///
+ /// 输入的密码
+ ///
+ private static Tuple GetEesKey(string pwd)
+ {
+ var hash1 = $"{pwd}-{Slat}".Md5();
+ var hash2 = $"{hash1}-{Slat}".Md5();
+ var hash3 = $"{hash2}-{Slat}".To16Md5();
+ var key = Encoding.UTF8.GetBytes($"{hash1}{hash2}".To16Md5()[..8]);
+ var iv = Encoding.UTF8.GetBytes(hash3[..8]);
+ return new(key, iv);
+ }
+
+ ///
+ /// DES加密
+ ///
+ /// 待加密数据
+ /// 密钥
+ /// 加密模式
+ /// 填充模式
+ /// 加密后的数据
+ public static byte[] Encrypt(byte[] content, string pwd, CipherMode mode = CipherMode.CBC, PaddingMode padding = PaddingMode.PKCS7)
+ {
+ var (key, iv) = GetEesKey(pwd);
+
+ var des = System.Security.Cryptography.DES.Create();
+ des.Key = key;
+ des.IV = iv;
+ des.Mode = mode;
+ des.Padding = padding;
+ using var ms = new MemoryStream();
+ using var cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
+ cs.Write(content, 0, content.Length);
+ cs.FlushFinalBlock();
+ return ms.ToArray();
+ }
+
+ ///
+ /// DES解密字符串
+ ///
+ /// 待解密数据
+ /// 密钥
+ /// 加密模式
+ /// 填充模式
+ /// 解密后的字符串
+ public static byte[] Decrypt(byte[] secret, string pwd, CipherMode mode = CipherMode.CBC, PaddingMode padding = PaddingMode.PKCS7)
+ {
+ var (key, iv) = GetEesKey(pwd);
+ var des = System.Security.Cryptography.DES.Create();
+ des.Key = key;
+ des.IV = iv;
+ des.Mode = mode;
+ des.Padding = padding;
+ using var ms = new MemoryStream();
+ using var cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);
+ cs.Write(secret, 0, secret.Length);
+ cs.FlushFinalBlock();
+ return ms.ToArray();
+ }
+}
\ No newline at end of file
diff --git a/framework/NPin.Framework.Core/Crypt/DES/TripleDes.cs b/framework/NPin.Framework.Core/Crypt/DES/TripleDes.cs
new file mode 100644
index 0000000..d1c3da3
--- /dev/null
+++ b/framework/NPin.Framework.Core/Crypt/DES/TripleDes.cs
@@ -0,0 +1,73 @@
+using System.Security.Cryptography;
+using System.Text;
+
+namespace NPin.Framework.Core.Crypt.DES;
+
+public static class TripleDes
+{
+ ///
+ /// 盐
+ ///
+ private const string slat = "HosW[A1]ew0sVtVzf[DfQ~x%hk2+ifMlg;)Wsf[9@Fh{_z$jNC";
+
+ ///
+ /// 处理key
+ ///
+ /// 输入的密码
+ ///
+ private static Tuple GetEesKey(string pwd)
+ {
+ var hash1 = $"{pwd}-{slat}".Md5();
+ var hash2 = $"{hash1}-{slat}".Md5();
+ var hash3 = $"{hash2}-{slat}".To16Md5();
+ var Key = Encoding.UTF8.GetBytes($"{hash1}{hash2}".Md5()[..24]);
+ var IV = Encoding.UTF8.GetBytes(hash3[..8]);
+ return new(Key, IV);
+ }
+
+ ///
+ /// 使用给定密钥加密
+ ///
+ /// 待加密数据
+ /// 密钥
+ /// 加密模式
+ /// 填充模式
+ /// 加密后的数据
+ public static byte[] Encrypt(byte[] content, string pwd, CipherMode mode = CipherMode.CBC, PaddingMode padding = PaddingMode.PKCS7)
+ {
+ var (Key, IV) = GetEesKey(pwd);
+ var des = TripleDES.Create();
+ des.Key = Key;
+ des.IV = IV;
+ des.Mode = mode;
+ des.Padding = padding;
+ using var ms = new MemoryStream();
+ using var cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
+ cs.Write(content, 0, content.Length);
+ cs.FlushFinalBlock();
+ return ms.ToArray();
+ }
+
+ ///
+ /// 使用给定密钥解密数据
+ ///
+ /// 待解密数据
+ /// 密钥
+ /// 加密模式
+ /// 填充模式
+ /// 解密后的数据
+ public static byte[] Decrypt(byte[] secret, string pwd, CipherMode mode = CipherMode.CBC, PaddingMode padding = PaddingMode.PKCS7)
+ {
+ var (Key, IV) = GetEesKey(pwd);
+ var des = TripleDES.Create();
+ des.Key = Key;
+ des.IV = IV;
+ des.Mode = mode;
+ des.Padding = padding;
+ using var ms = new MemoryStream();
+ using var cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);
+ cs.Write(secret, 0, secret.Length);
+ cs.FlushFinalBlock();
+ return ms.ToArray();
+ }
+}
\ No newline at end of file
diff --git a/framework/NPin.Framework.Core/Crypt/Md5Extensions.cs b/framework/NPin.Framework.Core/Crypt/Md5Extensions.cs
new file mode 100644
index 0000000..6f38b5e
--- /dev/null
+++ b/framework/NPin.Framework.Core/Crypt/Md5Extensions.cs
@@ -0,0 +1,36 @@
+using System.Security.Cryptography;
+using System.Text;
+
+namespace NPin.Framework.Core.Crypt;
+
+public static class Md5Extensions
+{
+ ///
+ /// 获取16位长度的MD5大写字符串
+ /// 截取第 9~25 位
+ ///
+ ///
+ ///
+ public static string To16Md5(this string value) => value.Md5().Substring(8, 16);
+
+ ///
+ /// 获取32位长度的MD5大写字符串
+ ///
+ ///
+ ///
+ public static string Md5(this string value)
+ {
+ using var md5 = MD5.Create();
+
+ var inputBytes = Encoding.UTF8.GetBytes(value);
+ var hashBytes = md5.ComputeHash(inputBytes);
+
+ var sb = new StringBuilder();
+ foreach (var hash in hashBytes)
+ {
+ sb.Append(hash.ToString("X2"));
+ }
+
+ return sb.ToString();
+ }
+}
\ No newline at end of file
diff --git a/framework/NPin.Framework.Core/Crypt/RC4/Rc4Crypt.cs b/framework/NPin.Framework.Core/Crypt/RC4/Rc4Crypt.cs
new file mode 100644
index 0000000..19ed027
--- /dev/null
+++ b/framework/NPin.Framework.Core/Crypt/RC4/Rc4Crypt.cs
@@ -0,0 +1,48 @@
+namespace NPin.Framework.Core.Crypt.RC4;
+
+///
+/// RC4 加密解密
+///
+public static class Rc4Crypt
+{
+ ///
+ /// RC4解密
+ ///
+ /// 待解密数据
+ /// 密钥
+ ///
+ public static byte[] Decrypt(IEnumerable data, byte[] key) => Encrypt(data, key);
+
+ ///
+ /// RC4加密
+ ///
+ /// 待加密数据
+ /// 密钥
+ ///
+ public static byte[] Encrypt(IEnumerable data, byte[] key)
+ {
+ var s = EncryptInit(key);
+ var i = 0;
+ var j = 0;
+ return data.Select(b =>
+ {
+ i = (i + 1) & 255;
+ j = (j + s[i]) & 255;
+ Swap(s, i, j);
+ return (byte)(b ^ s[(s[i] + s[j]) & 255]);
+ }).ToArray();
+ }
+
+ private static byte[] EncryptInit(byte[] key)
+ {
+ var s = Enumerable.Range(0, 256).Select(i => (byte)i).ToArray();
+ for (int i = 0, j = 0; i < 256; i++)
+ {
+ j = (j + key[i % key.Length] + s[i]) & 255;
+ Swap(s, i, j);
+ }
+ return s;
+ }
+
+ private static void Swap(byte[] s, int i, int j) => (s[i], s[j]) = (s[j], s[i]);
+}
\ No newline at end of file
diff --git a/framework/NPin.Framework.Core/Crypt/README.md b/framework/NPin.Framework.Core/Crypt/README.md
new file mode 100644
index 0000000..cc782ad
--- /dev/null
+++ b/framework/NPin.Framework.Core/Crypt/README.md
@@ -0,0 +1,14 @@
+> 来自于[EasilyNET.Security](https://github.com/EasilyNET/EasilyNET/blob/main/src/EasilyNET.Security/README.md)的加密库封装
+
+一个.Net 中常用的加密算法的封装.降低加密解密的使用复杂度.
+
+- 目前有的算法:AES,DES,RC4,TripleDES,RSA,SM2,SM3,SM4
+- 支持 RSA XML 结构的 SecurityKey 和 Base64 格式的互转.
+- 本库不是去实现加密算法,而是基于.Net 提供的接口封装,为了方便使用
+- 未经测试的预测,若是遇到了解密乱码,可能是需要引入一个包.
+- 在主项目中添加 System.Text.Encoding.CodePages 库,并在程序入口处添加注册代码. Programe.cs
+
+```c#
+var builder = WebApplication.CreateBuilder(args);
+System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
+```
\ No newline at end of file
diff --git a/framework/NPin.Framework.Core/Crypt/RSA/RsaCrypt.cs b/framework/NPin.Framework.Core/Crypt/RSA/RsaCrypt.cs
new file mode 100644
index 0000000..5f93e94
--- /dev/null
+++ b/framework/NPin.Framework.Core/Crypt/RSA/RsaCrypt.cs
@@ -0,0 +1,178 @@
+using System.Security.Cryptography;
+using System.Text;
+
+namespace NPin.Framework.Core.Crypt.RSA;
+
+///
+/// RSA算法
+///
+public static class RsaCrypt
+{
+ ///
+ /// 创建RSA密钥对
+ ///
+ /// 密钥的大小,必须384位到16384位,增量为8
+ ///
+ public static RsaSecretKey GenerateKey(int keySize)
+ {
+ if (keySize is > 16384 or < 384 && keySize % 8 is not 0)
+ {
+ throw new ArgumentException("密钥的大小,必须384位到16384位,增量为8", nameof(keySize));
+ }
+
+ var rsa = new RSACryptoServiceProvider(keySize)
+ {
+ KeySize = keySize,
+ PersistKeyInCsp = false
+ };
+ return new()
+ {
+ PrivateKey = rsa.ToXmlString(true),
+ PublicKey = rsa.ToXmlString(false)
+ };
+ }
+
+ ///
+ /// 创建RSA密钥对
+ ///
+ /// 密钥的大小,提供常用长度枚举
+ ///
+ public static RsaSecretKey GenerateKey(RsaKeyLength keySize) => GenerateKey((int)keySize);
+
+ ///
+ /// 使用RSA的加密byte[](该方法存在长度限制)
+ ///
+ /// 当前RSA对象的密匙XML字符串(不包括专用参数)--公钥
+ /// 需要进行加密的字节数组
+ /// 加密后的数据
+ public static byte[] Encrypt(string xmlPublicKey, byte[] content)
+ {
+ using var rsa = new RSACryptoServiceProvider();
+ rsa.FromXmlString(xmlPublicKey);
+ return rsa.Encrypt(content, false);
+ }
+
+ ///
+ /// RSA解密byte[](该方法存在长度限制)
+ ///
+ /// 当前RSA对象的密匙XML字符串(包括专用参数)--私钥
+ /// 需要进行解密的字节数组
+ /// 解密后的字符串
+ public static byte[] Decrypt(string xmlPrivateKey, byte[] secret)
+ {
+ using var rsa = new RSACryptoServiceProvider();
+ rsa.FromXmlString(xmlPrivateKey);
+ return rsa.Decrypt(secret, false);
+ }
+
+ ///
+ /// RSA加密 不限长度的加密版本
+ ///
+ /// 公匙
+ /// 需要进行加密的数据
+ /// 加密后的数据
+ public static void Encrypt(string xmlPublicKey, byte[] content, out byte[] secret)
+ {
+ if (content.Length is 0) throw new("加密字符串不能为空.");
+ ArgumentException.ThrowIfNullOrEmpty(xmlPublicKey, nameof(xmlPublicKey));
+ using var rsaProvider = new RSACryptoServiceProvider();
+ rsaProvider.FromXmlString(xmlPublicKey); //载入公钥
+ var bufferSize = (rsaProvider.KeySize >> 3) - 11; //单块最大长度
+ var buffer = new byte[bufferSize];
+ using MemoryStream ms = new(content), os = new();
+ while (true)
+ {
+ //分段加密
+ var readSize = ms.Read(buffer, 0, bufferSize);
+ if (readSize <= 0) break;
+ var temp = new byte[readSize];
+ Array.Copy(buffer, 0, temp, 0, readSize);
+ var encryptedBytes = rsaProvider.Encrypt(temp, false);
+ os.Write(encryptedBytes, 0, encryptedBytes.Length);
+ }
+
+ secret = os.ToArray(); //转化为字节流方便传输
+ }
+
+ ///
+ /// RSA解密 不限长度的解密版本
+ ///
+ /// 私匙
+ /// 需要进行解密的数据
+ /// 解密后的数据
+ public static void Decrypt(string xmlPrivateKey, byte[] secret, out byte[] context)
+ {
+ if (secret.Length is 0) throw new("解密字符串不能为空.");
+ ArgumentException.ThrowIfNullOrEmpty(xmlPrivateKey, nameof(xmlPrivateKey));
+ using var rsaProvider = new RSACryptoServiceProvider();
+ rsaProvider.FromXmlString(xmlPrivateKey);
+ var bufferSize = rsaProvider.KeySize >> 3;
+ var buffer = new byte[bufferSize];
+ using MemoryStream ms = new(secret), os = new();
+ while (true)
+ {
+ var readSize = ms.Read(buffer, 0, bufferSize);
+ if (readSize <= 0) break;
+ var temp = new byte[readSize];
+ Array.Copy(buffer, 0, temp, 0, readSize);
+ var rawBytes = rsaProvider.Decrypt(temp, false);
+ os.Write(rawBytes, 0, rawBytes.Length);
+ }
+
+ context = os.ToArray();
+ }
+
+ ///
+ /// 从文件中取得SHA256描述信息
+ ///
+ ///
+ ///
+ public static string GetFileSHA256(FileStream objFile)
+ {
+ ArgumentNullException.ThrowIfNull(objFile, nameof(objFile));
+ using var stream = new MemoryStream();
+ objFile.CopyTo(stream);
+ var bytes = stream.ToArray();
+ var array = SHA256.HashData(bytes);
+ objFile.Close();
+ return Encoding.UTF8.GetString(array);
+ }
+
+ #region RSA签名与签名验证
+
+ ///
+ /// RSA签名
+ ///
+ /// 当前RSA对象的密匙XML字符串(包括专用参数)--私钥
+ /// 需要签名的数据
+ /// 签名数据
+ public static byte[] Signature(string xmlPrivateKey, byte[] context)
+ {
+ using var rsa = new RSACryptoServiceProvider();
+ rsa.FromXmlString(xmlPrivateKey);
+ var rsaFormatter = new RSAPKCS1SignatureFormatter(rsa);
+ //设置签名的算法为SHA256
+ rsaFormatter.SetHashAlgorithm("SHA256");
+ //执行签名
+ return rsaFormatter.CreateSignature(context);
+ }
+
+ ///
+ /// RSA 签名验证
+ ///
+ /// 当前RSA对象的密匙XML字符串(不包括专用参数)--公钥
+ /// 用RSA签名的数据[俗称:Hash描述字符串,即:MD5或者SHA256这种.本库使用SHA256]
+ /// 要为该数据验证的已签名数据
+ /// 如果 Verification 与使用指定的哈希算法和密钥在 signature 上计算出的签名匹配,则为 ;否则为 .
+ public static bool Verification(string xmlPublicKey, byte[] secret, byte[] signature)
+ {
+ using var rsa = new RSACryptoServiceProvider();
+ rsa.FromXmlString(xmlPublicKey);
+ var formatter = new RSAPKCS1SignatureDeformatter(rsa);
+ //指定解密的时候HASH算法为SHA256
+ formatter.SetHashAlgorithm("SHA256");
+ return formatter.VerifySignature(secret, signature);
+ }
+
+ #endregion
+}
\ No newline at end of file
diff --git a/framework/NPin.Framework.Core/Crypt/RSA/RsaKeyConverter.cs b/framework/NPin.Framework.Core/Crypt/RSA/RsaKeyConverter.cs
new file mode 100644
index 0000000..7bb3008
--- /dev/null
+++ b/framework/NPin.Framework.Core/Crypt/RSA/RsaKeyConverter.cs
@@ -0,0 +1,89 @@
+using System.Security.Cryptography;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Pkcs;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.X509;
+
+namespace NPin.Framework.Core.Crypt.RSA;
+
+///
+/// RSAKey转化扩展类,用于将XML格式和Base64这种互转.如C#和Java的编码就不一样.
+///
+public static class RsaKeyConverter
+{
+ ///
+ /// XML私钥 👉 Base64私钥
+ ///
+ /// XML私钥
+ /// Base64私钥
+ public static string ToBase64PrivateKey(string xmlPrivate)
+ {
+ using var rsa = new RSACryptoServiceProvider();
+ rsa.FromXmlString(xmlPrivate);
+ var param = rsa.ExportParameters(true);
+ var privateKeyParam = new RsaPrivateCrtKeyParameters(new(1, param.Modulus), new(1, param.Exponent),
+ new(1, param.D), new(1, param.P),
+ new(1, param.Q), new(1, param.DP),
+ new(1, param.DQ), new(1, param.InverseQ));
+ var privateKey = PrivateKeyInfoFactory.CreatePrivateKeyInfo(privateKeyParam);
+ return Convert.ToBase64String(privateKey.ToAsn1Object().GetEncoded());
+ }
+
+ ///
+ /// XML公钥 👉 Base64公钥
+ ///
+ /// XML公钥
+ /// Base64公钥
+ public static string ToBase64PublicKey(string xmlPublic)
+ {
+ using var rsa = new RSACryptoServiceProvider();
+ rsa.FromXmlString(xmlPublic);
+ var p = rsa.ExportParameters(false);
+ var keyParams = new RsaKeyParameters(false, new(1, p.Modulus), new(1, p.Exponent));
+ var publicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(keyParams);
+ return Convert.ToBase64String(publicKeyInfo.ToAsn1Object().GetEncoded());
+ }
+
+ ///
+ /// Base64私钥 👉 XML私钥
+ ///
+ /// Base64私钥
+ /// XML私钥
+ public static string ToXmlPrivateKey(string base64Private)
+ {
+ var privateKeyParams =
+ (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(base64Private));
+ using var rsa = new RSACryptoServiceProvider();
+ var rsaParams = new RSAParameters
+ {
+ Modulus = privateKeyParams.Modulus.ToByteArrayUnsigned(),
+ Exponent = privateKeyParams.PublicExponent.ToByteArrayUnsigned(),
+ D = privateKeyParams.Exponent.ToByteArrayUnsigned(),
+ DP = privateKeyParams.DP.ToByteArrayUnsigned(),
+ DQ = privateKeyParams.DQ.ToByteArrayUnsigned(),
+ P = privateKeyParams.P.ToByteArrayUnsigned(),
+ Q = privateKeyParams.Q.ToByteArrayUnsigned(),
+ InverseQ = privateKeyParams.QInv.ToByteArrayUnsigned()
+ };
+ rsa.ImportParameters(rsaParams);
+ return rsa.ToXmlString(true);
+ }
+
+ ///
+ /// Base64公钥 👉 XML公钥
+ ///
+ /// Base64公钥
+ /// XML公钥
+ public static string ToXmlPublicKey(string base64Public)
+ {
+ var p = (RsaKeyParameters)PublicKeyFactory.CreateKey(Convert.FromBase64String(base64Public));
+ using var rsa = new RSACryptoServiceProvider();
+ var rsaParams = new RSAParameters
+ {
+ Modulus = p.Modulus.ToByteArrayUnsigned(),
+ Exponent = p.Exponent.ToByteArrayUnsigned()
+ };
+ rsa.ImportParameters(rsaParams);
+ return rsa.ToXmlString(false);
+ }
+}
\ No newline at end of file
diff --git a/framework/NPin.Framework.Core/Crypt/RSA/RsaKeyLength.cs b/framework/NPin.Framework.Core/Crypt/RSA/RsaKeyLength.cs
new file mode 100644
index 0000000..280b361
--- /dev/null
+++ b/framework/NPin.Framework.Core/Crypt/RSA/RsaKeyLength.cs
@@ -0,0 +1,27 @@
+namespace NPin.Framework.Core.Crypt.RSA;
+
+///
+/// RSA 密钥长度
+///
+public enum RsaKeyLength
+{
+ ///
+ /// 512 bit
+ ///
+ Bit512 = 512,
+
+ ///
+ /// 1024 bit
+ ///
+ Bit1024 = 1024,
+
+ ///
+ /// 2048 bit
+ ///
+ Bit2048 = 2048,
+
+ ///
+ /// 4096 bit
+ ///
+ Bit4096 = 4096
+}
\ No newline at end of file
diff --git a/framework/NPin.Framework.Core/Crypt/RSA/RsaSecretKey.cs b/framework/NPin.Framework.Core/Crypt/RSA/RsaSecretKey.cs
new file mode 100644
index 0000000..3c60fe6
--- /dev/null
+++ b/framework/NPin.Framework.Core/Crypt/RSA/RsaSecretKey.cs
@@ -0,0 +1,49 @@
+namespace NPin.Framework.Core.Crypt.RSA;
+
+///
+/// RSA密钥 结构体
+///
+///
+///
+public struct RsaSecretKey(string privateKey, string publicKey)
+{
+ ///
+ /// 公钥
+ ///
+ public string PublicKey { get; set; } = publicKey;
+
+ ///
+ /// 私钥
+ ///
+ public string PrivateKey { get; set; } = privateKey;
+
+ ///
+ /// 得到XML格式的私钥和公钥
+ ///
+ ///
+ public readonly string ToXmlString() =>
+ $"""
+ -----BEGIN RSA XML PRIVATE KEY-----
+ {PrivateKey}
+ -----END RSA XML PRIVATE KEY-----
+
+ -----BEGIN RSA XML PUBLIC KEY-----
+ {PublicKey}
+ -----END RSA XML PUBLIC KEY-----
+ """;
+
+ ///
+ /// 得到Base64格式的私钥和公钥
+ ///
+ ///
+ public readonly string ToBase64String() =>
+ $"""
+ -----BEGIN RSA BASE64 PRIVATE KEY-----
+ {RsaKeyConverter.ToBase64PrivateKey(PrivateKey)}
+ -----END RSA BASE64 PRIVATE KEY-----
+
+ -----BEGIN RSA BASE64 PUBLIC KEY-----
+ {RsaKeyConverter.ToBase64PublicKey(PublicKey)}
+ -----END RSA BASE64 PUBLIC KEY-----
+ """;
+}
\ No newline at end of file
diff --git a/framework/NPin.Framework.Core/Crypt/SM2/Sm2Crypt.cs b/framework/NPin.Framework.Core/Crypt/SM2/Sm2Crypt.cs
new file mode 100644
index 0000000..fd4bd0f
--- /dev/null
+++ b/framework/NPin.Framework.Core/Crypt/SM2/Sm2Crypt.cs
@@ -0,0 +1,157 @@
+using Org.BouncyCastle.Asn1.GM;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Signers;
+
+namespace NPin.Framework.Core.Crypt.SM2;
+
+///
+/// BouncyCastle(BC) 实现SM2国密加解密、签名、验签
+///
+public static class Sm2Crypt
+{
+ private static readonly X9ECParameters X9 = GMNamedCurves.GetByName("SM2P256V1");
+
+ ///
+ /// 构建公钥和私钥
+ ///
+ ///
+ ///
+ public static void GenerateKey(out byte[] publicKey, out byte[] privateKey)
+ {
+ var g = new ECKeyPairGenerator();
+ g.Init(new ECKeyGenerationParameters(new ECDomainParameters(X9), new()));
+ var k = g.GenerateKeyPair();
+ publicKey = ((ECPublicKeyParameters)k.Public).Q.GetEncoded(false);
+ privateKey = ((ECPrivateKeyParameters)k.Private).D.ToByteArray();
+ }
+
+ ///
+ /// SM2加密,默认:C1C3C2
+ ///
+ /// 公钥
+ /// 需要加密的数据
+ /// 模式
+ /// 用户ID
+ ///
+ public static byte[] Encrypt(byte[] publicKey, byte[] data, byte[]? userId = null,
+ SM2Engine.Mode model = SM2Engine.Mode.C1C3C2)
+ {
+ var sm2 = new SM2Engine(new SM3Digest(), SM2Engine.Mode.C1C3C2);
+ ICipherParameters cp =
+ new ParametersWithRandom(new ECPublicKeyParameters(X9.Curve.DecodePoint(publicKey), new(X9)));
+ if (userId is not null)
+ {
+ cp = new ParametersWithID(cp, userId);
+ }
+
+ sm2.Init(true, cp);
+ data = sm2.ProcessBlock(data, 0, data.Length);
+ if (model == SM2Engine.Mode.C1C2C3) data = C132ToC123(data);
+ return data;
+ }
+
+ ///
+ /// SM2解密,默认:C1C3C2
+ ///
+ /// 私钥
+ /// 需要解密的数据
+ /// 模式
+ /// 用户ID
+ ///
+ public static byte[] Decrypt(byte[] privateKey, byte[] data, byte[]? userId = null,
+ SM2Engine.Mode model = SM2Engine.Mode.C1C3C2)
+ {
+ if (model == SM2Engine.Mode.C1C2C3) data = C123ToC132(data);
+ var sm2 = new SM2Engine(new SM3Digest(), SM2Engine.Mode.C1C3C2);
+ ICipherParameters cp = new ECPrivateKeyParameters(new(1, privateKey), new(X9));
+ if (userId is not null)
+ {
+ cp = new ParametersWithID(cp, userId);
+ }
+
+ sm2.Init(false, cp);
+ return sm2.ProcessBlock(data, 0, data.Length);
+ }
+
+ ///
+ /// SM2签名
+ ///
+ /// 私钥
+ /// 数据
+ /// 用户ID
+ ///
+ public static byte[] Signature(byte[] privateKey, byte[] msg, byte[]? userId = null)
+ {
+ var sm2 = new SM2Signer(new SM3Digest());
+ // var sm2 = new SM2Signer(StandardDsaEncoding.Instance, new SM3Digest());
+ // var sm2 = new SM2Signer(PlainDsaEncoding.Instance, new SM3Digest());
+ ICipherParameters cp = new ParametersWithRandom(new ECPrivateKeyParameters(new(1, privateKey), new(X9)));
+ if (userId is not null)
+ {
+ cp = new ParametersWithID(cp, userId);
+ }
+
+ sm2.Init(true, cp);
+ sm2.BlockUpdate(msg, 0, msg.Length);
+ return sm2.GenerateSignature();
+ }
+
+ ///
+ /// SM2验签
+ ///
+ /// 公钥
+ /// 数据
+ /// 签名数据
+ /// 用户ID
+ ///
+ public static bool Verify(byte[] publicKey, byte[] msg, byte[] signature, byte[]? userId = null)
+ {
+ var sm2 = new SM2Signer(new SM3Digest());
+ ICipherParameters cp = new ECPublicKeyParameters(X9.Curve.DecodePoint(publicKey), new(X9));
+ if (userId is not null)
+ {
+ cp = new ParametersWithID(cp, userId);
+ }
+
+ sm2.Init(false, cp);
+ sm2.BlockUpdate(msg, 0, msg.Length);
+ return sm2.VerifySignature(signature);
+ }
+
+ ///
+ /// C1C2C3转成C1C3C2
+ ///
+ ///
+ ///
+ private static byte[] C123ToC132(byte[] c1c2c3)
+ {
+ var c1Len = (((X9.Curve.FieldSize + 7) >> 3) << 1) + 1; //sm2p256v1的这个固定65。可看GMNamedCurves、ECCurve代码。
+ const int c3Len = 32;
+ var result = new byte[c1c2c3.Length];
+ Array.Copy(c1c2c3, 0, result, 0, c1Len); //c1
+ Array.Copy(c1c2c3, c1c2c3.Length - c3Len, result, c1Len, c3Len); //c3
+ Array.Copy(c1c2c3, c1Len, result, c1Len + c3Len, c1c2c3.Length - c1Len - c3Len); //c2
+ return result;
+ }
+
+ ///
+ /// C1C3C2转成C1C2C3
+ ///
+ ///
+ ///
+ private static byte[] C132ToC123(byte[] c1c3c2)
+ {
+ var c1Len = (((X9.Curve.FieldSize + 7) >> 3) << 1) + 1;
+ const int c3Len = 32;
+ var result = new byte[c1c3c2.Length];
+ Array.Copy(c1c3c2, 0, result, 0, c1Len); //c1: 0->65
+ Array.Copy(c1c3c2, c1Len + c3Len, result, c1Len, c1c3c2.Length - c1Len - c3Len); //c2
+ Array.Copy(c1c3c2, c1Len, result, c1c3c2.Length - c3Len, c3Len); //c3
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/framework/NPin.Framework.Core/Crypt/SM3/Sm3Crypt.cs b/framework/NPin.Framework.Core/Crypt/SM3/Sm3Crypt.cs
new file mode 100644
index 0000000..70392e2
--- /dev/null
+++ b/framework/NPin.Framework.Core/Crypt/SM3/Sm3Crypt.cs
@@ -0,0 +1,37 @@
+using System.Text;
+using Org.BouncyCastle.Crypto.Digests;
+
+namespace NPin.Framework.Core.Crypt.SM3;
+
+///
+/// SM3算法(10进制的ASCII)
+/// 在SHA-256基础上改进实现的一种算法
+/// 对标国际MD5算法和SHA算法
+///
+public static class Sm3Crypt
+{
+ ///
+ /// 获取字符串的SM3签名
+ ///
+ ///
+ ///
+ public static byte[] Signature(string data)
+ {
+ var msg = Encoding.UTF8.GetBytes(data);
+ return Signature(msg);
+ }
+
+ ///
+ /// 获取字节数组的SM3签名
+ ///
+ ///
+ ///
+ public static byte[] Signature(byte[] data)
+ {
+ var md = new byte[32];
+ var sm3 = new SM3Digest();
+ sm3.BlockUpdate(data, 0, data.Length);
+ sm3.DoFinal(md, 0);
+ return md;
+ }
+}
\ No newline at end of file
diff --git a/framework/NPin.Framework.Core/Crypt/SM4/Sm4.cs b/framework/NPin.Framework.Core/Crypt/SM4/Sm4.cs
new file mode 100644
index 0000000..0769a62
--- /dev/null
+++ b/framework/NPin.Framework.Core/Crypt/SM4/Sm4.cs
@@ -0,0 +1,323 @@
+namespace NPin.Framework.Core.Crypt.SM4;
+
+internal sealed class Sm4
+{
+ ///
+ /// 固定参数CK
+ ///
+ private readonly uint[] CK =
+ [
+ 0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
+ 0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
+ 0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,
+ 0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
+ 0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,
+ 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
+ 0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,
+ 0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279
+ ];
+
+ ///
+ /// 系统参数FK
+ ///
+ private readonly uint[] FK = [0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc];
+
+ ///
+ /// S盒
+ ///
+ private readonly byte[] SBoxTable =
+ [
+ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f*/
+ /*0*/ 0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05,
+ /*1*/ 0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,
+ /*2*/ 0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62,
+ /*3*/ 0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6,
+ /*4*/ 0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8,
+ /*5*/ 0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35,
+ /*6*/ 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87,
+ /*7*/ 0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e,
+ /*8*/ 0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1,
+ /*9*/ 0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3,
+ /*a*/ 0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f,
+ /*b*/ 0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51,
+ /*c*/ 0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8,
+ /*d*/ 0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0,
+ /*e*/ 0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84,
+ /*f*/ 0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48
+ ];
+
+ ///
+ /// 加密 非线性τ函数B=τ(A)
+ ///
+ ///
+ ///
+ ///
+ private static long GetULongByBe(byte[] b, int i) => ((long)(b[i] & 0xff) << 24) | (uint)((b[i + 1] & 0xff) << 16) | (uint)((b[i + 2] & 0xff) << 8) | (b[i + 3] & 0xff & 0xffffffffL);
+
+ ///
+ /// 解密 非线性τ函数B=τ(A)
+ ///
+ ///
+ ///
+ ///
+ private static void PutULongToBe(long n, byte[] b, int i)
+ {
+ b[i] = (byte)(int)(0xFF & (n >> 24));
+ b[i + 1] = (byte)(int)(0xFF & (n >> 16));
+ b[i + 2] = (byte)(int)(0xFF & (n >> 8));
+ b[i + 3] = (byte)(int)(0xFF & n);
+ }
+
+ private static long SHL(long x, int n) => (x & 0xFFFFFFFF) << n;
+
+ ///
+ /// 循环移位,为32位的x循环左移n位
+ ///
+ ///
+ ///
+ ///
+ private static long RotL(long x, int n) => SHL(x, n) | (x >> (32 - n));
+
+ ///
+ /// 将密钥逆序
+ ///
+ ///
+ ///
+ private static void Swap(long[] sk, int i) => (sk[i], sk[31 - i]) = (sk[31 - i], sk[i]);
+
+ ///
+ /// Sm4的S盒取值
+ ///
+ ///
+ ///
+ private byte SBox(byte inch) => SBoxTable[inch & 0xFF];
+
+ ///
+ /// 线性变换 L
+ ///
+ ///
+ ///
+ private long Lt(long ka)
+ {
+ var a = new byte[4];
+ var b = new byte[4];
+ PutULongToBe(ka, a, 0);
+ b[0] = SBox(a[0]);
+ b[1] = SBox(a[1]);
+ b[2] = SBox(a[2]);
+ b[3] = SBox(a[3]);
+ var bb = GetULongByBe(b, 0);
+ return bb ^ RotL(bb, 2) ^ RotL(bb, 10) ^ RotL(bb, 18) ^ RotL(bb, 24);
+ }
+
+ ///
+ /// 轮函数 F
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ private long F(long x0, long x1, long x2, long x3, long rk) => x0 ^ Lt(x1 ^ x2 ^ x3 ^ rk);
+
+ ///
+ /// 轮密钥rk
+ ///
+ ///
+ ///
+ private long CalcRK(long ka)
+ {
+ var a = new byte[4];
+ var b = new byte[4];
+ PutULongToBe(ka, a, 0);
+ b[0] = SBox(a[0]);
+ b[1] = SBox(a[1]);
+ b[2] = SBox(a[2]);
+ b[3] = SBox(a[3]);
+ var bb = GetULongByBe(b, 0);
+ return bb ^ RotL(bb, 13) ^ RotL(bb, 23);
+ }
+
+ ///
+ /// 加密密钥
+ ///
+ ///
+ ///
+ private void SetKey(long[] SK, byte[] key)
+ {
+ var MK = new long[4];
+ var k = new long[36];
+ var i = 0;
+ MK[0] = GetULongByBe(key, 0);
+ MK[1] = GetULongByBe(key, 4);
+ MK[2] = GetULongByBe(key, 8);
+ MK[3] = GetULongByBe(key, 12);
+ k[0] = MK[0] ^ FK[0];
+ k[1] = MK[1] ^ FK[1];
+ k[2] = MK[2] ^ FK[2];
+ k[3] = MK[3] ^ FK[3];
+ for (; i < 32; i++)
+ {
+ k[i + 4] = k[i] ^ CalcRK(k[i + 1] ^ k[i + 2] ^ k[i + 3] ^ CK[i]);
+ SK[i] = k[i + 4];
+ }
+ }
+
+ ///
+ /// 解密函数
+ ///
+ /// 轮密钥
+ /// 输入分组的密文
+ /// 输出的对应的分组明文
+ private void OneRound(long[] sk, byte[] input, byte[] output)
+ {
+ var i = 0;
+ var ul_buf = new long[36];
+ ul_buf[0] = GetULongByBe(input, 0);
+ ul_buf[1] = GetULongByBe(input, 4);
+ ul_buf[2] = GetULongByBe(input, 8);
+ ul_buf[3] = GetULongByBe(input, 12);
+ while (i < 32)
+ {
+ ul_buf[i + 4] = F(ul_buf[i], ul_buf[i + 1], ul_buf[i + 2], ul_buf[i + 3], sk[i]);
+ i++;
+ }
+ PutULongToBe(ul_buf[35], output, 0);
+ PutULongToBe(ul_buf[34], output, 4);
+ PutULongToBe(ul_buf[33], output, 8);
+ PutULongToBe(ul_buf[32], output, 12);
+ }
+
+ ///
+ /// 补足 16 进制字符串的 0 字符,返回不带 0x 的16进制字符串
+ ///
+ ///
+ /// 1表示加密,0表示解密
+ ///
+ private static byte[] Padding(byte[] input, Sm4Mode mode)
+ {
+ byte[] ret;
+ if (mode is Sm4Mode.Encrypt)
+ {
+ var p = 16 - input.Length % 16;
+ ret = new byte[input.Length + p];
+ Array.Copy(input, 0, ret, 0, input.Length);
+ for (var i = 0; i < p; i++)
+ {
+ ret[input.Length + i] = (byte)p;
+ }
+ }
+ else
+ {
+ int p = input[^1];
+ ret = new byte[input.Length - p];
+ Array.Copy(input, 0, ret, 0, input.Length - p);
+ }
+ return ret;
+ }
+
+ ///
+ /// 设置加密的key
+ ///
+ ///
+ ///
+ internal void SetKeyEnc(Sm4Context ctx, byte[] key)
+ {
+ ctx.Mode = Sm4Mode.Encrypt;
+ SetKey(ctx.Key, key);
+ }
+
+ ///
+ /// 设置解密的key
+ ///
+ ///
+ ///
+ internal void SetKeyDec(Sm4Context ctx, byte[] key)
+ {
+ ctx.Mode = Sm4Mode.Decrypt;
+ SetKey(ctx.Key, key);
+ for (var i = 0; i < 16; i++)
+ {
+ Swap(ctx.Key, i);
+ }
+ }
+
+ internal byte[] ECB(Sm4Context ctx, byte[] input)
+ {
+ if (ctx is { IsPadding: true, Mode: Sm4Mode.Encrypt })
+ {
+ input = Padding(input, Sm4Mode.Encrypt);
+ }
+ var length = input.Length;
+ var bins = new byte[length];
+ Array.Copy(input, 0, bins, 0, length);
+ var bous = new byte[length];
+ for (var i = 0; length > 0; length -= 16, i++)
+ {
+ var inBytes = new byte[16];
+ var outBytes = new byte[16];
+ Array.Copy(bins, i * 16, inBytes, 0, length > 16 ? 16 : length);
+ OneRound(ctx.Key, inBytes, outBytes);
+ Array.Copy(outBytes, 0, bous, i * 16, length > 16 ? 16 : length);
+ }
+ if (ctx is { IsPadding: true, Mode: Sm4Mode.Decrypt })
+ {
+ bous = Padding(bous, Sm4Mode.Decrypt);
+ }
+ return bous;
+ }
+
+ internal byte[] CBC(Sm4Context ctx, byte[] iv, byte[] input)
+ {
+ if (ctx is { IsPadding: true, Mode: Sm4Mode.Encrypt }) input = Padding(input, Sm4Mode.Encrypt);
+ var length = input.Length;
+ var bins = new byte[length];
+ Array.Copy(input, 0, bins, 0, length);
+ var bousList = new List();
+ int i;
+ if (ctx.Mode is Sm4Mode.Encrypt)
+ {
+ for (var j = 0; length > 0; length -= 16, j++)
+ {
+ var inBytes = new byte[16];
+ var outBytes = new byte[16];
+ var out1 = new byte[16];
+ Array.Copy(bins, j * 16, inBytes, 0, length > 16 ? 16 : length);
+ for (i = 0; i < 16; i++)
+ {
+ outBytes[i] = (byte)(inBytes[i] ^ iv[i]);
+ }
+ OneRound(ctx.Key, outBytes, out1);
+ Array.Copy(out1, 0, iv, 0, 16);
+ for (var k = 0; k < 16; k++)
+ {
+ bousList.Add(out1[k]);
+ }
+ }
+ }
+ else
+ {
+ var temp = new byte[16];
+ for (var j = 0; length > 0; length -= 16, j++)
+ {
+ var inBytes = new byte[16];
+ var outBytes = new byte[16];
+ var out1 = new byte[16];
+ Array.Copy(bins, j * 16, inBytes, 0, length > 16 ? 16 : length);
+ Array.Copy(inBytes, 0, temp, 0, 16);
+ OneRound(ctx.Key, inBytes, outBytes);
+ for (i = 0; i < 16; i++)
+ {
+ out1[i] = (byte)(outBytes[i] ^ iv[i]);
+ }
+ Array.Copy(temp, 0, iv, 0, 16);
+ for (var k = 0; k < 16; k++)
+ {
+ bousList.Add(out1[k]);
+ }
+ }
+ }
+ return ctx is { IsPadding: true, Mode: Sm4Mode.Decrypt } ? Padding(bousList.ToArray(), Sm4Mode.Decrypt) : bousList.ToArray();
+ }
+}
\ No newline at end of file
diff --git a/framework/NPin.Framework.Core/Crypt/SM4/Sm4Context.cs b/framework/NPin.Framework.Core/Crypt/SM4/Sm4Context.cs
new file mode 100644
index 0000000..d234d0d
--- /dev/null
+++ b/framework/NPin.Framework.Core/Crypt/SM4/Sm4Context.cs
@@ -0,0 +1,19 @@
+namespace NPin.Framework.Core.Crypt.SM4;
+
+internal sealed class Sm4Context
+{
+ ///
+ /// 是否补足16进制字符串
+ ///
+ internal bool IsPadding { get; set; } = true;
+
+ ///
+ /// 加密或者解密
+ ///
+ internal Sm4Mode Mode { get; set; } = Sm4Mode.Encrypt;
+
+ ///
+ /// 密钥
+ ///
+ internal long[] Key { get; } = new long[32];
+}
\ No newline at end of file
diff --git a/framework/NPin.Framework.Core/Crypt/SM4/Sm4Crypt.cs b/framework/NPin.Framework.Core/Crypt/SM4/Sm4Crypt.cs
new file mode 100644
index 0000000..f6b0ce4
--- /dev/null
+++ b/framework/NPin.Framework.Core/Crypt/SM4/Sm4Crypt.cs
@@ -0,0 +1,116 @@
+using System.Text;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace NPin.Framework.Core.Crypt.SM4;
+
+///
+/// SM4 加解密
+///
+public static class Sm4Crypt
+{
+ ///
+ /// 加密ECB模式
+ ///
+ /// 密钥
+ /// 密钥是否是十六进制
+ /// 二进制格式加密的内容
+ /// 返回二进制格式密文
+ public static byte[] EncryptECB(string secretKey, bool hexString, byte[] plainText)
+ {
+ var ctx = new Sm4Context
+ {
+ IsPadding = true,
+ Mode = Sm4Mode.Encrypt
+ };
+ var keyBytes = hexString ? Hex.Decode(secretKey) : Encoding.UTF8.GetBytes(secretKey);
+ var sm4 = new Sm4();
+ sm4.SetKeyEnc(ctx, keyBytes);
+ return sm4.ECB(ctx, plainText);
+ }
+
+ ///
+ /// 解密ECB模式
+ ///
+ /// 密钥
+ /// 密钥是否是十六进制
+ /// 二进制格式密文
+ /// 二进制格式明文
+ public static byte[] DecryptECB(string secretKey, bool hexString, byte[] cipherBytes)
+ {
+ var ctx = new Sm4Context
+ {
+ IsPadding = true,
+ Mode = Sm4Mode.Decrypt
+ };
+ var keyBytes = hexString ? Hex.Decode(secretKey) : Encoding.UTF8.GetBytes(secretKey);
+ var sm4 = new Sm4();
+ sm4.SetKeyDec(ctx, keyBytes);
+ return sm4.ECB(ctx, cipherBytes);
+ }
+
+ ///
+ /// 加密CBC模式
+ ///
+ /// 密钥
+ /// 密钥和IV是否是十六进制
+ ///
+ /// 二进制格式明文
+ /// 返回二进制密文数组
+ public static byte[] EncryptCBC(string secretKey, bool hexString, string iv, byte[] plainText)
+ {
+ var ctx = new Sm4Context
+ {
+ IsPadding = true,
+ Mode = Sm4Mode.Encrypt
+ };
+ byte[] keyBytes;
+ byte[] ivBytes;
+ if (hexString)
+ {
+ keyBytes = Hex.Decode(secretKey);
+ ivBytes = Hex.Decode(iv);
+ }
+ else
+ {
+ keyBytes = Encoding.UTF8.GetBytes(secretKey);
+ ivBytes = Encoding.UTF8.GetBytes(iv);
+ }
+
+ var sm4 = new Sm4();
+ sm4.SetKeyEnc(ctx, keyBytes);
+ return sm4.CBC(ctx, ivBytes, plainText);
+ }
+
+ ///
+ /// 解密CBC模式
+ ///
+ /// 16进制密钥
+ /// 密钥和IV是否是十六进制
+ ///
+ /// 二进制格式密文
+ /// 返回二进制格式明文
+ public static byte[] DecryptCBC(string secretKey, bool hexString, string iv, byte[] cipherText)
+ {
+ var ctx = new Sm4Context
+ {
+ IsPadding = true,
+ Mode = Sm4Mode.Decrypt
+ };
+ byte[] keyBytes;
+ byte[] ivBytes;
+ if (hexString)
+ {
+ keyBytes = Hex.Decode(secretKey);
+ ivBytes = Hex.Decode(iv);
+ }
+ else
+ {
+ keyBytes = Encoding.UTF8.GetBytes(secretKey);
+ ivBytes = Encoding.UTF8.GetBytes(iv);
+ }
+
+ var sm4 = new Sm4();
+ sm4.SetKeyDec(ctx, keyBytes);
+ return sm4.CBC(ctx, ivBytes, cipherText);
+ }
+}
\ No newline at end of file
diff --git a/framework/NPin.Framework.Core/Crypt/SM4/Sm4Mode.cs b/framework/NPin.Framework.Core/Crypt/SM4/Sm4Mode.cs
new file mode 100644
index 0000000..5f4818c
--- /dev/null
+++ b/framework/NPin.Framework.Core/Crypt/SM4/Sm4Mode.cs
@@ -0,0 +1,7 @@
+namespace NPin.Framework.Core.Crypt.SM4;
+
+public enum Sm4Mode
+{
+ Encrypt,
+ Decrypt
+}
\ No newline at end of file
diff --git a/framework/NPin.Framework.Core/NPin.Framework.Core.csproj b/framework/NPin.Framework.Core/NPin.Framework.Core.csproj
index 0a3e1af..4bc59a2 100644
--- a/framework/NPin.Framework.Core/NPin.Framework.Core.csproj
+++ b/framework/NPin.Framework.Core/NPin.Framework.Core.csproj
@@ -2,6 +2,7 @@
+
diff --git a/framework/NPin.Framework.SqlSugarCore.Abstractions/Data/IEnabled.cs b/framework/NPin.Framework.SqlSugarCore.Abstractions/Data/IEnabled.cs
new file mode 100644
index 0000000..0a565b5
--- /dev/null
+++ b/framework/NPin.Framework.SqlSugarCore.Abstractions/Data/IEnabled.cs
@@ -0,0 +1,6 @@
+namespace NPin.Framework.SqlSugarCore.Abstractions.Data;
+
+public interface IEnabled
+{
+ bool IsEnabled { get; set; }
+}
\ No newline at end of file
diff --git a/framework/NPin.Framework.SqlSugarCore.Abstractions/Data/IOrderNum.cs b/framework/NPin.Framework.SqlSugarCore.Abstractions/Data/IOrderNum.cs
new file mode 100644
index 0000000..e69cb6a
--- /dev/null
+++ b/framework/NPin.Framework.SqlSugarCore.Abstractions/Data/IOrderNum.cs
@@ -0,0 +1,9 @@
+namespace NPin.Framework.SqlSugarCore.Abstractions.Data;
+
+public interface IOrderNum
+{
+ ///
+ /// 排序号
+ ///
+ int OrderNum { get; set; }
+}
\ No newline at end of file
diff --git a/framework/NPin.Framework.SqlSugarCore.Abstractions/ISqlSugarDbConnectionCreator.cs b/framework/NPin.Framework.SqlSugarCore.Abstractions/ISqlSugarDbConnectionCreator.cs
index 3e35021..9109b64 100644
--- a/framework/NPin.Framework.SqlSugarCore.Abstractions/ISqlSugarDbConnectionCreator.cs
+++ b/framework/NPin.Framework.SqlSugarCore.Abstractions/ISqlSugarDbConnectionCreator.cs
@@ -13,6 +13,7 @@ public interface ISqlSugarDbConnectionCreator
Action OnLogExecuting { get; set; }
Action OnLogExecuted { get; set; }
Action EntityService { get; set; }
+ Action EntityNameService { get; set; }
ConnectionConfig Build(Action? action = null);
void SetDbAop(ISqlSugarClient currentDb);
diff --git a/framework/NPin.Framework.SqlSugarCore/SqlSugarDbConnectionCreator.cs b/framework/NPin.Framework.SqlSugarCore/SqlSugarDbConnectionCreator.cs
index 8bd7056..a88b6a5 100644
--- a/framework/NPin.Framework.SqlSugarCore/SqlSugarDbConnectionCreator.cs
+++ b/framework/NPin.Framework.SqlSugarCore/SqlSugarDbConnectionCreator.cs
@@ -20,6 +20,8 @@ public class SqlSugarDbConnectionCreator : ISqlSugarDbConnectionCreator, ITransi
[DisablePropertyInjection] public Action OnLogExecuted { get; set; }
[DisablePropertyInjection] public Action EntityService { get; set; }
+
+ [DisablePropertyInjection] public Action EntityNameService { get; set; }
public DbConnOptions Options { get; }
@@ -87,6 +89,10 @@ public class SqlSugarDbConnectionCreator : ISqlSugarDbConnectionCreator, ITransi
}
EntityService(c, p);
+ },
+ EntityNameService = (t, e) =>
+ {
+ EntityNameService(t, e);
}
},
// Aop
diff --git a/framework/NPin.Framework.SqlSugarCore/SqlSugarDbContext.cs b/framework/NPin.Framework.SqlSugarCore/SqlSugarDbContext.cs
index 98846e8..f411de9 100644
--- a/framework/NPin.Framework.SqlSugarCore/SqlSugarDbContext.cs
+++ b/framework/NPin.Framework.SqlSugarCore/SqlSugarDbContext.cs
@@ -5,7 +5,6 @@ using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NPin.Framework.SqlSugarCore.Abstractions;
using SqlSugar;
-using Volo.Abp;
using Volo.Abp.Auditing;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
@@ -47,6 +46,7 @@ public class SqlSugarDbContext : ISqlSugarDbContext
var connectionCreator = LazyServiceProvider.LazyGetRequiredService();
connectionCreator.OnSqlSugarClientConfig = OnSqlSugarClientConfig;
connectionCreator.EntityService = EntityService;
+ connectionCreator.EntityNameService = EntityNameService;
connectionCreator.DataExecuting = DataExecuting;
connectionCreator.DataExecuted = DataExecuted;
connectionCreator.OnLogExecuting = OnLogExecuting;
@@ -204,6 +204,9 @@ public class SqlSugarDbContext : ISqlSugarDbContext
///
/// 实体配置
+ /// 自动主键
+ /// 自动Ignore关联配置(导航)
+ /// 开启下划线
///
///
///
@@ -213,10 +216,25 @@ public class SqlSugarDbContext : ISqlSugarDbContext
{
column.IsIgnore = true;
}
+
if (property.Name == nameof(Entity