public async Task <ActionResult> Verify([FromBody] TOTPInputModel inputClaims) { if (inputClaims == null) { return(StatusCode((int)HttpStatusCode.Conflict, new TOTPB2CResponse("Can not deserialize input claims", HttpStatusCode.Conflict))); } try { var secretKey = Convert.FromBase64String(DecryptAndBase64(inputClaims.secretKey)); var totp = new Totp(secretKey); long timeStepMatched; // Verify the TOTP code provided by the users var verificationResult = totp.VerifyTotp( inputClaims.totpCode, out timeStepMatched, VerificationWindow.RfcSpecifiedNetworkDelay); if (!verificationResult) { return(StatusCode((int)HttpStatusCode.Conflict, new TOTPB2CResponse("The verification code is invalid.", HttpStatusCode.Conflict))); } // Using the input claim 'timeStepMatched', we check whether the verification code has already been used. // For sign-up, the 'timeStepMatched' input claim is null and should not be evaluated // For sign-in, the 'timeStepMatched' input claim contains the last time last matched (from the user profile), and evaluated with // the value of the result of the TOTP out 'timeStepMatched' variable if (string.IsNullOrEmpty(inputClaims.timeStepMatched) == false && Convert.ToInt64(inputClaims.timeStepMatched ?? "0") >= timeStepMatched) { return(StatusCode((int)HttpStatusCode.Conflict, new TOTPB2CResponse("The verification code has already been used.", HttpStatusCode.Conflict))); } var output = new TOTPB2CResponse(string.Empty, HttpStatusCode.OK) { timeStepMatched = timeStepMatched.ToString() }; return(Ok(output)); } catch (Exception ex) { return(StatusCode((int)HttpStatusCode.Conflict, new TOTPB2CResponse($"General error (REST API): {ex.Message}", HttpStatusCode.Conflict))); } }
public async Task <ActionResult> Generate([FromBody] TOTPInputModel inputClaims) { if (inputClaims == null) { return(StatusCode((int)HttpStatusCode.Conflict, new TOTPB2CResponse("Can not deserialize input claims", HttpStatusCode.Conflict))); } try { // Define the URL for the QR code. When user scan this URL, it opens one of the // authentication apps running on the mobile device var secretKey = KeyGeneration.GenerateRandomKey(20); var TOTPUrl = KeyUrl.GetTotpUrl(secretKey, $"{_settings.AccountPrefix}:{inputClaims.userName}", _settings.Timestep); TOTPUrl = $"{TOTPUrl}&issuer={_settings.Issuer.Replace(" ", "%20")}"; // Generate QR code for the above URL var qrCodeGenerator = new QRCodeGenerator(); var qrCodeData = qrCodeGenerator.CreateQrCode(TOTPUrl, QRCodeGenerator.ECCLevel.L); var qrCode = new BitmapByteQRCode(qrCodeData); var qrCodeBitmap = qrCode.GetGraphic(4); var output = new TOTPB2CResponse(string.Empty, HttpStatusCode.OK) { qrCodeBitmap = Convert.ToBase64String(qrCodeBitmap), secretKey = EncryptAndBase64(Convert.ToBase64String(secretKey)) }; return(Ok(output)); } catch (Exception ex) { return(StatusCode((int)HttpStatusCode.Conflict, new TOTPB2CResponse($"General error (REST API): {ex.Message} - {ex.StackTrace}", HttpStatusCode.Conflict))); } }