/// <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)));
        }
Example #3
0
        /// <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));
            });
        }
Example #4
0
        /// <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)
            });
        }
Example #5
0
        /// <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));
                });
            });
        }
Example #6
0
        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)));
        }
Example #8
0
        /// <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));
            });
        }
Example #9
0
        /// <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));
        }
Example #10
0
        /// <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)));
        }
Example #13
0
        /// <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);
        }
Example #14
0
        /// <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
            });
        }