chovy-sign/PspCrypto/Security/Cryptography/ECDsaManaged.cs

171 lines
7.1 KiB
C#

using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Signers;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Math.EC;
using Org.BouncyCastle.Security;
using System;
namespace PspCrypto.Security.Cryptography
{
internal class ECDsaManaged : System.Security.Cryptography.ECDsa
{
private ECKeyParameters _ecKeyParameters;
private readonly bool _ebootPbp;
private readonly int _type;
public ECDsaManaged()
{
}
public ECDsaManaged(System.Security.Cryptography.ECParameters parameters, bool ebootPbp, int type)
{
_ebootPbp = ebootPbp;
_type = type;
var gx = new BigInteger(1, parameters.Curve.G.X);
var gy = new BigInteger(1, parameters.Curve.G.Y);
var curve = ConvertECCurve(parameters.Curve);
var g = curve.CreatePoint(gx, gy);
var domainParameters = new ECDomainParameters(curve, g, curve.Order);
if (parameters.D != null)
{
var privateKey = new BigInteger(1, parameters.D);
_ecKeyParameters = new ECPrivateKeyParameters(privateKey, domainParameters);
}
else if (parameters.Q.X != null && parameters.Q.Y != null)
{
var publicKey = curve.CreatePoint(new BigInteger(1, parameters.Q.X), new BigInteger(1, parameters.Q.Y));
_ecKeyParameters = new ECPublicKeyParameters(publicKey, domainParameters);
}
else
{
throw new ArgumentException("invalid parameters", nameof(parameters));
}
}
public override byte[] SignHash(byte[] hash)
{
if (_ecKeyParameters is not ECPrivateKeyParameters)
{
throw new ArgumentException("key is not private Key");
}
var signer = CreateSigner();
signer.Init(true, _ecKeyParameters);
signer.BlockUpdate(hash);
return signer.GenerateSignature();
}
public override bool VerifyHash(byte[] hash, byte[] signature)
{
var signer = CreateSigner();
if (_ecKeyParameters is ECPrivateKeyParameters ecPrivateKeyParameters)
{
var publicKey = new ECPublicKeyParameters(
ecPrivateKeyParameters.Parameters.G.Multiply(ecPrivateKeyParameters.D),
ecPrivateKeyParameters.Parameters);
signer.Init(false, publicKey);
}
else
{
signer.Init(false, _ecKeyParameters);
}
signer.BlockUpdate(hash);
return signer.VerifySignature(signature);
}
protected override byte[] HashData(byte[] data, int offset, int count, System.Security.Cryptography.HashAlgorithmName hashAlgorithm)
{
var dataSpan = new ReadOnlySpan<byte>(data, offset, count);
if (hashAlgorithm == System.Security.Cryptography.HashAlgorithmName.SHA256)
{
return System.Security.Cryptography.SHA256.HashData(dataSpan);
}
else if (hashAlgorithm == System.Security.Cryptography.HashAlgorithmName.SHA1)
{
return System.Security.Cryptography.SHA1.HashData(dataSpan);
}
else
{
throw new NotSupportedException($"{hashAlgorithm} not supported");
}
}
private ISigner CreateSigner()
{
IDigest digest = DigestUtilities.GetDigest("NONE");
IDsa dsa = _ebootPbp ? new ECDsaSigner(new EbootPbpKCalculator(_type)) : new ECDsaSigner();
var signer = new DsaDigestSigner(dsa, digest, PlainDsaEncoding.Instance);
return signer;
}
private FpCurve _fpCurve;
public override void GenerateKey(System.Security.Cryptography.ECCurve curve)
{
_fpCurve = ConvertECCurve(curve);
var gx = new BigInteger(1, curve.G.X);
var gy = new BigInteger(1, curve.G.Y);
var g = _fpCurve.CreatePoint(gx, gy);
var domainParameters = new ECDomainParameters(_fpCurve, g, _fpCurve.Order);
var gen = new ECKeyPairGenerator();
gen.Init(new ECKeyGenerationParameters(domainParameters, new SecureRandom()));
var keyPair = gen.GenerateKeyPair();
_ecKeyParameters = (ECKeyParameters)keyPair.Private;
}
public override System.Security.Cryptography.ECParameters ExportExplicitParameters(bool includePrivateParameters)
{
var normalG = _ecKeyParameters.Parameters.G;
var curve = new System.Security.Cryptography.ECCurve
{
A = _fpCurve.A.ToBigInteger().ToByteArrayUnsigned(),
B = _fpCurve.B.ToBigInteger().ToByteArrayUnsigned(),
Prime = _fpCurve.Q.ToByteArrayUnsigned(),
Order = _fpCurve.Order.ToByteArrayUnsigned(),
Cofactor = _fpCurve.Cofactor.ToByteArrayUnsigned(),
G = new System.Security.Cryptography.ECPoint
{
X = normalG.AffineXCoord.ToBigInteger().ToByteArrayUnsigned(),
Y = normalG.AffineYCoord.ToBigInteger().ToByteArrayUnsigned()
}
};
var parameters = new System.Security.Cryptography.ECParameters
{
Curve = curve
};
if (includePrivateParameters && _ecKeyParameters is ECPrivateKeyParameters privateKeyParameters)
{
parameters.D = privateKeyParameters.D.ToByteArrayUnsigned();
var publicKey = _ecKeyParameters.Parameters.G.Multiply(privateKeyParameters.D).Normalize();
parameters.Q = new System.Security.Cryptography.ECPoint
{
X = publicKey.AffineXCoord.ToBigInteger().ToByteArrayUnsigned(),
Y = publicKey.AffineYCoord.ToBigInteger().ToByteArrayUnsigned()
};
}
else if (_ecKeyParameters is ECPublicKeyParameters publicKeyParameters)
{
var publicKey = publicKeyParameters.Q.Normalize();
parameters.Q = new System.Security.Cryptography.ECPoint
{
X = publicKey.AffineXCoord.ToBigInteger().ToByteArrayUnsigned(),
Y = publicKey.AffineYCoord.ToBigInteger().ToByteArrayUnsigned()
};
}
return parameters;
}
private static FpCurve ConvertECCurve(System.Security.Cryptography.ECCurve curve)
{
var p = new BigInteger(1, curve.Prime);
var a = new BigInteger(1, curve.A);
var b = new BigInteger(1, curve.B);
var n = new BigInteger(1, curve.Order);
var fpCurve = new FpCurve(p, a, b, n, BigInteger.One);
return fpCurve;
}
}
}