diff --git a/Code-generation-validation.md b/Code-generation-validation.md new file mode 100644 index 0000000..4bfee0f --- /dev/null +++ b/Code-generation-validation.md @@ -0,0 +1,69 @@ +# Code generation/validation +Here we will look at how to generate an OTP on client side and validate it on server side + +## Code generation +### Time-based OTP +For TOTP it's quite simple: you load your OTP configuration from your storage (in this example it's `Xamarin.Essentials.Preferences`) and then generate a new OTP code with `OTPService` +```csharp +OTPConfiguration totpConfig = JsonConvert.DeserializeObject(Preferences.Get("myTotpConfig", "")); + +OTPCode code = OTPService.GenerateCode(ref totpConfig); +Debug.WriteLine(code); // OTPasswordModel { Code = 350386, Expiring = 23-May-21 06:08:30 PM } +``` + +### HMAC-based OTP +For HOTPs it's important to update your configuration after code generation because it's based on a counter which should be incremented each time you generate a password: +```csharp +OTPConfiguration hotpConfig = JsonConvert.DeserializeObject(Preferences.Get("myHotpConfig", "")); + +OTPCode code = OTPService.GenerateCode(ref hotpConfig); +Debug.WriteLine(code); // OTPasswordModel { Code = 350386, Expiring = null } // Since HOTP isn't time related, it doesn't have expiration time +Preferences.Set("myHotpConfig", JsonConvert.SerializeObject(hotpConfig)); // It's important to update configuration to prevent desynchronization with server +``` +It's also recommended to not let user generate HOTP in one action. Make sure you've notified user that generating code for no reason can cause a desynchronization with the server, thus inability to log in + +## Code validation +### Time-based OTP +Code validation is quite like what we do with code generation. In this example as storage location, we will use an `DatabaseContext` from ASP.NET since usually validation occurs on server side +```csharp +[HttpGet] +public IActionResult Get(int code, Guid id) +{ + OTPConfiguration totpConfig = db.Configs.Find(id); + if (OTPService.ValidateTotp(code, totpConfig, TimeSpan.FromSeconds(30))) + return Ok(); + else + return Forbidden(); +} +``` +`TimeSpan.FromSeconds(30)` here is tolerance time which defines a set of periods, thus OTP codes which are valid at that moment. This is used to handle time desynchronization between server and client. If `OTPConfiguration.Period` is equal to 30 seconds, this tolerance time suggests that at that moment there're 3 valid OTP codes: current one, previous one and next one: +``` + t - 30 t t + 30 + | | | +| (n - 1)-th period | n-th period | (n + 1)-th period | +``` + +Recommended tolerance time: 30 seconds + +### HMAC-based OTP +Similar to code generation, after code validation you need to update configuration in your storage. Note that HOTP counter increments only on successful validation +```csharp +[HttpGet] +public IActionResult Get(int code, Guid id) +{ + OTPConfiguration hotpConfig = db.Configs.Find(id); + if (OTPService.ValidateHotp(code, ref hotpConfig, 1, true)) // 1 - toleranceSpan; true - resyncCounter + { + db.Update(hotpConfig); + db.SaveChanges(); + return Ok(); + } + else + return Forbidden(); +} +``` +For HOTP configuration tolerance span is presented in number of preceding and subsequent counters which should be treated as valid. Last parameter is `resyncCounter` and determines if `OTPService.ValidateHotp` should update counter according to provided OTP code + +Recommended tolerance span: 1-2 + +It is also recommended to dismiss validated code to prevent from using it second time \ No newline at end of file