using System; using System.Security.Cryptography; using Google.Protobuf; using Org.BouncyCastle.Asn1.Sec; using Org.BouncyCastle.Crypto.Digests; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Crypto.Signers; using Org.BouncyCastle.Math; using FrostFS.Refs; using FrostFS.SDK.Cryptography; using FrostFS.Session; namespace FrostFS.SDK.ClientV2; public static class RequestSigner { public const int RFC6979SignatureSize = 64; public static byte[] SignRFC6979(this ECDsa key, byte[] data) { var digest = new Sha256Digest(); var secp256R1 = SecNamedCurves.GetByName("secp256r1"); var ecParameters = new ECDomainParameters(secp256R1.Curve, secp256R1.G, secp256R1.N); var privateKey = new ECPrivateKeyParameters(new BigInteger(1, key.PrivateKey()), ecParameters); var signer = new ECDsaSigner(new HMacDsaKCalculator(digest)); var hash = new byte[digest.GetDigestSize()]; digest.BlockUpdate(data, 0, data.Length); digest.DoFinal(hash, 0); signer.Init(true, privateKey); var rs = signer.GenerateSignature(hash); var signature = new byte[RFC6979SignatureSize]; var rbytes = rs[0].ToByteArrayUnsigned(); var sbytes = rs[1].ToByteArrayUnsigned(); var index = RFC6979SignatureSize / 2 - rbytes.Length; rbytes.CopyTo(signature, index); index = RFC6979SignatureSize - sbytes.Length; sbytes.CopyTo(signature, index); return signature; } public static SignatureRFC6979 SignRFC6979(this ECDsa key, IMessage message) { return new SignatureRFC6979 { Key = ByteString.CopyFrom(key.PublicKey()), Sign = ByteString.CopyFrom(key.SignRFC6979(message.ToByteArray())), }; } public static SignatureRFC6979 SignRFC6979(this ECDsa key, ByteString data) { return new SignatureRFC6979 { Key = ByteString.CopyFrom(key.PublicKey()), Sign = ByteString.CopyFrom(key.SignRFC6979(data.ToByteArray())), }; } public static byte[] SignData(this ECDsa key, byte[] data) { var hash = new byte[65]; hash[0] = 0x04; key .SignHash(SHA512.Create().ComputeHash(data)) .CopyTo(hash, 1); return hash; } public static Signature SignMessagePart(this ECDsa key, IMessage? data) { var data2Sign = data is null ? Array.Empty() : data.ToByteArray(); var sig = new Signature { Key = ByteString.CopyFrom(key.PublicKey()), Sign = ByteString.CopyFrom(key.SignData(data2Sign)), }; return sig; } public static void Sign(this IVerificableMessage message, ECDsa key) { var meta = message.GetMetaHeader(); IVerificationHeader verify = message switch { IRequest => new RequestVerificationHeader(), IResponse => new ResponseVerificationHeader(), _ => throw new InvalidOperationException("Unsupported message type") }; var verifyOrigin = message.GetVerificationHeader(); if (verifyOrigin is null) verify.BodySignature = key.SignMessagePart(message.GetBody()); verify.MetaSignature = key.SignMessagePart(meta); verify.OriginSignature = key.SignMessagePart(verifyOrigin); verify.SetOrigin(verifyOrigin); message.SetVerificationHeader(verify); } }