Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
EcdsaAlgorithm.cs
1using System;
2using System.Globalization;
3using System.Reflection;
4using System.Text;
7using Waher.Events;
11using Waher.Security;
13
15{
19 public abstract class EcdsaAlgorithm : SignatureAlgorithm
20 {
29 public override bool VerifySignature(byte[] Data, byte[] Signature, IPublicKey PublicKey,
30 ICommunicationLayer? Client)
31 {
32 if (PublicKey is not EllipticCurvePublicKey ECPublicKey)
33 {
34 Client?.Error("No ECDSA public key provided or found.");
35 return false;
36 }
37
38 return VerifySignature(Data, Signature, ECPublicKey, this.HashAlgorithm,
39 this.HashAlgorithmStream, Client);
40 }
41
52 public static bool VerifySignature(byte[] Data, byte[] Signature,
55 {
56 System.Numerics.BigInteger Order = PublicKey.Order;
57 System.Numerics.BigInteger Cofactor = PublicKey.CoFactor;
58 System.Numerics.BigInteger A = PublicKey.A;
59 System.Numerics.BigInteger B = PublicKey.B;
60 PointOnCurve BasePoint = PublicKey.BasePoint;
61 PointOnCurve PublicKeyPoint = PublicKey.PublicKey;
62 bool HasSniffer = Client?.HasSniffers ?? false;
63
64 if (!ASN1.TryDecodeDer(Client, Signature, out object? Obj) ||
65 Obj is not Vector SignatureVector ||
66 SignatureVector.Length != 2 ||
67 SignatureVector.FirstElement is not System.Numerics.BigInteger R ||
68 SignatureVector[1] is not System.Numerics.BigInteger S)
69 {
70 if (HasSniffer)
71 Client!.Error("Unable to parse signature: " + Hashes.BinaryToString(Signature));
72
73 return false;
74 }
75
76 StringBuilder? Msg = HasSniffer ? new StringBuilder() : null;
77
78 if (HasSniffer)
79 {
80 Msg!.AppendLine("ECDSA signature verification parameters:");
81 Msg.Append("A (dec): ");
82 Msg.AppendLine(A.ToString(CultureInfo.InvariantCulture));
83 Msg.Append("B (dec): ");
84 Msg.AppendLine(B.ToString(CultureInfo.InvariantCulture));
85 Msg.Append("Order (dec): ");
86 Msg.AppendLine(Order.ToString(CultureInfo.InvariantCulture));
87 Msg.Append("Cofactor (dec): ");
88 Msg.AppendLine(Cofactor.ToString(CultureInfo.InvariantCulture));
89 Msg.Append("BasePoint.X (dec): ");
90 Msg.AppendLine(BasePoint.X.ToString(CultureInfo.InvariantCulture));
91 Msg.Append("BasePoint.Y (dec): ");
92 Msg.AppendLine(BasePoint.Y.ToString(CultureInfo.InvariantCulture));
93 Msg.Append("PublicKey.X (dec): ");
94 Msg.AppendLine(PublicKeyPoint.X.ToString(CultureInfo.InvariantCulture));
95 Msg.Append("PublicKey.Y (dec): ");
96 Msg.AppendLine(PublicKeyPoint.Y.ToString(CultureInfo.InvariantCulture));
97 Msg.Append("S (Signature, hex): ");
98 Msg.AppendLine(Hashes.BinaryToString(Signature));
99 Msg.Append("R (dec): ");
100 Msg.AppendLine(R.ToString(CultureInfo.InvariantCulture));
101 Msg.Append("S (dec): ");
102 Msg.AppendLine(S.ToString(CultureInfo.InvariantCulture));
103 Msg.Append("Hash function: ");
104 Msg.AppendLine(HashAlgorithm.Method.Name);
105 Msg.Append("Message (hex): ");
106 Msg.AppendLine(Hashes.BinaryToString(Data));
107 }
108
109 PrimeFieldCurve? Selected = null;
110
111 if (PublicKey.HasNamedCurve)
112 {
113 if (PublicKey.NamedCurve is PrimeFieldCurve PrimeFieldCurve)
114 Selected = PrimeFieldCurve;
115 else
116 {
117 if (HasSniffer)
118 {
119 Client!.Information(Msg!.ToString());
120 Client.Error("Named curve not supported by ECDSA: " + PublicKey.NamedCurve.CurveName);
121 }
122
123 return false;
124 }
125 }
126 else if (PublicKey.Field is PrimeField PrimeField)
127 {
128 System.Numerics.BigInteger Prime = PrimeField.Prime;
129
130 foreach (EllipticCurve EC in curves)
131 {
132 if (EC.Order != Order ||
133 EC.Cofactor != Cofactor ||
134 EC.BasePoint.X != BasePoint.X ||
135 EC.BasePoint.Y != BasePoint.Y)
136 {
137 continue;
138 }
139
140 if (EC is not PrimeFieldCurve PrimeFieldCurve)
141 continue;
142
143 if (PrimeFieldCurve.Prime != Prime)
144 continue;
145
147 {
148 if (WeierstrassCurve.A != A || WeierstrassCurve.B != B)
149 continue;
150 }
151 else if (EC is MontgomeryCurve MontgomeryCurve)
152 {
153 if (MontgomeryCurve.A != A)
154 continue;
155 }
156 else if (EC is EdwardsCurve EdwardsCurve)
157 {
158 if (EdwardsCurve.D != A)
159 continue;
160 }
162 {
163 if (EdwardsTwistedCurve.D != A)
164 continue;
165 }
166 else
167 continue;
168
169 Selected = PrimeFieldCurve;
170 break;
171 }
172
173 if (Selected is null)
174 {
175 if (HasSniffer)
176 Msg!.AppendLine("Elliptic Curve not recognized. A custom Weierstras curve will be used.");
177
178 if (Cofactor < int.MinValue || Cofactor > int.MaxValue)
179 {
180 if (HasSniffer)
181 {
182 Client!.Information(Msg!.ToString());
183 Client.Error("Unsupported cofactor.");
184 }
185
186 return false;
187 }
188
189 Selected = new CustomWeierstrassCurve("Custom", Prime, BasePoint, A, B,
190 Order, (int)Cofactor, HashAlgorithm, HashAlgorithmStream);
191 }
192 else if (Selected.HashFunction != HashAlgorithm ||
194 {
195 if (HasSniffer)
196 {
197 Msg!.Append("Elliptic Curve Hash algorithm not standard: ");
198 Msg.Append(HashAlgorithm.Method.Name);
199 Msg.Append(" (instead of ");
200 Msg.Append(Selected.HashFunction.Method.Name);
201 Msg.AppendLine(")");
202 }
203
204 Selected = new CustomWeierstrassCurve(Selected.CurveName, Prime, BasePoint, A, B,
205 Order, Selected.Cofactor, HashAlgorithm, HashAlgorithmStream);
206 }
207 }
208 else
209 {
210 if (HasSniffer)
211 {
212 Client!.Information(Msg!.ToString());
213 Client.Error("Curve field type not supported: " + PublicKey.Field.GetType().FullName);
214 }
215
216 return false;
217 }
218
219 ASN1.ReportAlgorithmUse(Selected);
220
221 if (HasSniffer)
222 {
223 Msg!.Append("Curve used for signature: ");
224 Msg.Append(Selected.CurveName);
225 Msg.Append(" (implemented by ");
226 Msg.Append(Selected.GetType().FullName);
227 Msg.AppendLine(")");
228 }
229
230 if (!Selected.IsPoint(PublicKeyPoint))
231 {
232 if (HasSniffer)
233 {
234 Client!.Information(Msg!.ToString());
235 Client.Error("Public key not a point on curve.");
236 }
237
238 return false;
239 }
240
241 if (!ECDSA.Verify(Data, PublicKeyPoint, HashAlgorithm, Selected, R, S))
242 {
243 if (HasSniffer)
244 {
245 Client!.Information(Msg!.ToString());
246 Client.Error("ECDSA validation failed.");
247 }
248
249 return false;
250 }
251
252 if (HasSniffer)
253 Client!.Information(Msg!.ToString());
254
255 return true;
256 }
257
258 private static readonly EllipticCurve[] curves = GetEllipticCurves();
259
260 private static EllipticCurve[] GetEllipticCurves()
261 {
262 ChunkedList<EllipticCurve> EllipticCurves = [];
263
265 {
266 ConstructorInfo? CI = Types.GetDefaultConstructor(T);
267 if (CI is null)
268 continue;
269
270 try
271 {
273 if (Algorithm is EllipticCurve Curve)
274 EllipticCurves.Add(Curve);
275 }
276 catch (Exception ex)
277 {
278 Log.Exception(ex);
279 }
280 }
281
282 return [.. EllipticCurves];
283 }
284
288 public abstract HashFunctionArray HashAlgorithm { get; }
289
294 }
295}
Static class for parsing and decoding security objects encoded using Abstract Syntax Notation 1 (ASN....
Definition: ASN1.cs:22
static bool TryDecodeDer(byte[] Data, out object? Value)
Decodes a DER-encoded object.
Definition: ASN1.cs:77
static int ReportAlgorithmUse(string Name)
Records an Elliptic Curve has been used.
Definition: ASN1.cs:420
BigInteger Prime
Prime number used to define the prime field.
Definition: PrimeField.cs:60
override bool VerifySignature(byte[] Data, byte[] Signature, IPublicKey PublicKey, ICommunicationLayer? Client)
Verifies a digital signature.
abstract HashFunctionStream HashAlgorithmStream
Hash algorithm to use for streams of data.
abstract HashFunctionArray HashAlgorithm
Hash algorithm to use for in-memory blocks of data.
static bool VerifySignature(byte[] Data, byte[] Signature, EllipticCurvePublicKey PublicKey, HashFunctionArray HashAlgorithm, HashFunctionStream HashAlgorithmStream, ICommunicationLayer? Client)
Verifies a digital signature using the ECDSA algorithm.
Abstract base class for signature algorithms, as defined in RFC 5280.
Static class managing the application event log. Applications and services log events on this static ...
Definition: Log.cs:14
static void Exception(Exception Exception, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, params KeyValuePair< string, object >[] Tags)
Logs an exception. Event type will be determined by the severity of the exception.
Definition: Log.cs:1657
A chunked list is a linked list of chunks of objects of type T .
Definition: ChunkedList.cs:54
void Add(T Item)
Adds an item to the collection.
Definition: ChunkedList.cs:272
Static class that dynamically manages types and interfaces available in the runtime environment.
Definition: Types.cs:15
static object[] NoParameters
Contains an empty array of parameter values.
Definition: Types.cs:572
static Type[] GetTypesImplementingInterface(string InterfaceFullName)
Gets all types implementing a given interface.
Definition: Types.cs:85
static ConstructorInfo GetDefaultConstructor(Type Type)
Gets the default constructor of a type, if one exists.
Definition: Types.cs:1742
Custom Weierstrass curves (y²=x³+ax+b) over a prime field.
Implements the Elliptic Curve Digital Signature Algorithm (ECDSA).
Definition: ECDSA.cs:11
static bool Verify(byte[] Data, byte[] PublicKey, bool BigEndian, HashFunctionArray HashFunction, PrimeFieldCurve Curve, byte[] Signature)
Verifies a signature of Data made by the ECDSA algorithm.
Definition: ECDSA.cs:184
BigInteger D
d coefficient of Edwards curve.
Base class of Edwards curves (x²+y²=1+dx²y²) over a prime field.
Definition: EdwardsCurve.cs:10
Base class of Twisted Edwards curves (-x²+y²=1+dx²y²) over a prime field.
Abstract base class for elliptic curves.
abstract string CurveName
Name of curve.
virtual bool IsPoint(byte[] Point)
Checks if an encoded point is on the curve.
PointOnCurve BasePoint
Base-point of curve.
Base class of Montgomery curves (y²=x³+Ax²+x), with birational Edwards equivalent over a prime field.
Base class of Elliptic curves over a prime field.
virtual HashFunctionStream HashFunctionStream
Hash function to use in signatures for data streams.
virtual HashFunctionArray HashFunction
Hash function to use in signatures for binary blocks of data in memory.
Base class of Weierstrass curves (y²=x³+ax+b) over a prime field.
Contains methods for simple hash calculations.
Definition: Hashes.cs:57
static string BinaryToString(byte[] Data)
Converts an array of bytes to a string with their hexadecimal representations (in lower case).
Definition: Hashes.cs:63
void Information(string Comment)
Called to inform the viewer of something.
void Error(string Error)
Called to inform the viewer of an error state.
Interface for observable classes implementing communication protocols.
bool HasSniffers
If there are sniffers registered on the object.
Interface for digital signature algorithms.
delegate byte[] HashFunctionStream(Stream Data)
Delegate to hash function.
delegate byte[] HashFunctionArray(byte[] Data)
Delegate to hash function.
Definition: App.xaml.cs:4
Represents a point on a curve.
Definition: PointOnCurve.cs:10