/// <summary>
 /// Generates a DeviceSecretVerifierConfigType object for a device associated with a CognitoUser for SRP Authentication
 /// </summary>
 /// <param name="deviceGroupKey">The DeviceKey Group for the associated CognitoDevice</param>
 /// <param name="deviceKey">The DeviceKey for the associated CognitoDevice</param>
 /// <param name="devicePass">The random password for the associated CognitoDevice</param>
 /// <returns></returns>
 public DeviceSecretVerifierConfigType GenerateDeviceVerifier(string deviceGroupKey, string devicePass, string username)
 {
     return(AuthenticationHelper.GenerateDeviceVerifier(deviceGroupKey, devicePass, username));
 }
        /// <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 virtual 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[CognitoConstants.ChlgParamDeviceKey] = Device.DeviceKey;
            }

            RespondToAuthChallengeResponse verifierResponse =
                await Provider.RespondToAuthChallengeAsync(challengeRequest).ConfigureAwait(false);

            var isDeviceAuthRequest = verifierResponse.AuthenticationResult == null && (!string.IsNullOrEmpty(srpRequest.DeviceGroupKey) ||
                                                                                        !string.IsNullOrEmpty(srpRequest.DevicePass));

            #region Device-level authentication
            if (isDeviceAuthRequest)
            {
                if (string.IsNullOrEmpty(srpRequest.DeviceGroupKey) || string.IsNullOrEmpty(srpRequest.DevicePass))
                {
                    throw new ArgumentNullException("Device Group Key and Device Pass required for authentication.", "srpRequest");
                }

                #region Device SRP Auth
                var deviceAuthRequest  = CreateDeviceSrpAuthRequest(verifierResponse, tupleAa);
                var deviceAuthResponse = await Provider.RespondToAuthChallengeAsync(deviceAuthRequest).ConfigureAwait(false);

                #endregion

                #region Device Password Verifier
                var devicePasswordChallengeRequest = CreateDevicePasswordVerifierAuthRequest(deviceAuthResponse, srpRequest.DeviceGroupKey, srpRequest.DevicePass, tupleAa);
                verifierResponse = await Provider.RespondToAuthChallengeAsync(devicePasswordChallengeRequest).ConfigureAwait(false);

                #endregion
            }
            #endregion

            UpdateSessionIfAuthenticationComplete(verifierResponse.ChallengeName, verifierResponse.AuthenticationResult);

            return(new AuthFlowResponse(verifierResponse.Session,
                                        verifierResponse.AuthenticationResult,
                                        verifierResponse.ChallengeName,
                                        verifierResponse.ChallengeParameters,
                                        new Dictionary <string, string>(verifierResponse.ResponseMetadata.Metadata)));
        }
示例#3
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
            });
        }