Bootstrap

.NET C# 国密算法(SM算法)详细实现

.NET C# 国密算法(SM算法)详细实现

1 SM2 - 椭圆曲线公钥密码算法

SM2 是基于椭圆曲线密码学 (ECC) 的公钥密码算法,功能类似于国际通用的 RSA 或 ECC,主要用于加密、签名和密钥交换。

  • 特点
    基于椭圆曲线的复杂数学问题(离散对数问题),安全性高。
    密钥长度短:推荐使用 256 位椭圆曲线,比 RSA 2048 位更高效。
    支持加密、数字签名和密钥协商。

  • 主要应用场景
    数据加密:点对点安全传输。
    数字签名:身份认证、数据完整性校验。
    密钥交换:安全通信中生成会话密钥。

  • 技术细节
    曲线参数采用推荐曲线 sm2p256v1,其定义与国际标准曲线 secp256k1 类似。
    椭圆曲线方程:y2=x3+ax+bmod py^2 = x^3 + ax + b \mod py2=x3+ax+bmodp, 其中 a=−3a = -3a=−3,bbb 和 ppp 是固定常数。

  • 优点
    性能优异:在同等安全等级下,计算效率高于 RSA。
    国家标准:符合中国密码标准,适合中国市场使用。

using Hearth.Services.Security.Interfaces;
using Org.BouncyCastle.Asn1.GM;
using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Math.EC;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities.Encoders;
using System.Text;

namespace Hearth.Services.Security
{
    public class SM2Encryptor : IAsymmetricEncryptor
    {
        private byte[] _publicKey;
        private byte[] _privateKey;

        public byte[] Decrypt(byte[] data)
        {
            ArgumentNullException.ThrowIfNull(data);
            ArgumentNullException.ThrowIfNull(_privateKey);

            // 参数“1”必须,BigInteger 默认以有符号整数解析。如果私钥的最高位是 1,可能会被误解为负数,需要强制以无符号方式处理:
            BigInteger d = new BigInteger(1, _privateKey);
            X9ECParameters sm2Params = GMNamedCurves.GetByName("sm2p256v1");
            ECDomainParameters domainParameters = new ECDomainParameters(sm2Params.Curve, sm2Params.G, sm2Params.N, sm2Params.H);
            string dataHexStr = Hex.ToHexString(data);
            string privateKeyHexStr = Hex.ToHexString(_privateKey);
            AsymmetricKeyParameter keyParameter = new ECPrivateKeyParameters(d, domainParameters);
            SM2Engine engine = new SM2Engine();
            engine.Init(false, keyParameter);
            byte[] decryptedData = engine.ProcessBlock(data, 0, data.Length);
            return decryptedData;
        }

        public string Decrypt(string data)
        {
            ArgumentNullException.ThrowIfNull(data);
            ArgumentNullException.ThrowIfNull(_privateKey);

            byte[] encryptedData = Hex.Decode(data);
            byte[] decryptedData = Decrypt(encryptedData);
            return Encoding.UTF8.GetString(decryptedData);
        }

        public byte[] Encrypt(byte[] data)
        {
            ArgumentNullException.ThrowIfNull(data);
            ArgumentNullException.ThrowIfNull(_publicKey);

            X9ECParameters sm2Params = GMNamedCurves.GetByName("sm2p256v1");
            ECPoint q = sm2Params.Curve.DecodePoint(_publicKey);
            ECDomainParameters domainParameters = new ECDomainParameters(sm2Params.Curve, sm2Params.G, sm2Params.N, sm2Params.H);
            AsymmetricKeyParameter keyParameter = new ECPublicKeyParameters(q, domainParameters);
            SM2Engine engine = new SM2Engine();
            engine.Init(true, new ParametersWithRandom(keyParameter, new SecureRandom()));
            byte[] encryptedData = engine.ProcessBlock(data, 0, data.Length);
            return encryptedData;
        }

        public string Encrypt(string data)
        {
            ArgumentNullException.ThrowIfNull(data);
            ArgumentNullException.ThrowIfNull(_publicKey);

            byte[] dataBytes = Encoding.UTF8.GetBytes(data);
            byte[] encryptedData = Encrypt(dataBytes);
            return Hex.ToHexString(encryptedData);
        }

        public string GetPrivateKey()
        {
            ArgumentNullException.ThrowIfNull(_privateKey);
            return Hex.ToHexString(_privateKey);
        }

        public byte[] GetPrivateKeyBytes()
        {
            return _privateKey;
        }

        public string GetPublicKey()
        {
            ArgumentNullException.ThrowIfNull(_publicKey);
            return Hex.ToHexString(_publicKey);
        }

        public byte[] GetPublicKeyBytes()
        {
            return _publicKey;
        }

        public void SetPrivateKey(string privateKey)
        {
            ArgumentNullException.ThrowIfNull(privateKey);

            _privateKey = Hex.Decode(privateKey);
        }

        public void SetPrivateKey(byte[] privateKey)
        {
            _privateKey = privateKey;
        }

        public void SetPublicKey(string publicKey)
        {
            ArgumentNullException.ThrowIfNull(publicKey);

            _publicKey = Hex.Decode(publicKey);
        }

        public void SetPublicKey(byte[] publicKey)
        {
            _publicKey = publicKey;
        }
    }
}

2 SM3 - 哈希算法

SM3 是一种杂凑算法,功能类似于国际标准的 SHA-256,但有独特的设计,增强了对碰撞攻击的抵抗能力。

  • 特点
    输出长度固定为 256 位。
    抗碰撞性强:给定输入,几乎不可能找到两个具有相同哈希值的输入。
    高效:计算速度快,适合在硬件或软件中实现。
  • 主要应用场景
    数字签名:结合 SM2 验证数据完整性。
    消息认证:校验数据传输中的篡改。
    数据指纹:生成文件或数据的唯一标识。
  • 技术细节
    基本结构基于 Merkle-Damgård 结构。
    消息分组长度为 512 位,每次处理一个分组。
    压缩函数包含 64 轮迭代,每轮使用不同的常量。
  • 与 SHA-256 的区别
    算法内部逻辑稍有不同,增强了安全性。
    更适合与其他国密算法(如 SM2 和 SM4)结合使用。
using Hearth.Services.Security.Interfaces;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Utilities.Encoders;
using System.Text;

namespace Hearth.Services.Security
{
    public class SM3Encryptor : IHashEncryptor
    {
        public byte[] Encrypt(byte[] data)
        {
            SM3Digest digest = new SM3Digest();
            digest.BlockUpdate(data, 0, data.Length);
            byte[] hash = new byte[digest.GetDigestSize()];
            digest.DoFinal(hash, 0);
            return hash;
        }

        public string Encrypt(string data)
        {
            byte[] dataBytes = Encoding.UTF8.GetBytes(data);
            byte[] hashResult = Encrypt(dataBytes);
            return Hex.ToHexString(hashResult);
        }
    }
}

3 SM4 - 分组对称加密算法

SM4 是一种对称加密算法,功能类似于 AES,用于数据加密和解密。

  • 特点
    块加密:以 128 位分组进行加密和解密。
    密钥长度固定为 128 位。
    采用 Feistel 结构,每轮执行 S-Box 替换、线性变换和密钥加混。
  • 主要应用场景
    无线网络安全:如 WLAN 认证和加密。
    数据存储:文件加密和数据库保护。
    通信安全:加密传输数据。
  • 技术细节
    总共有 32 轮加密。
    使用 128 位的对称密钥。
    提供 ECB、CBC、CFB、OFB 等常见的加密模式。
  • 与 AES 的比较
    相同分组长度(128 位)和密钥长度(128 位)。
    在硬件实现上性能与 AES 相当,但设计上更适合中国密码标准环境。

3.1 CBC 模式(Cipher Block Chaining)

需要提供初始化向量(IV),它与密钥一起参与加密过程,对每个明文块加密前会先与前一个密文块进行异或操作,增强了加密安全性,避免了相同明文加密出相同密文的情况。
通过CipherUtilities.GetCipher(“SM4/CBC/PKCS7Padding”)获取对应的密码器实例,并使用ParametersWithIV结合密钥和 IV 进行初始化后执行加密操作。

using Hearth.Services.Security.Interfaces;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities.Encoders;
using System.Text;

namespace Hearth.Services.Security
{
    public class SM4CBCEncryptor : IIVSymmetricEncryptor
    {
        private byte[] _key;
        private byte[] _iv;

        public byte[] Decrypt(byte[] data)
        {
            ArgumentNullException.ThrowIfNull(data);
            ArgumentNullException.ThrowIfNull(_key);
            ArgumentNullException.ThrowIfNull(_iv);

            IBufferedCipher bufferedCipher = CipherUtilities.GetCipher("SM4/CBC/PKCS7Padding");
            KeyParameter keyParameter = new KeyParameter(_key);
            bufferedCipher.Init(false, new ParametersWithIV(keyParameter, _iv));
            return bufferedCipher.DoFinal(data);
        }

        public string Decrypt(string data)
        {
            ArgumentNullException.ThrowIfNull(data);
            ArgumentNullException.ThrowIfNull(_key);
            ArgumentNullException.ThrowIfNull(_iv);

            byte[] encryptedBytes = Hex.Decode(data);
            byte[] decryptedBytes = Decrypt(encryptedBytes);
            return Encoding.UTF8.GetString(decryptedBytes);
        }

        public byte[] Encrypt(byte[] data)
        {
            ArgumentNullException.ThrowIfNull(data);
            ArgumentNullException.ThrowIfNull(_key);
            ArgumentNullException.ThrowIfNull(_iv);

            IBufferedCipher bufferedCipher = CipherUtilities.GetCipher("SM4/CBC/PKCS7Padding");
            KeyParameter keyParameter = new KeyParameter(_key);
            bufferedCipher.Init(true, new ParametersWithIV(keyParameter, _iv));
            return bufferedCipher.DoFinal(data);
        }

        public string Encrypt(string data)
        {
            ArgumentNullException.ThrowIfNull(data);
            ArgumentNullException.ThrowIfNull(_key);
            ArgumentNullException.ThrowIfNull(_iv);

            byte[] plainBytes = Encoding.UTF8.GetBytes(data);
            byte[] encryptedBytes = Encrypt(plainBytes);
            return Hex.ToHexString(encryptedBytes);
        }

        public string GetIV()
        {
            return Hex.ToHexString(_iv);
        }

        public byte[] GetIVBytes()
        {
            return _iv;
        }

        public string GetKey()
        {
            return Hex.ToHexString(_key);
        }

        public byte[] GetKeyBytes()
        {
            return _key;
        }

        public void SetIV(string iv)
        {
            _iv = Hex.Decode(iv);
        }

        public void SetIV(byte[] iv)
        {
            _iv = iv;
        }

        public void SetKey(string key)
        {
            _key = Hex.Decode(key);
        }

        public void SetKey(byte[] key)
        {
            _key = key;
        }
    }
}

3.2 ECB 模式(Electronic Codebook)

是最简单的模式,每个明文块独立加密,相同的明文块会加密出相同的密文块,安全性相对较低,常用于一些对数据完整性要求不高的场景或者结合其他技术使用。
直接使用CipherUtilities.GetCipher(“SM4/ECB/PKCS7Padding”)获取密码器,用密钥初始化后进行加密。

using Hearth.Services.Security.Interfaces;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities.Encoders;
using System.Text;

namespace Hearth.Services.Security
{
    public class SM4ECBEncryptor : ISymmetricEncryptor
    {
        private byte[] _key;

        public byte[] Decrypt(byte[] data)
        {
            ArgumentNullException.ThrowIfNull(data);
            ArgumentNullException.ThrowIfNull(_key);

            IBufferedCipher bufferedCipher = CipherUtilities.GetCipher("SM4/ECB/PKCS7Padding");
            KeyParameter keyParameter = new KeyParameter(_key);
            bufferedCipher.Init(false, keyParameter);
            return bufferedCipher.DoFinal(data);
        }

        public string Decrypt(string data)
        {
            ArgumentNullException.ThrowIfNull(data);
            ArgumentNullException.ThrowIfNull(_key);

            byte[] encryptedBytes = Hex.Decode(data);
            byte[] decryptedBytes = Decrypt(encryptedBytes);
            return Encoding.UTF8.GetString(decryptedBytes);
        }

        public byte[] Encrypt(byte[] data)
        {
            ArgumentNullException.ThrowIfNull(data);
            ArgumentNullException.ThrowIfNull(_key);

            IBufferedCipher bufferedCipher = CipherUtilities.GetCipher("SM4/ECB/PKCS7Padding");
            KeyParameter keyParameter = new KeyParameter(_key);
            bufferedCipher.Init(true, keyParameter);
            return bufferedCipher.DoFinal(data);
        }

        public string Encrypt(string data)
        {
            ArgumentNullException.ThrowIfNull(data);
            ArgumentNullException.ThrowIfNull(_key);

            byte[] plainBytes = Encoding.UTF8.GetBytes(data);
            byte[] encryptedBytes = Encrypt(plainBytes);
            return Hex.ToHexString(encryptedBytes);
        }

        public string GetKey()
        {
            return Hex.ToHexString(_key);
        }

        public byte[] GetKeyBytes()
        {
            return _key;
        }

        public void SetKey(string key)
        {
            _key = Hex.Decode(key);
        }

        public void SetKey(byte[] key)
        {
            _key = key;
        }
    }
}

3.3 CFB 模式(Cipher Feedback)

也需要 IV,它将加密后的部分结果反馈到加密过程中,以实现类似流密码的效果,加密时不需要对明文进行分组填充等操作,加密单位可以更小,比如按位或者字节等。
使用CfbBlockCipher结合SM4Engine构建BufferedBlockCipher,再用密钥和 IV 初始化后加密。

using Hearth.Services.Security.Interfaces;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Utilities.Encoders;
using System.Text;

namespace Hearth.Services.Security
{
    public class SM4CFBEncryptor : IIVSymmetricEncryptor
    {
        private byte[] _key;
        private byte[] _iv;

        public byte[] Decrypt(byte[] data)
        {
            ArgumentNullException.ThrowIfNull(data);
            ArgumentNullException.ThrowIfNull(_key);
            ArgumentNullException.ThrowIfNull(_iv);

            IBlockCipher engine = new SM4Engine();
            CfbBlockCipher blockCipher = new CfbBlockCipher(engine, 128);
            BufferedBlockCipher bufferedBlockCipher = new BufferedBlockCipher(blockCipher);
            bufferedBlockCipher.Init(false, new ParametersWithIV(new KeyParameter(_key), _iv));
            return bufferedBlockCipher.DoFinal(data);
        }

        public string Decrypt(string data)
        {
            ArgumentNullException.ThrowIfNull(data);
            ArgumentNullException.ThrowIfNull(_key);
            ArgumentNullException.ThrowIfNull(_iv);

            byte[] encryptedBytes = Hex.Decode(data);
            byte[] decryptedBytes = Decrypt(encryptedBytes);
            return Encoding.UTF8.GetString(decryptedBytes);
        }

        public byte[] Encrypt(byte[] data)
        {
            ArgumentNullException.ThrowIfNull(data);
            ArgumentNullException.ThrowIfNull(_key);
            ArgumentNullException.ThrowIfNull(_iv);

            IBlockCipher engine = new SM4Engine();
            CfbBlockCipher blockCipher = new CfbBlockCipher(engine, 128);
            BufferedBlockCipher bufferedBlockCipher = new BufferedBlockCipher(blockCipher);
            bufferedBlockCipher.Init(true, new ParametersWithIV(new KeyParameter(_key), _iv));
            return bufferedBlockCipher.DoFinal(data);
        }

        public string Encrypt(string data)
        {
            ArgumentNullException.ThrowIfNull(data);
            ArgumentNullException.ThrowIfNull(_key);
            ArgumentNullException.ThrowIfNull(_iv);

            byte[] plainBytes = Encoding.UTF8.GetBytes(data);
            byte[] encryptedBytes = Encrypt(plainBytes);
            return Hex.ToHexString(encryptedBytes);
        }

        public string GetIV()
        {
            return Hex.ToHexString(_iv);
        }

        public byte[] GetIVBytes()
        {
            return _iv;
        }

        public string GetKey()
        {
            return Hex.ToHexString(_key);
        }

        public byte[] GetKeyBytes()
        {
            return _key;
        }

        public void SetIV(string iv)
        {
            _iv = Hex.Decode(iv);
        }

        public void SetIV(byte[] iv)
        {
            _iv = iv;
        }

        public void SetKey(string key)
        {
            _key = Hex.Decode(key);
        }

        public void SetKey(byte[] key)
        {
            _key = key;
        }
    }
}

3.4 OFB 模式(Output Feedback)

同样依赖 IV,它生成一个密钥流,将明文与密钥流进行异或操作来加密,加密过程中密钥流的生成与明文无关,只要密钥和 IV 相同,生成的密钥流就相同,在某些场景下使用较为方便。
利用OfbBlockCipher结合SM4Engine构建BufferedBlockCipher,使用密钥和 IV 初始化来完成加密。

using Hearth.Services.Security.Interfaces;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Utilities.Encoders;
using System.Text;

namespace Hearth.Services.Security
{
    public class SM4OFBEncryptor : IIVSymmetricEncryptor
    {
        private byte[] _key;
        private byte[] _iv;

        public byte[] Decrypt(byte[] data)
        {
            ArgumentNullException.ThrowIfNull(data);
            ArgumentNullException.ThrowIfNull(_key);
            ArgumentNullException.ThrowIfNull(_iv);

            IBlockCipher engine = new SM4Engine();
            OfbBlockCipher blockCipher = new OfbBlockCipher(engine, 128);
            BufferedBlockCipher bufferedBlockCipher = new BufferedBlockCipher(blockCipher);
            bufferedBlockCipher.Init(false, new ParametersWithIV(new KeyParameter(_key), _iv));
            return bufferedBlockCipher.DoFinal(data);
        }

        public string Decrypt(string data)
        {
            ArgumentNullException.ThrowIfNull(data);
            ArgumentNullException.ThrowIfNull(_key);
            ArgumentNullException.ThrowIfNull(_iv);

            byte[] encryptedBytes = Hex.Decode(data);
            byte[] decryptedBytes = Decrypt(encryptedBytes);
            return Encoding.UTF8.GetString(decryptedBytes);
        }

        public byte[] Encrypt(byte[] data)
        {
            ArgumentNullException.ThrowIfNull(data);
            ArgumentNullException.ThrowIfNull(_key);
            ArgumentNullException.ThrowIfNull(_iv);

            IBlockCipher engine = new SM4Engine();
            OfbBlockCipher blockCipher = new OfbBlockCipher(engine, 128);
            BufferedBlockCipher bufferedBlockCipher = new BufferedBlockCipher(blockCipher);
            bufferedBlockCipher.Init(true, new ParametersWithIV(new KeyParameter(_key), _iv));
            return bufferedBlockCipher.DoFinal(data);
        }

        public string Encrypt(string data)
        {
            ArgumentNullException.ThrowIfNull(data);
            ArgumentNullException.ThrowIfNull(_key);
            ArgumentNullException.ThrowIfNull(_iv);

            byte[] plainBytes = Encoding.UTF8.GetBytes(data);
            byte[] encryptedBytes = Encrypt(plainBytes);
            return Hex.ToHexString(encryptedBytes);
        }

        public string GetIV()
        {
            return Hex.ToHexString(_iv);
        }

        public byte[] GetIVBytes()
        {
            return _iv;
        }

        public string GetKey()
        {
            return Hex.ToHexString(_key);
        }

        public byte[] GetKeyBytes()
        {
            return _key;
        }

        public void SetIV(string iv)
        {
            _iv = Hex.Decode(iv);
        }

        public void SetIV(byte[] iv)
        {
            _iv = iv;
        }

        public void SetKey(string key)
        {
            _key = Hex.Decode(key);
        }

        public void SetKey(byte[] key)
        {
            _key = key;
        }
    }
}

4 附录

4.1 环境

  • 语言框架:C# + .NET 8
  • 依赖库:BouncyCastle.Cryptography 版本:2.4.0

4.2 接口列表

namespace Hearth.Services.Security.Interfaces
{
    /// <summary>
    /// 可解密接口
    /// </summary>
    public interface IDecryptable
    {
        /// <summary>
        /// 解密数据
        /// </summary>
        /// <param name="data">密文数据</param>
        /// <returns>明文数据</returns>
        byte[] Decrypt(byte[] data);
        /// <summary>
        /// 解密数据
        /// </summary>
        /// <param name="data">密文</param>
        /// <returns>明文</returns>
        string Decrypt(string data);
    }
}

namespace Hearth.Services.Security.Interfaces
{
    /// <summary>
    /// 可加密的接口
    /// </summary>
    public interface IEncryptable
    {
        /// <summary>
        /// 加密数据
        /// </summary>
        /// <param name="data">明文数据</param>
        /// <returns>密文数据</returns>
        byte[] Encrypt(byte[] data);
        /// <summary>
        /// 加密数据
        /// </summary>
        /// <param name="data">明文</param>
        /// <returns>密文</returns>
        string Encrypt(string data);
    }
}

namespace Hearth.Services.Security.Interfaces
{
    /// <summary>
    /// 哈希加密器接口
    /// </summary>
    public interface IHashEncryptor : IEncryptable
    {

    }
}

namespace Hearth.Services.Security.Interfaces
{
    /// <summary>
    /// 对称加密器接口
    /// </summary>
    public interface ISymmetricEncryptor : IEncryptable, IDecryptable
    {
        /// <summary>
        /// 设置密钥
        /// </summary>
        /// <param name="key">秘钥</param>
        void SetKey(string key);
        /// <summary>
        /// 设置密钥
        /// </summary>
        /// <param name="key">秘钥</param>
        void SetKey(byte[] key);
        /// <summary>
        /// 获取密钥
        /// </summary>
        string GetKey();
        /// <summary>
        /// 获取密钥字节数组
        /// </summary>
        byte[] GetKeyBytes();
    }
}

namespace Hearth.Services.Security.Interfaces
{
    /// <summary>
    /// 初始化向量对称加密器接口
    /// </summary>
    public interface IIVSymmetricEncryptor : ISymmetricEncryptor
    {
        /// <summary>
        /// 设置初始化向量
        /// </summary>
        void SetIV(string key);
        /// <summary>
        /// 设置初始化向量
        /// </summary>
        /// <param name="key"></param>
        void SetIV(byte[] key);
        /// <summary>
        /// 获取初始化向量
        /// </summary>
        /// <returns></returns>
        string GetIV();
        /// <summary>
        /// 获取初始化向量
        /// </summary>
        /// <returns></returns>
        byte[] GetIVBytes();
    }
}

namespace Hearth.Services.Security.Interfaces
{
    /// <summary>
    /// 非对称加密器接口
    /// </summary>
    public interface IAsymmetricEncryptor : IEncryptable, IDecryptable
    {
        /// <summary>
        /// 设置公钥
        /// </summary>
        void SetPublicKey(string publicKey);
        /// <summary>
        /// 设置公钥
        /// </summary>
        void SetPublicKey(byte[] publicKey);
        /// <summary>
        /// 设置私钥
        /// </summary>
        void SetPrivateKey(string privateKey);
        /// <summary>
        /// 设置私钥
        /// </summary>
        void SetPrivateKey(byte[] privateKey);
        /// <summary>
        /// 获取公钥
        /// </summary>
        string GetPublicKey();
        /// <summary>
        /// 获取公钥
        /// </summary>
        string GetPrivateKey();
        /// <summary>
        /// 获取公钥字节数组
        /// </summary>
        byte[] GetPublicKeyBytes();
        /// <summary>
        /// 获取私钥字节数组
        /// </summary>
        byte[] GetPrivateKeyBytes();
    }
}

4.3 测试用例

using Hearth.Services.Security.Interfaces;
using Org.BouncyCastle.Asn1.GM;
using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities.Encoders;

namespace Hearth.Services.Security.Tests
{
    public class SM2EncryptorTests
    {
        [Fact]
        public void EncryptDecrypt_PlainText_ReturnEqualOriginalPlainText()
        {
            // Arrange
            // Step 1: 获取 SM2 曲线参数
            X9ECParameters sm2Params = GMNamedCurves.GetByName("sm2p256v1");
            ECDomainParameters domainParams = new ECDomainParameters(sm2Params.Curve, sm2Params.G, sm2Params.N, sm2Params.H);

            // Step 2: 初始化密钥生成器
            ECKeyPairGenerator keyGen = new ECKeyPairGenerator();
            SecureRandom random = new SecureRandom();
            ECKeyGenerationParameters keyGenParam = new ECKeyGenerationParameters(domainParams, random);
            keyGen.Init(keyGenParam);

            // Step 3: 生成密钥对
            AsymmetricCipherKeyPair keyPair = keyGen.GenerateKeyPair();
            ECPrivateKeyParameters privateKeyParams = (ECPrivateKeyParameters)keyPair.Private;
            ECPublicKeyParameters publicKeyParams = (ECPublicKeyParameters)keyPair.Public;

            // Step 4: 将私钥和公钥转为16进制字符串
            string privateKeyHex = privateKeyParams.D.ToString(16);
            string publicKeyHex = Hex.ToHexString(publicKeyParams.Q.GetEncoded()); // 非压缩格式

            // Act
            // Step 5: 使用公钥加密字符串
            string plaintext = "Hello, SM2!";
            IAsymmetricEncryptor encryptor = new SM2Encryptor();
            encryptor.SetPublicKey(publicKeyHex);
            var ciphertext = encryptor.Encrypt(plaintext);

            // Step 6: 使用私钥解密数据
            encryptor.SetPrivateKey(privateKeyHex);
            string ciphertextDecrypted = encryptor.Decrypt(ciphertext);

            // Assert
            Assert.Equal(plaintext, ciphertextDecrypted);
        }
    }
}
using Hearth.Services.Security.Interfaces;
using System.Text;

namespace Hearth.Services.Security.Tests
{
    public class SM3EncryptorTests
    {
        [Fact]
        public void Encrypt_PlainText_ShouldReturnCipherText()
        {
            // Arrange
            IHashEncryptor encryptor = new SM3Encryptor();
            string plainText = "Hello, world!";
            byte[] plainBytes = Encoding.UTF8.GetBytes(plainText);
            // Act
            string encryptedString = encryptor.Encrypt(plainText);
            byte[] encryptedBytes = encryptor.Encrypt(plainBytes);
            string base64String = Convert.ToBase64String(encryptedBytes);
            // Assert
            Assert.NotNull(encryptedString);
        }
    }
}
using Hearth.Services.Security.Interfaces;
using System.Security.Cryptography;

namespace Hearth.Services.Security.Tests
{
    public class SM4CBCEncryptorTests
    {
        [Fact]
        public void EncryptDecrypt_PlainText_ReturnOriginalPlainText()
        {
            // Arrange
            byte[] key = new byte[16];
            byte[] iv = new byte[16];
            using (var generator = RandomNumberGenerator.Create())
            {
                generator.GetBytes(key);
                generator.GetBytes(iv);
            }

            IIVSymmetricEncryptor encryptor = new SM4CBCEncryptor();
            encryptor.SetKey(key);
            encryptor.SetIV(iv);

            string plainText = "Hello, world!";

            // Act
            string cipherText = encryptor.Encrypt(plainText);
            string decryptedText = encryptor.Decrypt(cipherText);

            // Assert
            Assert.Equal(plainText, decryptedText);
        }

        [Fact]
        public void MultipleEncrypt_EqualPlainText_ReturnDifferentCipherText()
        {
            // Arrange
            byte[] key = new byte[16];
            byte[] iv1 = new byte[16];
            byte[] iv2 = new byte[16];
            using (var generator = RandomNumberGenerator.Create())
            {
                generator.GetBytes(key);
                generator.GetBytes(iv1);
                generator.GetBytes(iv2);
            }
            IIVSymmetricEncryptor encryptor1 = new SM4CFBEncryptor();
            encryptor1.SetKey(key);
            encryptor1.SetIV(iv1);
            IIVSymmetricEncryptor encryptor2 = new SM4CFBEncryptor();
            encryptor2.SetKey(key);
            encryptor2.SetIV(iv2);
            string plainText = "Hello, world!";

            // Act
            string cipherText1 = encryptor1.Encrypt(plainText);
            string cipherText2 = encryptor2.Encrypt(plainText);

            // Assert
            Assert.NotEqual(cipherText1, cipherText2);
        }
    }
}
using Hearth.Services.Security.Interfaces;
using System.Security.Cryptography;

namespace Hearth.Services.Security.Tests
{
    public class SM4CFBEncryptorTests
    {
        [Fact]
        public void EncryptDecrypt_PlainText_ReturnOriginalPlainText()
        {
            // Arrange
            byte[] key = new byte[16];
            byte[] iv = new byte[16];
            using (var generator = RandomNumberGenerator.Create())
            {
                generator.GetBytes(key);
                generator.GetBytes(iv);
            }

            IIVSymmetricEncryptor encryptor = new SM4CFBEncryptor();
            encryptor.SetKey(key);
            encryptor.SetIV(iv);

            string plainText = "Hello, world!";

            // Act
            string cipherText = encryptor.Encrypt(plainText);
            string decryptedText = encryptor.Decrypt(cipherText);

            // Assert
            Assert.Equal(plainText, decryptedText);
        }

        [Fact]
        public void MultipleEncrypt_EqualPlainText_ReturnDifferentCipherText()
        {
            // Arrange
            byte[] key = new byte[16];
            byte[] iv1 = new byte[16];
            byte[] iv2 = new byte[16];
            using (var generator = RandomNumberGenerator.Create())
            {
                generator.GetBytes(key);
                generator.GetBytes(iv1);
                generator.GetBytes(iv2);
            }
            IIVSymmetricEncryptor encryptor1 = new SM4CFBEncryptor();
            encryptor1.SetKey(key);
            encryptor1.SetIV(iv1);
            IIVSymmetricEncryptor encryptor2 = new SM4CFBEncryptor();
            encryptor2.SetKey(key);
            encryptor2.SetIV(iv2);
            string plainText = "Hello, world!";

            // Act
            string cipherText1 = encryptor1.Encrypt(plainText);
            string cipherText2 = encryptor2.Encrypt(plainText);

            // Assert
            Assert.NotEqual(cipherText1, cipherText2);
        }
    }
}
using Hearth.Services.Security.Interfaces;
using System.Security.Cryptography;

namespace Hearth.Services.Security.Tests
{
    public class SM4ECBEncryptorTests
    {
        [Fact]
        public void EncryptDecrypt_PlainText_ReturnOriginalPlainText()
        {
            // Arrange
            byte[] key = new byte[16];
            using (var generator = RandomNumberGenerator.Create())
            {
                generator.GetBytes(key);
            }

            ISymmetricEncryptor encryptor = new SM4ECBEncryptor();
            encryptor.SetKey(key);

            string plainText = "Hello, world!";

            // Act
            string cipherText = encryptor.Encrypt(plainText);
            string decryptedText = encryptor.Decrypt(cipherText);

            // Assert
            Assert.Equal(plainText, decryptedText);
        }

        [Fact]
        public void MultipleEncrypt_EqualPlainText_ReturnECipherText()
        {
            // Arrange
            byte[] key = new byte[16];
            using (var generator = RandomNumberGenerator.Create())
            {
                generator.GetBytes(key);
            }
            ISymmetricEncryptor encryptor1 = new SM4ECBEncryptor();
            encryptor1.SetKey(key);
            ISymmetricEncryptor encryptor2 = new SM4ECBEncryptor();
            encryptor2.SetKey(key);
            string plainText = "Hello, world!";

            // Act
            string cipherText1 = encryptor1.Encrypt(plainText);
            string cipherText2 = encryptor2.Encrypt(plainText);

            // Assert
            Assert.Equal(cipherText1, cipherText2);
        }
    }
}
using Hearth.Services.Security.Interfaces;
using System.Security.Cryptography;

namespace Hearth.Services.Security.Tests
{
    public class SM4OFBEncryptorTests
    {
        [Fact]
        public void EncryptDecrypt_PlainText_ReturnOriginalPlainText()
        {
            // Arrange
            byte[] key = new byte[16];
            byte[] iv = new byte[16];
            using (var generator = RandomNumberGenerator.Create())
            {
                generator.GetBytes(key);
                generator.GetBytes(iv);
            }
            IIVSymmetricEncryptor encryptor = new SM4OFBEncryptor();
            encryptor.SetKey(key);
            encryptor.SetIV(iv);
            string plainText = "Hello, world!";

            // Act
            string cipherText = encryptor.Encrypt(plainText);
            string decryptedText = encryptor.Decrypt(cipherText);

            // Assert
            Assert.Equal(plainText, decryptedText);
        }

        [Fact]
        public void MultipleEncrypt_ShouldReturnDifferentCipherText()
        {
            // Arrange
            byte[] key = new byte[16];
            byte[] iv1 = new byte[16];
            byte[] iv2 = new byte[16];
            using (var generator = RandomNumberGenerator.Create())
            {
                generator.GetBytes(key);
                generator.GetBytes(iv1);
                generator.GetBytes(iv2);
            }
            IIVSymmetricEncryptor encryptor1 = new SM4OFBEncryptor();
            encryptor1.SetKey(key);
            encryptor1.SetIV(iv1);
            IIVSymmetricEncryptor encryptor2 = new SM4OFBEncryptor();
            encryptor2.SetKey(key);
            encryptor2.SetIV(iv2);
            string plainText = "Hello, world!";

            // Act
            string cipherText1 = encryptor1.Encrypt(plainText);
            string cipherText2 = encryptor2.Encrypt(plainText);

            // Assert
            Assert.NotEqual(cipherText1, cipherText2);
        }
    }
}
;