You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

242 lines
9.2 KiB

using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Asn1.Smime;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.EC;
using Org.BouncyCastle.Crypto.Encodings;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Paddings;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.Pqc.Crypto.Lms;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.X509;
using System;
using System.Linq;
using System.Text;
/// <summary>
/// 提供对国密标准(SM2, SM3, SM4)加密算法的支持。
/// </summary>
public class GmCrypto
{
// SM2 密钥对,用于非对称加密和解密操作
private AsymmetricCipherKeyPair _sm2KeyPair;
/// <summary>
/// 构造函数,默认生成新的 SM2 密钥对。
/// </summary>
public GmCrypto()
{
_sm2KeyPair = GenerateSm2KeyPair();
}
/// <summary>
///
/// </summary>
/// <param name="pubKey">sm2公匙</param>
/// <param name="priKey">sm2私匙</param>
public GmCrypto(string pubKey, string priKey)
{
_sm2KeyPair = new AsymmetricCipherKeyPair(ReadPublicKeyFromBase64(pubKey), ReadPrivateKeyFromBase64(priKey));
}
/// <summary>
/// 生成一个新的 SM2 密钥对。
/// </summary>
public AsymmetricCipherKeyPair GenerateSm2KeyPair()
{
// 定义椭圆曲线参数(这里使用的是SM2默认的曲线)
X9ECParameters ecParams = CustomNamedCurves.GetByName("sm2p256v1");
ECDomainParameters domainParams = new ECDomainParameters(ecParams.Curve, ecParams.G, ecParams.N, ecParams.H, ecParams.GetSeed());
// 创建密钥对生成器并初始化
var keyPairGenerator = GeneratorUtilities.GetKeyPairGenerator("EC");
var keyGenParam = new ECKeyGenerationParameters(domainParams, new SecureRandom());
keyPairGenerator.Init(keyGenParam);
return keyPairGenerator.GenerateKeyPair();
}
public (string pubKey, string priKey) GetSM2Key()
{
// 获取公私钥
ECPrivateKeyParameters privateKey = (ECPrivateKeyParameters)_sm2KeyPair.Private;
ECPublicKeyParameters publicKey = (ECPublicKeyParameters)_sm2KeyPair.Public;
// 将公钥转换为Base64编码的字符串
string publicKeyString = Convert.ToBase64String(SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey).GetDerEncoded());
// 将私钥转换为PKCS#8格式并Base64编码
PrivateKeyInfo privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(privateKey);
string privateKeyString = Convert.ToBase64String(privateKeyInfo.GetDerEncoded());
return (publicKeyString, privateKeyString);
}
/// <summary>
/// 读取公私匙
/// </summary>
/// <param name="publicKeyBase64"></param>
/// <returns></returns>
public ECPublicKeyParameters ReadPublicKeyFromBase64(string publicKeyBase64)
{
byte[] encodedPublicKey = Convert.FromBase64String(publicKeyBase64);
SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfo.GetInstance(encodedPublicKey);
return (ECPublicKeyParameters)PublicKeyFactory.CreateKey(publicKeyInfo);
}
/// <summary>
/// 读取私有钥匙
/// </summary>
/// <param name="privateKeyBase64"></param>
/// <returns></returns>
public ECPrivateKeyParameters ReadPrivateKeyFromBase64(string privateKeyBase64)
{
byte[] encodedPrivateKey = Convert.FromBase64String(privateKeyBase64);
PrivateKeyInfo privateKeyInfo = PrivateKeyInfo.GetInstance(encodedPrivateKey);
return (ECPrivateKeyParameters)PrivateKeyFactory.CreateKey(privateKeyInfo);
}
/// <summary>
/// 使用 SM2 算法加密给定的数据字符串。
/// </summary>
/// <param name="data">要加密的数据字符串。</param>
/// <returns>返回加密后的字节数组。</returns>
public byte[] EncryptSm2(string data)
{
return EncryptWithSM2(data, (ECPublicKeyParameters)_sm2KeyPair.Public);
}
/// <summary>
/// 使用 SM2 算法解密给定的加密数据。
/// </summary>
/// <param name="encryptedData">已加密的数据字节数组。</param>
/// <returns>返回解密后的原始数据字符串。</returns>
public string DecryptSm2(byte[] encryptedData)
{
return DecryptWithSM2(encryptedData, (ECPrivateKeyParameters)_sm2KeyPair.Private);
}
/// <summary>
/// 使用SM2算法进行加密。
/// </summary>
/// <param name="data">要加密的字符串。</param>
/// <param name="publicKey">用于加密的公钥。</param>
/// <returns>返回加密后的字节数组。</returns>
public static byte[] EncryptWithSM2(string data, ECPublicKeyParameters publicKey)
{
var cipher = new SM2Engine();
cipher.Init(true, new ParametersWithRandom(publicKey, new SecureRandom()));
return cipher.ProcessBlock(Encoding.UTF8.GetBytes(data), 0, data.Length);
}
/// <summary>
/// 使用SM2算法进行解密。
/// </summary>
/// <param name="encryptedData">要解密的字节数组。</param>
/// <param name="privateKey">用于解密的私钥。</param>
/// <returns>返回解密后的字符串。</returns>
public static string DecryptWithSM2(byte[] encryptedData, ECPrivateKeyParameters privateKey)
{
var cipher = new SM2Engine();
cipher.Init(false, privateKey);
var output = cipher.ProcessBlock(encryptedData, 0, encryptedData.Length);
return Encoding.UTF8.GetString(output);
}
/// <summary>
/// 使用 SM3 哈希算法计算给定消息的哈希值。
/// </summary>
/// <param name="message">要计算哈希的消息字符串。</param>
/// <returns>返回哈希结果的十六进制字符串表示形式。</returns>
public string HashSm3(string message)
{
var sm3Digest = new SM3Digest(); // 创建 SM3 摘要实例
byte[] messageBytes = Encoding.UTF8.GetBytes(message); // 将消息转换为字节数组
sm3Digest.BlockUpdate(messageBytes, 0, messageBytes.Length); // 更新摘要对象
byte[] hash = new byte[sm3Digest.GetDigestSize()]; // 准备存储哈希结果的空间
sm3Digest.DoFinal(hash, 0); // 完成哈希计算并获取结果
return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant(); // 转换为十六进制字符串
}
/// <summary>
/// 默认的 SM4 对称加密使用的密钥和初始化向量 (IV)。
/// 注意:在实际应用中应从安全的地方加载这些值。
/// </summary>
private static readonly string DefaultKey = "your-16-byte-key"; // 128 bits
private static readonly string DefaultIV = "your-16-byte-iv-"; // 128 bits
/// <summary>
/// 使用 SM4 算法加密数据
/// </summary>
/// <param name="plainText">要加密的明文</param>
/// <param name="key">16 字节的密钥</param>
/// <param name="iv">16 字节的初始化向量(IV)</param>
/// <returns>加密后的字节数组</returns>
public byte[] EncryptSM4(string plainText, string? key=null, string? iv = null)
{
if (string.IsNullOrEmpty(key))
key = DefaultKey;
if (string.IsNullOrEmpty(iv))
iv = DefaultIV;
// 将明文、密钥和 IV 转换为字节数组
byte[] inputBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
byte[] keyBytes = System.Text.Encoding.UTF8.GetBytes(key);
byte[] ivBytes = System.Text.Encoding.UTF8.GetBytes(iv);
// 获取 SM4/CBC/PKCS7Padding 模式的加密引擎
IBufferedCipher cipher = CipherUtilities.GetCipher("SM4/CBC/PKCS7Padding");
// 创建密钥参数
KeyParameter keyParam = ParameterUtilities.CreateKeyParameter("SM4", keyBytes);
// 创建包含密钥和 IV 的参数
ParametersWithIV parameters = new ParametersWithIV(keyParam, ivBytes);
// 初始化加密模式
cipher.Init(true, parameters);
// 执行加密操作并返回加密后的字节数组
return cipher.DoFinal(inputBytes);
}
/// <summary>
/// 使用 SM4 算法解密数据
/// </summary>
/// <param name="cipherText">要解密的密文</param>
/// <param name="key">16 字节的密钥</param>
/// <param name="iv">16 字节的初始化向量(IV)</param>
/// <returns>解密后的字节数组</returns>
public byte[] DecryptSM4(byte[] cipherText, string? key=null, string? iv=null)
{
if (string.IsNullOrEmpty(key))
key = DefaultKey;
if (string.IsNullOrEmpty(iv))
iv = DefaultIV;
// 将密钥和 IV 转换为字节数组
byte[] keyBytes = System.Text.Encoding.UTF8.GetBytes(key);
byte[] ivBytes = System.Text.Encoding.UTF8.GetBytes(iv);
// 获取 SM4/CBC/PKCS7Padding 模式的解密引擎
IBufferedCipher cipher = CipherUtilities.GetCipher("SM4/CBC/PKCS7Padding");
// 创建密钥参数
KeyParameter keyParam = ParameterUtilities.CreateKeyParameter("SM4", keyBytes);
// 创建包含密钥和 IV 的参数
ParametersWithIV parameters = new ParametersWithIV(keyParam, ivBytes);
// 初始化解密模式
cipher.Init(false, parameters);
// 执行解密操作并返回解密后的字节数组
return cipher.DoFinal(cipherText);
}
}