C#使用ECC椭圆曲线算法实现加密与解密&签名与验签,有完整代码

2 篇文章 1 订阅
2 篇文章 0 订阅

        在C#、Java、Android中都使用BouncyCastle,以此实现多种环境之间的互通,比如在Java中生成的公私钥,在C#或Android中使用……

        为了在几种环境中得到一致结果,实现时做了一些退化。比如公钥、私钥转为字符串时,直接读取了公私钥的参数,而不是转为PKCS8(java中默认);还比如,C#中找不到ECIES,所以java与C#中都使用SM2实现加解密,等等。

        网上难以搜索到相关实现,所以贴上完整代码。有些地方还不确定是否符号标准,比如公私钥转为字符串时,直接使用其中D、Q值,不确定这种实现在未来版本中是否会变得不适用。如果哪位安全专家看到这篇文章,希望能够批评指正。在Java、C#中测试,两边可以互通。相反,如果在Java中使用Key的getEncoded得到的公私钥,在C#中不能使用;反之亦然,在C#中转为PKCS8,在Java中不能用。

        以下是几个主要函数的说明:

  1. genKeyPair产生公私钥对,密钥长度是256位,据说强度与RSA 3072相当;
  2. sign使用私钥签名,verify使用公钥验签;
  3. encrypt使用公钥加密,decrypt使用私钥解密;
  4. privateKey2Str将私钥转为base64字符串,publicKey2Str将公钥转为base64字符串,对应有str2PublicKey、str2PrivateKey进行逆向转变,此功能用在与js的交互中。

        以上列举的这些功能在至简网格中用到,至简网格是为中小企业信息化准备的,它是一套分布式、服务化、端云结合的开发框架。它可以多实例跨机房、跨城市部署,也可以部署到一部旧手机中。提供的服务都是开源、免费的,以此为中小企业节省成本。其中用到多种技术,对这些技术点的摸索,都记录在CSDN至简网格专栏中,便于自己查找,也希望能帮到需要的人。

using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.EC;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Math.EC;
using Org.BouncyCastle.Security;
using System;

namespace MeshClient.util {
public class Ecc {
	private const string SIGN_ALGORITHM = "SHA256withECDSA"; //"SM3withSM2";
	private static readonly SecureRandom random = new SecureRandom();
	private static readonly ECDomainParameters domainParameters;
	private readonly ECPrivateKeyParameters privateKey;
	private readonly ECPublicKeyParameters publicKey;

	static Ecc() {
		DerObjectIdentifier oid = X9ObjectIdentifiers.Prime256v1;
		X9ECParameters ecps = CustomNamedCurves.GetByOid(oid);
		domainParameters = new ECDomainParameters(ecps.Curve, ecps.G, ecps.N, ecps.H, ecps.GetSeed());
	}

	private Ecc(ECPrivateKeyParameters privateKey, ECPublicKeyParameters publicKey) {
		this.privateKey = privateKey;
		this.publicKey = publicKey;
	}

	public static Ecc instance(AsymmetricCipherKeyPair keyPair) {
		return new Ecc((ECPrivateKeyParameters)keyPair.Private, (ECPublicKeyParameters)keyPair.Public);
	}

	public static Ecc instance() {
		AsymmetricCipherKeyPair keyPair = genKeyPair();
		return new Ecc((ECPrivateKeyParameters)keyPair.Private, (ECPublicKeyParameters)keyPair.Public);
	}

	//产生EC公私钥对
	public static AsymmetricCipherKeyPair genKeyPair() {
		ECKeyGenerationParameters ecKeyGenerationParameters = new ECKeyGenerationParameters(domainParameters, random);
		ECKeyPairGenerator gen = new ECKeyPairGenerator();

		gen.Init(ecKeyGenerationParameters);
		return gen.GenerateKeyPair();
	}

	/// <summary>
	/// 签名
	/// </summary>
	/// <param name="content">待签名内容</param>
	/// <param name="privateKey">EC私钥</param>
	/// <returns></returns>
	public static byte[] sign(byte[] content, ECPrivateKeyParameters privateKey) {
		ISigner signer = SignerUtilities.GetSigner(SIGN_ALGORITHM);

		signer.Init(true, new ParametersWithRandom(privateKey, random));
		signer.BlockUpdate(content, 0, content.Length);

		return signer.GenerateSignature();
	}

	/// <summary>
	/// 验签
	/// </summary>
	/// <param name="content">待验签内容</param>
	/// <param name="signature">待比较的签名结果</param>
	/// <param name="publicKey">EC公钥</param>
	/// <returns></returns>
	public static bool verify(byte[] content, byte[] signature, ECPublicKeyParameters publicKey) {
		ISigner signer = SignerUtilities.GetSigner(SIGN_ALGORITHM);

		signer.Init(false, publicKey);
		signer.BlockUpdate(content, 0, content.Length);

		return signer.VerifySignature(signature);
	}

	//使用SM2(国密2)算法解密数据
	public static byte[] decrypt(byte[] cipherText, ECPrivateKeyParameters privateKey) {
		SM2Engine sm2Engine = new SM2Engine();
		sm2Engine.Init(false, privateKey);
		return sm2Engine.ProcessBlock(cipherText, 0, cipherText.Length);
	}

	//使用SM2(国密2)算法加密数据
	public static byte[] encrypt(byte[] plainText, ECPublicKeyParameters publicKey) {
		SM2Engine sm2Engine = new SM2Engine();
		sm2Engine.Init(true, new ParametersWithRandom(publicKey, random));
		return sm2Engine.ProcessBlock(plainText, 0, plainText.Length);
	}

	/**
	 * convert a privateKey to string
	 * @param privateKey 私钥
	 * @return 私钥字符串,以base64编码
	 */
	public static string privateKey2Str(ECPrivateKeyParameters privateKey) {
		return Convert.ToBase64String(privateKey2Bytes(privateKey));
	}

	public static byte[] privateKey2Bytes(ECPrivateKeyParameters privateKey) {
		return privateKey.D.ToByteArray();
	}

	/**
	 * convert the privateKey to string
	 * @return 私钥字符串,以base64编码
	 */
	public string privateKey2Str() {
		return privateKey2Str(this.privateKey);
	}

	/**
	 * 将私钥从字符串转为私钥对象
	 * @param content 私钥字符串,标准base64格式
	 * @return 私钥
	 */
	public static ECPrivateKeyParameters str2PrivateKey(string privateKey) {
		byte[] publicKeyBytes = Convert.FromBase64String(privateKey);
		return bytes2PrivateKey(publicKeyBytes);
	}

	public static ECPrivateKeyParameters bytes2PrivateKey(byte[] privateKey) {
		BigInteger D = new BigInteger(1, privateKey);
		return new ECPrivateKeyParameters(D, domainParameters);
	}

	/**
	 * convert a publicKey to string
	 * @param publicKey 公钥
	 * @return 公钥字符串,以base64格式返回
	 */
	public static string publicKey2Str(ECPublicKeyParameters publicKey) {
		BigInteger x = publicKey.Q.AffineXCoord.ToBigInteger();
		BigInteger y = publicKey.Q.AffineYCoord.ToBigInteger();
		byte[] bX = x.ToByteArray();
		byte[] bY = y.ToByteArray();
		int xLen = bX.Length;
		byte[] key = new byte[1 + xLen + bY.Length];
		key[0] = (byte)xLen; //EC256的情况为32
		Array.Copy(bX, 0, key, 1, xLen);
		Array.Copy(bY, 0, key, 1 + xLen, bY.Length);

		return Convert.ToBase64String(key);
	}

	public string publicKey2Str() {
		return publicKey2Str(this.publicKey);
	}

	/**
	 * 将公钥从字符串转为私钥对象
	 * @param content 公钥字符串,标准base64格式
	 * @return 公钥
	 */
	public static ECPublicKeyParameters str2PublicKey(string publicKey) {
		byte[] key = Convert.FromBase64String(publicKey);
		return bytes2PublicKey(key);
	}

	public static ECPublicKeyParameters bytes2PublicKey(byte[] key) {
		int xLen = (key[0]) & 0xff;
		if (xLen >= key.Length) {
			throw new ArgumentException("Invalid key data");
		}
		byte[] x = new byte[xLen];
		Array.Copy(key, 1, x, 0, xLen);
		byte[] y = new byte[key.Length - 1 - xLen];
		Array.Copy(key, 1 + xLen, y, 0, y.Length);
		ECPoint Q = domainParameters.Curve.ValidatePoint(new BigInteger(1, x), new BigInteger(1, y));
		return new ECPublicKeyParameters(Q, domainParameters);
	}
}
}

        

        

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用 C# 语言使用 PEM 密钥的本地文件 RSA 加密解密信息,以及 SHA256 的签名与验代码: 加密: ``` using System; using System.IO; using System.Security.Cryptography; using System.Text; public static string Encrypt(string publicKeyPath, string plainText) { var rsa = new RSACryptoServiceProvider(); var publicKey = File.ReadAllText(publicKeyPath); rsa.FromXmlString(publicKey); var plainBytes = Encoding.UTF8.GetBytes(plainText); var encryptedBytes = rsa.Encrypt(plainBytes, false); return Convert.ToBase64String(encryptedBytes); } ``` 解密: ``` using System; using System.IO; using System.Security.Cryptography; using System.Text; public static string Decrypt(string privateKeyPath, string encryptedText) { var rsa = new RSACryptoServiceProvider(); var privateKey = File.ReadAllText(privateKeyPath); rsa.FromXmlString(privateKey); var encryptedBytes = Convert.FromBase64String(encryptedText); var plainBytes = rsa.Decrypt(encryptedBytes, false); return Encoding.UTF8.GetString(plainBytes); } ``` 签名: ``` using System; using System.IO; using System.Security.Cryptography; using System.Text; public static string Sign(string privateKeyPath, string plainText) { var rsa = new RSACryptoServiceProvider(); var privateKey = File.ReadAllText(privateKeyPath); rsa.FromXmlString(privateKey); var plainBytes = Encoding.UTF8.GetBytes(plainText); var signatureBytes = rsa.SignData(plainBytes, new SHA256CryptoServiceProvider()); return Convert.ToBase64String(signatureBytes); } ``` 验签: ``` using System; using System.IO; using System.Security.Cryptography; using System.Text; public static bool Verify(string publicKeyPath, string plainText, string signatureText) { var rsa = new RSACryptoServiceProvider(); var publicKey = File.ReadAllText(publicKeyPath); rsa.FromXmlString(publicKey); var plainBytes = Encoding.UTF8.GetBytes(plainText); var signatureBytes = Convert.FromBase64String(signatureText); return rsa.VerifyData(plainBytes, new SHA256CryptoServiceProvider(), signatureBytes); } ``` 注意:以上代码仅供参考,实际使用时需要根据具体情况进行修改和调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值