/// <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))); }
/// <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 }); }