C# uses ECC elliptic curve algorithm to realize encryption and decryption & signature and verification, with complete code

        BouncyCastle is used in C#, Java, and Android to achieve intercommunication between multiple environments, such as public and private keys generated in Java, used in C# or Android...

        In order to get consistent results in several environments, some regressions are made in the implementation. For example, when the public key and private key are converted into strings, the parameters of the public and private keys are directly read instead of converted to PKCS8 (the default in java); for example, ECIES cannot be found in C#, so both java and C# use SM2 to implement encryption and decryption, and so on.

        It is difficult to search for relevant implementations on the Internet, so the complete code is pasted. In some places, it is not sure whether the symbol standard is not available. For example, when the public and private keys are converted into strings, the D and Q values ​​​​in it are directly used. It is not sure whether this implementation will become inapplicable in future versions. If any security expert reads this article, I hope to criticize and correct it. Tested in Java and C#, both sides can communicate with each other. On the contrary, if you use the public and private keys obtained by Key's getEncoded in Java, you cannot use them in C#; and vice versa, if you convert them to PKCS8 in C#, you cannot use them in Java.

        The following are descriptions of several main functions:

  1. genKeyPair generates a public-private key pair with a key length of 256 bits, which is said to be as strong as RSA 3072;
  2. sign uses the private key to sign, and verify uses the public key to verify the signature;
  3. encrypt uses the public key to encrypt, and decrypt uses the private key to decrypt;
  4. privateKey2Str converts the private key into a base64 string, publicKey2Str converts the public key into a base64 string, corresponding to str2PublicKey, str2PrivateKey for reverse conversion, this function is used in the interaction with js.

        The functions listed above are used in the Simple Grid . The Simple Grid is prepared for the informatization of small and medium-sized enterprises. It is a distributed, service-oriented, and terminal-cloud development framework. It can be deployed across computer rooms and cities with multiple instances, and can also be deployed to an old mobile phone. The services provided are all open source and free, so as to save costs for small and medium-sized enterprises. A variety of technologies are used in it, and the exploration of these technical points is recorded in the CSDN Zhijian Grid column , which is easy to find by yourself, and I hope to help those who need it.

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);
	}
}
}

        

        

Guess you like

Origin blog.csdn.net/flyinmind/article/details/131216774