/// <summary> /// Uses the properties of the RespondToSmsMfaRequest object to respond to the current MFA /// authentication challenge using an asynchronous call /// </summary> /// <param name="smsMfaRequest">RespondToSmsMfaRequest object containing the necessary parameters to /// respond to the current SMS MFA authentication challenge</param> /// <returns>Returns the AuthFlowResponse object that can be used to respond to the next challenge, /// if one exists</returns> public async Task <AuthFlowResponse> RespondToSmsMfaAuthAsync(RespondToSmsMfaRequest smsMfaRequest) { RespondToAuthChallengeRequest challengeRequest = new RespondToAuthChallengeRequest { ChallengeResponses = new Dictionary <string, string> { { CognitoConstants.ChlgParamSmsMfaCode, smsMfaRequest.MfaCode }, { CognitoConstants.ChlgParamUsername, Username } }, Session = smsMfaRequest.SessionID, ClientId = ClientID, ChallengeName = ChallengeNameType.SMS_MFA }; if (!string.IsNullOrEmpty(SecretHash)) { challengeRequest.ChallengeResponses.Add(CognitoConstants.ChlgParamSecretHash, SecretHash); } RespondToAuthChallengeResponse challengeResponse = await Provider.RespondToAuthChallengeAsync(challengeRequest).ConfigureAwait(false); UpdateSessionIfAuthenticationComplete(challengeResponse.ChallengeName, challengeResponse.AuthenticationResult); return(new AuthFlowResponse(challengeResponse.Session, challengeResponse.AuthenticationResult, challengeResponse.ChallengeName, challengeResponse.ChallengeParameters, new Dictionary <string, string>(challengeResponse.ResponseMetadata.Metadata))); }
/// <summary> /// Uses the properties of the RespondToNewPasswordRequiredRequest object to respond to the current new /// password required authentication challenge using an asynchronous call /// </summary> /// <param name="newPasswordRequest">RespondToNewPasswordRequiredRequest object containing the necessary /// parameters to respond to the current SMS MFA authentication challenge</param> /// <returns>Returns the AuthFlowResponse object that can be used to respond to the next challenge, /// if one exists</returns> public async Task <AuthFlowResponse> RespondToNewPasswordRequiredAsync(RespondToNewPasswordRequiredRequest newPasswordRequest) { RespondToAuthChallengeRequest challengeRequest = new RespondToAuthChallengeRequest { ChallengeResponses = new Dictionary <string, string> { { CognitoConstants.ChlgParamNewPassword, newPasswordRequest.NewPassword }, { CognitoConstants.ChlgParamUsername, Username } }, Session = newPasswordRequest.SessionID, ClientId = ClientID, ChallengeName = ChallengeNameType.NEW_PASSWORD_REQUIRED }; if (!string.IsNullOrEmpty(SecretHash)) { challengeRequest.ChallengeResponses.Add(CognitoConstants.ChlgParamSecretHash, SecretHash); } RespondToAuthChallengeResponse challengeResponse = await Provider.RespondToAuthChallengeAsync(challengeRequest).ConfigureAwait(false); UpdateSessionIfAuthenticationComplete(challengeResponse.ChallengeName, challengeResponse.AuthenticationResult); return(new AuthFlowResponse(challengeResponse.Session, challengeResponse.AuthenticationResult, challengeResponse.ChallengeName, challengeResponse.ChallengeParameters, new Dictionary <string, string>(challengeResponse.ResponseMetadata.Metadata))); }
/// <summary> /// Uses the properties of the RespondToCustomChallengeRequest object to respond to the current /// custom authentication challenge using an asynchronous call /// </summary> /// <param name="customRequest">RespondToCustomChallengeRequest object containing the necessary parameters to /// respond to the current custom authentication challenge</param> /// <returns>Returns the AuthFlowResponse object that can be used to respond to the next challenge, /// if one exists</returns> public void RespondToCustomAuthAsync(RespondToCustomChallengeRequest customRequest, AsyncCallback <AuthFlowResponse> callback = null) { RespondToAuthChallengeRequest request = new RespondToAuthChallengeRequest() { ChallengeName = ChallengeNameType.CUSTOM_CHALLENGE, ClientId = ClientID, ChallengeResponses = new Dictionary <string, string>(customRequest.ChallengeParameters), Session = customRequest.SessionID }; Provider.RespondToAuthChallengeAsync(request, r => { if (r.Exception != null) { callback?.Invoke(new AsyncResult <AuthFlowResponse>(null, r.Exception)); return; } RespondToAuthChallengeResponse authResponse = r.Response; UpdateSessionIfAuthenticationComplete(authResponse.ChallengeName, authResponse.AuthenticationResult); callback?.Invoke(new AsyncResult <AuthFlowResponse>(new AuthFlowResponse() { SessionID = authResponse.Session, ChallengeName = authResponse.ChallengeName, AuthenticationResult = authResponse.AuthenticationResult, ChallengeParameters = authResponse.ChallengeParameters, ClientMetadata = new Dictionary <string, string>(authResponse.ResponseMetadata.Metadata) }, null)); }); }
/// <summary> /// Initiates the asynchronous SRP authentication flow /// </summary> /// <param name="srpRequest">InitiateSrpAuthRequest object containing the necessary parameters to /// create an InitiateAuthAsync API call for SRP authentication</param> /// <returns>Returns the AuthFlowResponse object that can be used to respond to the next challenge, /// if one exists</returns> public async Task <AuthFlowResponse> StartWithSrpAuthAsync(InitiateSrpAuthRequest srpRequest) { if (srpRequest == null || string.IsNullOrEmpty(srpRequest.Password)) { throw new ArgumentNullException("Password required for authentication.", "srpRequest"); } Tuple <BigInteger, BigInteger> tupleAa = AuthenticationHelper.CreateAaTuple(); InitiateAuthRequest initiateRequest = CreateSrpAuthRequest(tupleAa); InitiateAuthResponse initiateResponse = await Provider.InitiateAuthAsync(initiateRequest).ConfigureAwait(false); UpdateUsernameAndSecretHash(initiateResponse.ChallengeParameters); RespondToAuthChallengeRequest challengeRequest = CreateSrpPasswordVerifierAuthRequest(initiateResponse, srpRequest.Password, tupleAa); RespondToAuthChallengeResponse verifierResponse = await Provider.RespondToAuthChallengeAsync(challengeRequest).ConfigureAwait(false); UpdateSessionIfAuthenticationComplete(verifierResponse.ChallengeName, verifierResponse.AuthenticationResult); return(new AuthFlowResponse() { SessionID = verifierResponse.Session, ChallengeName = verifierResponse.ChallengeName, AuthenticationResult = verifierResponse.AuthenticationResult, ChallengeParameters = verifierResponse.ChallengeParameters, ClientMetadata = new Dictionary <string, string>(verifierResponse.ResponseMetadata.Metadata) }); }
/// <summary> /// Initiates the asynchronous SRP authentication flow /// </summary> /// <param name="srpRequest">InitiateSrpAuthRequest object containing the necessary parameters to /// create an InitiateAuthAsync API call for SRP authentication</param> /// <returns>Returns the AuthFlowResponse object that can be used to respond to the next challenge, /// if one exists</returns> public void StartWithSrpAuthAsync(InitiateSrpAuthRequest srpRequest, AsyncCallback <AuthFlowResponse> callback = null) { if (srpRequest == null || string.IsNullOrEmpty(srpRequest.Password)) { throw new ArgumentNullException("Password required for authentication.", "srpRequest"); } Tuple <BigInteger, BigInteger> tupleAa = AuthenticationHelper.CreateAaTuple(); InitiateAuthRequest initiateRequest = CreateSrpAuthRequest(tupleAa); Provider.InitiateAuthAsync(initiateRequest, initResult => { if (initResult.Exception != null) { callback?.Invoke(new AsyncResult <AuthFlowResponse>(null, initResult.Exception)); return; } UpdateUsernameAndSecretHash(initResult.Response.ChallengeParameters); RespondToAuthChallengeRequest challengeRequest = CreateSrpPasswordVerifierAuthRequest(initResult.Response, srpRequest.Password, tupleAa); bool challengeResponsesValid = challengeRequest != null && challengeRequest.ChallengeResponses != null; bool deviceKeyValid = Device != null && !string.IsNullOrEmpty(Device.DeviceKey); if (challengeResponsesValid && deviceKeyValid) { challengeRequest.ChallengeResponses.Add(CognitoConstants.ChlgParamDeviceKey, Device.DeviceKey); } Provider.RespondToAuthChallengeAsync(challengeRequest, respondResult => { if (respondResult.Exception != null) { callback?.Invoke(new AsyncResult <AuthFlowResponse>(null, respondResult.Exception)); return; } RespondToAuthChallengeResponse verifierResponse = respondResult.Response; UpdateSessionIfAuthenticationComplete(verifierResponse.ChallengeName, verifierResponse.AuthenticationResult); callback?.Invoke(new AsyncResult <AuthFlowResponse>(new AuthFlowResponse() { SessionID = verifierResponse.Session, ChallengeName = verifierResponse.ChallengeName, AuthenticationResult = verifierResponse.AuthenticationResult, ChallengeParameters = verifierResponse.ChallengeParameters, ClientMetadata = new Dictionary <string, string>(verifierResponse.ResponseMetadata.Metadata) }, null)); }); }); }
public async Task <AuthFlowResponse> RespondToSoftwareMfaAuthAsync(RespondToSoftwareMfaRequest softwareMfaRequest) { RespondToAuthChallengeRequest challengeRequest = new RespondToAuthChallengeRequest { ChallengeResponses = new Dictionary <string, string> { { CognitoConstants.ChlgParamSoftwareMfaCode, softwareMfaRequest.MfaCode }, { CognitoConstants.ChlgParamUsername, Username }, }, Session = softwareMfaRequest.SessionID, ClientId = ClientID, ChallengeName = "SOFTWARE_TOKEN_MFA" }; if (Device != null && !string.IsNullOrEmpty(Device.DeviceKey)) { challengeRequest.ChallengeResponses.Add(CognitoConstants.ChlgParamDeviceKey, Device.DeviceKey); } if (!string.IsNullOrEmpty(SecretHash)) { challengeRequest.ChallengeResponses.Add(CognitoConstants.ChlgParamSecretHash, SecretHash); } RespondToAuthChallengeResponse challengeResponse = await Provider.RespondToAuthChallengeAsync(challengeRequest).ConfigureAwait(false); if (challengeResponse.ChallengeName == ChallengeNameType.DEVICE_SRP_AUTH) { challengeResponse = await HandleDeviceSrpAuthResponseAsync(challengeResponse).ConfigureAwait(false); } UpdateSessionIfAuthenticationComplete(challengeResponse.ChallengeName, challengeResponse.AuthenticationResult); return(new AuthFlowResponse { SessionID = challengeResponse.Session, ChallengeName = challengeResponse.ChallengeName, AuthenticationResult = challengeResponse.AuthenticationResult, ChallengeParameters = challengeResponse.ChallengeParameters, ClientMetadata = new Dictionary <string, string>(challengeResponse.ResponseMetadata.Metadata) }); }
/// <summary> /// Uses the properties of the RespondToCustomChallengeRequest object to respond to the current /// custom authentication challenge using an asynchronous call /// </summary> /// <param name="customRequest">RespondToCustomChallengeRequest object containing the necessary parameters to /// respond to the current custom authentication challenge</param> /// <returns>Returns the AuthFlowResponse object that can be used to respond to the next challenge, /// if one exists</returns> public async Task <AuthFlowResponse> RespondToCustomAuthAsync(RespondToCustomChallengeRequest customRequest) { RespondToAuthChallengeRequest request = new RespondToAuthChallengeRequest() { ChallengeName = ChallengeNameType.CUSTOM_CHALLENGE, ClientId = ClientID, ChallengeResponses = new Dictionary <string, string>(customRequest.ChallengeParameters), Session = customRequest.SessionID }; RespondToAuthChallengeResponse authResponse = await Provider.RespondToAuthChallengeAsync(request).ConfigureAwait(false); UpdateSessionIfAuthenticationComplete(authResponse.ChallengeName, authResponse.AuthenticationResult); return(new AuthFlowResponse(authResponse.Session, authResponse.AuthenticationResult, authResponse.ChallengeName, authResponse.ChallengeParameters, new Dictionary <string, string>(authResponse.ResponseMetadata.Metadata))); }
/// <summary> /// Uses the properties of the RespondToNewPasswordRequiredRequest object to respond to the current new /// password required authentication challenge using an asynchronous call /// </summary> /// <param name="newPasswordRequest">RespondToNewPasswordRequiredRequest object containing the necessary /// parameters to respond to the current SMS MFA authentication challenge</param> /// <returns>Returns the AuthFlowResponse object that can be used to respond to the next challenge, /// if one exists</returns> public void RespondToNewPasswordRequiredAsync(RespondToNewPasswordRequiredRequest newPasswordRequest, AsyncCallback <AuthFlowResponse> callback = null) { RespondToAuthChallengeRequest challengeRequest = new RespondToAuthChallengeRequest { ChallengeResponses = new Dictionary <string, string> { { CognitoConstants.ChlgParamNewPassword, newPasswordRequest.NewPassword }, { CognitoConstants.ChlgParamUsername, Username } }, Session = newPasswordRequest.SessionID, ClientId = ClientID, ChallengeName = ChallengeNameType.NEW_PASSWORD_REQUIRED }; if (!string.IsNullOrEmpty(SecretHash)) { challengeRequest.ChallengeResponses.Add(CognitoConstants.ChlgParamSecretHash, SecretHash); } Provider.RespondToAuthChallengeAsync(challengeRequest, r => { if (r.Exception != null) { callback?.Invoke(new AsyncResult <AuthFlowResponse>(null, r.Exception)); return; } RespondToAuthChallengeResponse challengeResponse = r.Response; UpdateSessionIfAuthenticationComplete(challengeResponse.ChallengeName, challengeResponse.AuthenticationResult); callback?.Invoke(new AsyncResult <AuthFlowResponse>(new AuthFlowResponse() { SessionID = challengeResponse.Session, ChallengeName = challengeResponse.ChallengeName, AuthenticationResult = challengeResponse.AuthenticationResult, ChallengeParameters = challengeResponse.ChallengeParameters, ClientMetadata = new Dictionary <string, string>(challengeResponse.ResponseMetadata.Metadata) }, null)); }); }
/// <summary> /// Respond to auth challange with name DEVICE_SRP_AUTH. /// </summary> /// <param name="currentResponse">Current auth response from AWS</param> /// <param name="AaTuple">Use for generate to current auth challange. If null - create new one.</param> /// <returns></returns> private async Task <RespondToAuthChallengeResponse> HandleDeviceSrpAuthResponseAsync( RespondToAuthChallengeResponse currentResponse, Tuple <BigInteger, BigInteger> AaTuple = null) { if (currentResponse == null) { throw new ArgumentNullException(nameof(currentResponse)); } if (AaTuple == null) { AaTuple = AuthenticationHelper.CreateAaTuple(); } var challengeRequest = new RespondToAuthChallengeRequest { ClientId = ClientID, Session = currentResponse.Session, ChallengeName = ChallengeNameType.DEVICE_SRP_AUTH, ChallengeResponses = new Dictionary <string, string> { { CognitoConstants.ChlgParamUsername, Username }, { CognitoConstants.ChlgParamSrpA, AaTuple.Item1.ToString("X") }, { CognitoConstants.ChlgParamDeviceKey, Device.DeviceKey }, { CognitoConstants.ChlgParamSecretHash, SecretHash } } }; currentResponse = await Provider.RespondToAuthChallengeAsync(challengeRequest).ConfigureAwait(false); if (currentResponse.ChallengeName == ChallengeNameType.DEVICE_PASSWORD_VERIFIER) { challengeRequest = CreateDeviceSrpAuthRequest(currentResponse, AaTuple); } else { throw new Exception($"Unsupported challenge {currentResponse.ChallengeName}"); } return(await Provider.RespondToAuthChallengeAsync(challengeRequest).ConfigureAwait(false)); }
/// <summary> /// Internal method which responds to the DEVICE_SRP_AUTH challenge in SRP authentication /// </summary> /// <param name="challenge">The response from the PASSWORD_VERIFIER challenge</param> /// <param name="tupleAa">Tuple of BigIntegers containing the A,a pair for the SRP protocol flow</param> /// <returns></returns> private RespondToAuthChallengeRequest CreateDeviceSrpAuthRequest(RespondToAuthChallengeResponse challenge, Tuple <BigInteger, BigInteger> tupleAa) { RespondToAuthChallengeRequest authChallengeRequest = new RespondToAuthChallengeRequest() { ChallengeName = "DEVICE_SRP_AUTH", ClientId = ClientID, Session = challenge.Session, ChallengeResponses = new Dictionary <string, string> { { CognitoConstants.ChlgParamUsername, Username }, { CognitoConstants.ChlgParamDeviceKey, Device.DeviceKey }, { CognitoConstants.ChlgParamSrpA, tupleAa.Item1.ToString("X") }, } }; if (!string.IsNullOrEmpty(ClientSecret)) { SecretHash = CognitoAuthHelper.GetUserPoolSecretHash(Username, ClientID, ClientSecret); authChallengeRequest.ChallengeResponses.Add(CognitoConstants.ChlgParamSecretHash, SecretHash); } return(authChallengeRequest); }
/// <summary> /// Unmarshaller the response from the service to the response class. /// </summary> /// <param name="context"></param> /// <returns></returns> public override AmazonWebServiceResponse Unmarshall(JsonUnmarshallerContext context) { RespondToAuthChallengeResponse response = new RespondToAuthChallengeResponse(); context.Read(); int targetDepth = context.CurrentDepth; while (context.ReadAtDepth(targetDepth)) { if (context.TestExpression("AuthenticationResult", targetDepth)) { var unmarshaller = AuthenticationResultTypeUnmarshaller.Instance; response.AuthenticationResult = unmarshaller.Unmarshall(context); continue; } if (context.TestExpression("ChallengeName", targetDepth)) { var unmarshaller = StringUnmarshaller.Instance; response.ChallengeName = unmarshaller.Unmarshall(context); continue; } if (context.TestExpression("ChallengeParameters", targetDepth)) { var unmarshaller = new DictionaryUnmarshaller <string, string, StringUnmarshaller, StringUnmarshaller>(StringUnmarshaller.Instance, StringUnmarshaller.Instance); response.ChallengeParameters = unmarshaller.Unmarshall(context); continue; } if (context.TestExpression("Session", targetDepth)) { var unmarshaller = StringUnmarshaller.Instance; response.Session = unmarshaller.Unmarshall(context); continue; } } return(response); }
/// <summary> /// Initiates the asynchronous SRP authentication flow /// </summary> /// <param name="srpRequest">InitiateSrpAuthRequest object containing the necessary parameters to /// create an InitiateAuthAsync API call for SRP authentication</param> /// <returns>Returns the AuthFlowResponse object that can be used to respond to the next challenge, /// if one exists</returns> public async Task <AuthFlowResponse> StartWithSrpAuthAsync(InitiateSrpAuthRequest srpRequest) { if (srpRequest == null || string.IsNullOrEmpty(srpRequest.Password)) { throw new ArgumentNullException("Password required for authentication.", "srpRequest"); } Tuple <BigInteger, BigInteger> tupleAa = AuthenticationHelper.CreateAaTuple(); InitiateAuthRequest initiateRequest = CreateSrpAuthRequest(tupleAa); InitiateAuthResponse initiateResponse = await Provider.InitiateAuthAsync(initiateRequest).ConfigureAwait(false); UpdateUsernameAndSecretHash(initiateResponse.ChallengeParameters); RespondToAuthChallengeRequest challengeRequest = CreateSrpPasswordVerifierAuthRequest(initiateResponse, srpRequest.Password, tupleAa); bool challengeResponsesValid = challengeRequest != null && challengeRequest.ChallengeResponses != null; bool deviceKeyValid = Device != null && !string.IsNullOrEmpty(Device.DeviceKey); if (challengeResponsesValid && deviceKeyValid) { challengeRequest.ChallengeResponses.Add(CognitoConstants.ChlgParamDeviceKey, Device.DeviceKey); } RespondToAuthChallengeResponse verifierResponse = await Provider.RespondToAuthChallengeAsync(challengeRequest).ConfigureAwait(false); UpdateSessionIfAuthenticationComplete(verifierResponse.ChallengeName, verifierResponse.AuthenticationResult); return(new AuthFlowResponse(verifierResponse.Session, verifierResponse.AuthenticationResult, verifierResponse.ChallengeName, verifierResponse.ChallengeParameters, new Dictionary <string, string>(verifierResponse.ResponseMetadata.Metadata))); }
/// <summary> /// Internal method which responds to the DEVICE_PASSWORD_VERIFIER challenge in SRP authentication /// </summary> /// <param name="challenge">Response from the InitiateAuth challenge</param> /// <param name="deviceKeyGroup">Group Key for the CognitoDevice, needed for authentication</param> /// <param name="devicePassword">Password for the CognitoDevice, needed for authentication</param> /// <param name="tupleAa">Tuple of BigIntegers containing the A,a pair for the SRP protocol flow</param> /// <returns>Returns the RespondToAuthChallengeRequest for an SRP authentication flow</returns> private RespondToAuthChallengeRequest CreateDevicePasswordVerifierAuthRequest(RespondToAuthChallengeResponse challenge, string deviceKeyGroup, string devicePassword, Tuple <BigInteger, BigInteger> tupleAa) { string deviceKey = challenge.ChallengeParameters[CognitoConstants.ChlgParamDeviceKey]; string username = challenge.ChallengeParameters[CognitoConstants.ChlgParamUsername]; string secretBlock = challenge.ChallengeParameters[CognitoConstants.ChlgParamSecretBlock]; string salt = challenge.ChallengeParameters[CognitoConstants.ChlgParamSalt]; BigInteger srpb = BigIntegerExtensions.FromUnsignedLittleEndianHex(challenge.ChallengeParameters[CognitoConstants.ChlgParamSrpB]); if ((srpb.TrueMod(AuthenticationHelper.N)).Equals(BigInteger.Zero)) { throw new ArgumentException("SRP error, B mod N cannot be zero.", "challenge"); } string timeStr = DateTime.UtcNow.ToString("ddd MMM d HH:mm:ss \"UTC\" yyyy", CultureInfo.InvariantCulture); var claimBytes = AuthenticationHelper.AuthenticateDevice(username, deviceKey, devicePassword, deviceKeyGroup, salt, challenge.ChallengeParameters[CognitoConstants.ChlgParamSrpB], secretBlock, timeStr, tupleAa); string claimB64 = Convert.ToBase64String(claimBytes); Dictionary <string, string> srpAuthResponses = new Dictionary <string, string>(StringComparer.Ordinal) { { CognitoConstants.ChlgParamPassSecretBlock, secretBlock }, { CognitoConstants.ChlgParamPassSignature, claimB64 }, { CognitoConstants.ChlgParamUsername, username }, { CognitoConstants.ChlgParamTimestamp, timeStr }, { CognitoConstants.ChlgParamDeviceKey, Device.DeviceKey } }; if (!string.IsNullOrEmpty(ClientSecret)) { SecretHash = CognitoAuthHelper.GetUserPoolSecretHash(Username, ClientID, ClientSecret); srpAuthResponses.Add(CognitoConstants.ChlgParamSecretHash, SecretHash); } RespondToAuthChallengeRequest authChallengeRequest = new RespondToAuthChallengeRequest() { ChallengeName = challenge.ChallengeName, ClientId = ClientID, Session = challenge.Session, ChallengeResponses = srpAuthResponses }; return(authChallengeRequest); }
/// <summary> /// Create request for DEVICE_SRP_AUTH. /// </summary> /// <param name="challenge">Current auth challange response</param> /// <param name="AaTuple">Use for generate request</param> /// <returns>DEVICE_SRP_AUTH request</returns> private RespondToAuthChallengeRequest CreateDeviceSrpAuthRequest(RespondToAuthChallengeResponse challenge, Tuple <BigInteger, BigInteger> AaTuple) { var usernameInternal = challenge.ChallengeParameters[CognitoConstants.ChlgParamUsername]; BigInteger srpB; if (challenge.ChallengeParameters.TryGetValue(CognitoConstants.ChlgParamSrpB, out var srpBBytes)) { srpB = BigIntegerExtensions.FromHexPositive(srpBBytes); } else { throw new Exception($"Missing {CognitoConstants.ChlgParamSrpB}"); } if (srpB.TrueMod(AuthenticationHelper.N).IsZero) { throw new Exception("SRP error, B cannot be zero"); } var salt = BigIntegerExtensions.FromHexPositive(challenge.ChallengeParameters[CognitoConstants.ChlgParamSalt]); var key = AuthenticationHelper.GetPasswordAuthenticationKey(Device.DeviceKey, Device.DeviceSecret, Device.GroupDeviceKey, AaTuple, srpB, salt); string hmac; var dateString = CognitoAuthHelper.UtcNow; { var hmacSha256 = new HMACSHA256(key); var bytes = CognitoAuthHelper.CombineBytes(new[] { Encoding.UTF8.GetBytes(Device.GroupDeviceKey), Encoding.UTF8.GetBytes(Device.DeviceKey), Convert.FromBase64String(challenge.ChallengeParameters[CognitoConstants.ChlgParamSecretBlock]), Encoding.UTF8.GetBytes(dateString) }); hmac = Convert.ToBase64String(hmacSha256.ComputeHash(bytes)); } string secretHash; { var hmacSha256 = new HMACSHA256(Encoding.UTF8.GetBytes(ClientSecret)); var hash = hmacSha256.ComputeHash(CognitoAuthHelper.CombineBytes(new[] { Encoding.UTF8.GetBytes(usernameInternal), Encoding.UTF8.GetBytes(ClientID), })); secretHash = Convert.ToBase64String(hash); } var challengeResponses = new Dictionary <string, string> { { CognitoConstants.ChlgParamPassSecretBlock, challenge.ChallengeParameters[CognitoConstants.ChlgParamSecretBlock] }, { CognitoConstants.ChlgParamPassSignature, hmac }, { CognitoConstants.ChlgParamTimestamp, dateString }, { CognitoConstants.ChlgParamUsername, usernameInternal }, { CognitoConstants.ChlgParamDeviceKey, Device.DeviceKey }, { CognitoConstants.ChlgParamSecretHash, secretHash } }; return(new RespondToAuthChallengeRequest { ChallengeName = challenge.ChallengeName, ClientId = ClientID, Session = challenge.Session, ChallengeResponses = challengeResponses }); }