Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
TotpValidator.cs
1using System;
2using System.Threading.Tasks;
6
8{
13 public class TotpValidator
14 {
18 public const string ProtocolName = "TOTP";
19
20 private readonly int nrDigits;
21 private readonly byte[] secret;
22 private readonly HashFunction hashFunction;
23 private readonly LoginAuditor auditor;
24 private readonly string endpoint;
25 private readonly int timeStepSeconds;
26 private readonly long t0;
27
35 public TotpValidator(byte[] Secret, string OtpEndpoint, LoginAuditor Auditor)
36 : this(HotpCalculator.DefaultNrDigits, Secret,
37 HotpCalculator.DefaultHashFunction, TotpCalculator.DefaultTimeStepSeconds,
39 {
40 }
41
50 public TotpValidator(int NrDigits, byte[] Secret, string OtpEndpoint, LoginAuditor Auditor)
51 : this(NrDigits, Secret, HotpCalculator.DefaultHashFunction,
52 TotpCalculator.DefaultTimeStepSeconds, OtpEndpoint, Auditor)
53 {
54 }
55
66 public TotpValidator(int NrDigits, byte[] Secret, HashFunction HashFunction,
68 : this(NrDigits, Secret, HashFunction, TimeStepSeconds, TotpCalculator.DefaultT0,
70 {
71 }
72
84 public TotpValidator(int NrDigits, byte[] Secret, HashFunction HashFunction,
85 int TimeStepSeconds, long T0, string OtpEndpoint, LoginAuditor Auditor)
86 {
87 HotpCalculator.CheckNrDigits(NrDigits);
88 HotpCalculator.CheckSecret(Secret);
89 TotpCalculator.CheckTimeStepSeconds(TimeStepSeconds, T0);
90
91 this.nrDigits = NrDigits;
92 this.secret = Secret;
93 this.hashFunction = HashFunction;
94 this.endpoint = OtpEndpoint;
95 this.auditor = Auditor;
96 this.timeStepSeconds = TimeStepSeconds;
97 this.t0 = T0;
98 }
99
103 public int NrDigits => this.nrDigits;
104
108 public HashFunction HashFunction => this.hashFunction;
109
113 public int TimeStepSeconds => this.timeStepSeconds;
114
118 public string OtpEndpoint => this.endpoint;
119
123 public LoginAuditor Auditor => this.auditor;
124
131 public static async Task<TotpValidator> TryCreate(string OtpEndpoint, LoginAuditor Auditor)
132 {
134 if (Secret is null || !Secret.HashFunction.HasValue)
135 return null;
136
137 return new TotpValidator(Secret.NrDigits, Secret.Secret, Secret.HashFunction.Value,
139 }
140
149 public Task<ValidationResult> Validate(string OtpEndpoint, string RemoteEndPoint,
150 DateTime Timestamp, int PassCode)
151 {
152 return Validate(this.nrDigits, this.secret, this.hashFunction, OtpEndpoint,
153 RemoteEndPoint, Timestamp, this.timeStepSeconds, PassCode, this.auditor);
154 }
155
167 public static Task<ValidationResult> Validate(byte[] Secret, string OtpEndpoint,
168 string RemoteEndPoint, DateTime Timestamp, int TimeStepSeconds, int PassCode,
170 {
172 RemoteEndPoint, Timestamp, TimeStepSeconds, PassCode, Auditor);
173 }
174
187 public static Task<ValidationResult> Validate(int NrDigits, byte[] Secret,
188 string OtpEndpoint, string RemoteEndPoint, DateTime Timestamp, int TimeStepSeconds,
189 int PassCode, LoginAuditor Auditor)
190 {
192 OtpEndpoint, RemoteEndPoint, Timestamp, TimeStepSeconds, PassCode, Auditor);
193 }
194
208 public static async Task<ValidationResult> Validate(int NrDigits, byte[] Secret,
209 HashFunction HashFunction, string OtpEndpoint, string RemoteEndPoint,
210 DateTime Timestamp, int TimeStepSeconds, int PassCode, LoginAuditor Auditor)
211 {
212 return await Validate(NrDigits, Secret, HashFunction, OtpEndpoint,
213 RemoteEndPoint, Timestamp, TimeStepSeconds, TotpCalculator.DefaultT0,
214 PassCode, Auditor);
215 }
216
231 public static async Task<ValidationResult> Validate(int NrDigits, byte[] Secret,
232 HashFunction HashFunction, string OtpEndpoint, string RemoteEndPoint,
233 DateTime Timestamp, int TimeStepSeconds, long T0, int PassCode,
235 {
236 using Semaphore Lock = await Semaphores.BeginWrite(ProtocolName + ":" + OtpEndpoint);
237
238 string Key = ProtocolName + "." + OtpEndpoint;
239 long LastCounter = await RuntimeCounters.GetCount(Key);
240 long Counter = TotpCalculator.CalcCounter(Timestamp, TimeStepSeconds, T0);
241
242 if (Counter <= LastCounter)
243 {
244 LoginAuditor.Fail("Counter value not valid (replay attack?).", OtpEndpoint,
245 RemoteEndPoint, ProtocolName);
246 return new ValidationResult();
247 }
248
249 await RuntimeCounters.IncrementCounter(Key, Counter - LastCounter);
250
251 DateTime? EarliestOpportunity = await Auditor.GetEarliestLoginOpportunity(RemoteEndPoint, ProtocolName);
252 if (EarliestOpportunity.HasValue)
253 return new ValidationResult(EarliestOpportunity.Value);
254
255 int Expected = HotpCalculator.Compute(NrDigits, Secret, HashFunction, Counter);
256 bool Ok = Expected == PassCode;
257
258 if (!Ok) // Check previous time step
259 {
260 Counter--; // Checking -1
261 Expected = HotpCalculator.Compute(NrDigits, Secret, HashFunction, Counter);
262 Ok = Expected == PassCode;
263
264 if (Ok)
266 else
267 {
268 Counter += 2; // Checking +1
269 Expected = HotpCalculator.Compute(NrDigits, Secret, HashFunction, Counter);
270 Ok = Expected == PassCode;
271
272 if (Ok)
274 }
275 }
276
277 if (Ok)
278 {
279 LoginAuditor.Success(ProtocolName + " authentication successful.",
280 OtpEndpoint, RemoteEndPoint, ProtocolName);
281 }
282 else
283 {
284 LoginAuditor.Fail(ProtocolName + " authentication failed.",
285 OtpEndpoint, RemoteEndPoint, ProtocolName);
286 }
287
288 return new ValidationResult(Ok);
289 }
290 }
291}
Static class managing persistent counters.
static Task< long > IncrementCounter(CaseInsensitiveString Key)
Increments a counter.
static Task< long > DecrementCounter(CaseInsensitiveString Key)
Decrements a counter.
static async Task< long > GetCount(CaseInsensitiveString Key)
Gets the current count of a counter.
Represents a named semaphore, i.e. an object, identified by a name, that allows single concurrent wri...
Definition: Semaphore.cs:19
Static class of application-wide semaphores that can be used to order access to editable objects.
Definition: Semaphores.cs:17
static async Task< Semaphore > BeginWrite(string Key)
Waits until the semaphore identified by Key is ready for writing. Each call to BeginWrite must be fo...
Definition: Semaphores.cs:91
Class that monitors login events, and help applications determine malicious intent....
Definition: LoginAuditor.cs:26
async Task< DateTime?> GetEarliestLoginOpportunity(string RemoteEndPoint, string Protocol)
Checks when a remote endpoint can login.
static async void Success(string Message, string UserName, string RemoteEndPoint, string Protocol, params KeyValuePair< string, object >[] Tags)
Handles a successful login attempt.
static void Fail(string Message, string UserName, string RemoteEndPoint, string Protocol)
Handles a failed login attempt.
Contains OTP secret information for an OTP endpoint.
HashFunction? HashFunction
Hash function used for the endpoint.
Implements the HOTP calculator algorithm, as defined in RFC 4226: https://datatracker....
int Compute(long Counter)
Calculates the expected one-time-password for the given counter value.
const int DefaultNrDigits
Default number of digits (6).
const HashFunction DefaultHashFunction
Default Hash Function (SHA-1)
Implements the TOTP calculator algorithm, as defined in RFC 6238: https://datatracker....
const long DefaultT0
Default time when starting counting steps (0).
static long CalcCounter(DateTime Timestamp, int TimeStepSeconds, long T0)
Calculates the counter number for use with the HOTP algorithm.
Implements the TOTP validator algorithm, as defined in RFC 6238: https://datatracker....
int TimeStepSeconds
Time step in seconds.
static async Task< TotpValidator > TryCreate(string OtpEndpoint, LoginAuditor Auditor)
Tries to create an TOTP calculator for the given endpoint.
TotpValidator(int NrDigits, byte[] Secret, HashFunction HashFunction, int TimeStepSeconds, string OtpEndpoint, LoginAuditor Auditor)
Implements the TOTP validator algorithm, as defined in RFC 6238: https://datatracker....
static async Task< ValidationResult > Validate(int NrDigits, byte[] Secret, HashFunction HashFunction, string OtpEndpoint, string RemoteEndPoint, DateTime Timestamp, int TimeStepSeconds, long T0, int PassCode, LoginAuditor Auditor)
Calculates the expected one-time-password for the given counter value.
static async Task< ValidationResult > Validate(int NrDigits, byte[] Secret, HashFunction HashFunction, string OtpEndpoint, string RemoteEndPoint, DateTime Timestamp, int TimeStepSeconds, int PassCode, LoginAuditor Auditor)
Calculates the expected one-time-password for the given counter value.
static Task< ValidationResult > Validate(byte[] Secret, string OtpEndpoint, string RemoteEndPoint, DateTime Timestamp, int TimeStepSeconds, int PassCode, LoginAuditor Auditor)
Calculates the expected one-time-password for the given counter value.
TotpValidator(int NrDigits, byte[] Secret, HashFunction HashFunction, int TimeStepSeconds, long T0, string OtpEndpoint, LoginAuditor Auditor)
Implements the TOTP validator algorithm, as defined in RFC 6238: https://datatracker....
TotpValidator(int NrDigits, byte[] Secret, string OtpEndpoint, LoginAuditor Auditor)
Implements the TOTP validator algorithm, as defined in RFC 6238: https://datatracker....
int NrDigits
Number of digits to present.
static Task< ValidationResult > Validate(int NrDigits, byte[] Secret, string OtpEndpoint, string RemoteEndPoint, DateTime Timestamp, int TimeStepSeconds, int PassCode, LoginAuditor Auditor)
Calculates the expected one-time-password for the given counter value.
HashFunction HashFunction
Hash function to use in computation.
TotpValidator(byte[] Secret, string OtpEndpoint, LoginAuditor Auditor)
Implements the TOTP validator algorithm, as defined in RFC 6238: https://datatracker....
const string ProtocolName
Protocol name (TOTP).
Task< ValidationResult > Validate(string OtpEndpoint, string RemoteEndPoint, DateTime Timestamp, int PassCode)
Calculates the expected one-time-password for the given counter value.
LoginAuditor Auditor
Login auditor.
Contains information of a HOTP or TOTP validation attempt.
CredentialAlgorithm
Specifies the type of external credential algorithm to use.
HashFunction
Hash method enumeration.
Definition: Hashes.cs:26