在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中不能用。
以下是几个主要函数的说明:
以上列举的这些功能在至简网格中用到,至简网格是为中小企业信息化准备的,它是一套分布式、服务化、端云结合的开发框架。它可以多实例跨机房、跨城市部署,也可以部署到一部旧手机中。提供的服务都是开源、免费的,以此为中小企业节省成本。其中用到多种技术,对这些技术点的摸索,都记录在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();
}
///
/// 签名
///
/// 待签名内容
/// EC私钥
///
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();
}
///
/// 验签
///
/// 待验签内容
/// 待比较的签名结果
/// EC公钥
///
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);
}
}
}