/// <summary> /// Interal method which creates the InitiateAuthRequest for an SRP authentication flow /// </summary> /// <param name="tupleAa">Tuple containing the A,a pair for SRP authentication</param> /// <returns>Returns the InitiateAuthRequest for an SRP authentication flow</returns> private InitiateAuthRequest CreateSrpAuthRequest(Tuple <BigInteger, BigInteger> tupleAa) { InitiateAuthRequest initiateAuthRequest = new InitiateAuthRequest() { AuthFlow = AuthFlowType.USER_SRP_AUTH, ClientId = ClientID, AuthParameters = new Dictionary <string, string>(StringComparer.Ordinal) { { CognitoConstants.ChlgParamUsername, Username }, { CognitoConstants.ChlgParamSrpA, tupleAa.Item1.ToString("X") } } }; if (!string.IsNullOrEmpty(ClientSecret)) { initiateAuthRequest.AuthParameters.Add(CognitoConstants.ChlgParamSecretHash, CognitoAuthHelper.GetUserPoolSecretHash(Username, ClientID, ClientSecret)); } if (Device != null && !string.IsNullOrEmpty(Device.DeviceKey)) { initiateAuthRequest.AuthParameters.Add(CognitoConstants.ChlgParamDeviceKey, Device.DeviceKey); } return(initiateAuthRequest); }
public void TestHkdfVector2() { // Expected Values byte[] prkFromSpec = CognitoAuthHelper.StringToByteArray("06a6b88c5853361a06104c9ceb35b45cef760014904671" + "014a193f40c15fc244"); byte[] okmFromSpec = CognitoAuthHelper.StringToByteArray("b11e398dc80327a1c8e7f78c596a49344f012eda2d4efa" + "d8a050cc4c19afa97c59045a99cac7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71c" + "c30c58179ec3e87c14c01d5c1f3434f1d87"); byte[] ikmBytes = CognitoAuthHelper.StringToByteArray("000102030405060708090a0b0c0d0e0f101112131" + "415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d" + "3e3f404142434445464748494a4b4c4d4e4f"); byte[] saltBytes = CognitoAuthHelper.StringToByteArray("606162636465666768696a6b6c6d6e6f70717273" + "7475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9" + "d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf"); byte[] infoBytes = CognitoAuthHelper.StringToByteArray("b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3" + "c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebece" + "deeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"); int length = 82; HkdfSha256 hkdfSha256 = new HkdfSha256(saltBytes, ikmBytes); byte[] hkdfResult = hkdfSha256.Expand(infoBytes, length); Assert.Equal(prkFromSpec, hkdfSha256.Prk); Assert.Equal(okmFromSpec, hkdfResult); }
/// <summary> /// Internal method to aid in the admin sign up flow for a new user /// </summary> /// <param name="userID">The userID of the user being created</param> /// <param name="userAttributes">The user attributes of the user being created</param> /// <param name="validationData">The validation data of the user being created</param> /// <returns>Returns the SignUpResponse for the sign up API request using the provided information</returns> private AdminCreateUserRequest CreateAdminSignUpRequest(string userID, IDictionary <string, string> userAttributes, IDictionary <string, string> validationData) { List <AttributeType> userAttributesList = null; if (userAttributes != null) { userAttributesList = CognitoAuthHelper.CreateAttributeList(userAttributes); } else { throw new ArgumentNullException(nameof(userAttributes), "userAttributes cannot be null."); } var validationDataList = validationData != null?CognitoAuthHelper.CreateAttributeList(validationData) : null; // Create User registration request return(new AdminCreateUserRequest() { Username = userID, UserPoolId = this.PoolID, UserAttributes = userAttributesList, ValidationData = validationDataList }); }
/// <summary> /// Performs the "Expand" portion of the Hkdf protocol to make /// the ouput key material of the desired length /// </summary> /// <param name="info">Contextual information for the expansion hash</param> /// <param name="length">The desired length of the output key material in bytes</param> /// <returns>Returns the output key material for the expansion protion of the HKDF protocol</returns> internal byte[] Expand(byte[] info, int length) { if (length > HLen * 255) { throw new ArgumentException("Length must be <= " + HLen * 255); } byte[] outputKeyMaterial = new byte[length]; HmacSha256 = new HMACSHA256(Prk); byte currentByte = 1; byte[] hashedBlock = new byte[0]; byte[] currentBlock; int bytesRemaining = length; while (bytesRemaining > 0) { currentBlock = CognitoAuthHelper.CombineBytes(hashedBlock, info, new byte[] { currentByte }); hashedBlock = HmacSha256.ComputeHash(currentBlock); Buffer.BlockCopy(hashedBlock, 0, outputKeyMaterial, length - bytesRemaining, Math.Min(hashedBlock.Length, bytesRemaining)); bytesRemaining -= hashedBlock.Length; currentByte++; } return(outputKeyMaterial); }
private UpdateUserAttributesRequest CreateUpdateUserAttributesRequest(IDictionary <string, string> attributes) { EnsureUserAuthenticated(); UpdateUserAttributesRequest updateUserAttributesRequest = new UpdateUserAttributesRequest() { AccessToken = SessionTokens.AccessToken, UserAttributes = CognitoAuthHelper.CreateAttributeList(attributes) }; return(updateUserAttributesRequest); }
/// <summary> /// Creates an instance of CognitoUser /// </summary> /// <param name="userID">UserID of the specified user</param> /// <param name="clientID">ClientID associated with the user pool</param> /// <param name="pool">CognitoUserPool this user is associated with </param> /// <param name="provider">IAmazonCognitoIdentityProvider for the specified user pool</param> /// <param name="clientSecret">Client secret for the specified client, if exists</param> /// <param name="username">Username for user, if different from userID</param> public CognitoUser(string userID, string clientID, CognitoUserPool pool, IAmazonCognitoIdentityProvider provider, string clientSecret = null, string status = null, string username = null, Dictionary <string, string> attributes = null) { if (pool.PoolID.Contains("_")) { this.PoolName = pool.PoolID.Split('_')[1]; } else { throw new ArgumentException("Pool's poolID malformed, should be of the form <region>_<poolname>."); } this.ClientSecret = clientSecret; if (!string.IsNullOrEmpty(clientSecret)) { this.SecretHash = CognitoAuthHelper.GetUserPoolSecretHash(userID, clientID, clientSecret); } this.UserID = userID; this.Username = userID; if (!string.IsNullOrEmpty(username)) { this.Username = username; } else { this.Username = userID; } this.Status = status; this.UserPool = pool; this.ClientID = clientID; this.SessionTokens = null; if (attributes != null) { this.Attributes = attributes; } this.Provider = provider; if (this.Provider is AmazonCognitoIdentityProviderClient eventProvider) { eventProvider.BeforeRequestEvent += CognitoAuthHelper.ServiceClientBeforeRequestEvent; } }
/// <summary> /// Internal method which responds to the PASSWORD_VERIFIER challenge in SRP authentication /// </summary> /// <param name="challenge">Response from the InitiateAuth challenge</param> /// <param name="password">Password for the CognitoUser, 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 CreateSrpPasswordVerifierAuthRequest(InitiateAuthResponse challenge, string password, Tuple <BigInteger, BigInteger> tupleAa) { string username = challenge.ChallengeParameters[CognitoConstants.ChlgParamUsername]; string poolName = PoolName; 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"); } DateTime timestamp = DateTime.UtcNow; string timeStr = timestamp.ToString("ddd MMM d HH:mm:ss \"UTC\" yyyy", CultureInfo.InvariantCulture); byte[] claim = AuthenticationHelper.AuthenticateUser(username, password, poolName, tupleAa, salt, challenge.ChallengeParameters[CognitoConstants.ChlgParamSrpB], secretBlock, timeStr); string claimBase64 = Convert.ToBase64String(claim); Dictionary <string, string> srpAuthResponses = new Dictionary <string, string>(StringComparer.Ordinal) { { CognitoConstants.ChlgParamPassSecretBlock, secretBlock }, { CognitoConstants.ChlgParamPassSignature, claimBase64 }, { CognitoConstants.ChlgParamUsername, username }, { CognitoConstants.ChlgParamTimestamp, timeStr }, }; if (!string.IsNullOrEmpty(ClientSecret)) { SecretHash = CognitoAuthHelper.GetUserPoolSecretHash(Username, ClientID, ClientSecret); srpAuthResponses.Add(CognitoConstants.ChlgParamSecretHash, SecretHash); } if (Device != null && !string.IsNullOrEmpty(Device.DeviceKey)) { srpAuthResponses.Add(CognitoConstants.ChlgParamDeviceKey, Device.DeviceKey); } RespondToAuthChallengeRequest authChallengeRequest = new RespondToAuthChallengeRequest() { ChallengeName = challenge.ChallengeName, ClientId = ClientID, Session = challenge.Session, ChallengeResponses = srpAuthResponses }; return(authChallengeRequest); }
/// <summary> /// Resets the <paramref name="user"/>'s password to the specified <paramref name="newPassword"/> after /// validating the given password reset <paramref name="token"/>. /// </summary> /// <param name="user">The user whose password should be reset.</param> /// <param name="token">The password reset token to verify.</param> /// <param name="newPassword">The new password to set if reset token verification succeeds.</param> /// <returns> /// The <see cref="Task"/> that represents the asynchronous operation, containing the <see cref="IdentityResult"/> /// of the operation. /// </returns> public Task ConfirmForgotPassword(string userID, string token, string newPassword, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var request = new ConfirmForgotPasswordRequest { Username = userID, ClientId = ClientID, ConfirmationCode = token, Password = newPassword, }; if (!string.IsNullOrEmpty(ClientSecret)) { request.SecretHash = CognitoAuthHelper.GetUserPoolSecretHash(userID, ClientID, ClientSecret); } return(Provider.ConfirmForgotPasswordAsync(request, cancellationToken)); }
public void TestHkdfVector3() { // Expected Values var prkFromSpec = CognitoAuthHelper.StringToByteArray("19ef24a32c717b167f33a91d6f648bdf96596776afdb6" + "377ac434c1c293ccb04"); var okmFromSpec = CognitoAuthHelper.StringToByteArray("8da4e775a563c18f715f802a063c5a31b8a11f5c5ee18" + "79ec3454e5f3c738d2d9d201395faa4b61a96c8"); var ikmBytes = CognitoAuthHelper.StringToByteArray("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"); var saltBytes = CognitoAuthHelper.StringToByteArray(""); var infoBytes = CognitoAuthHelper.StringToByteArray(""); var length = 42; var hkdfSha256 = new HkdfSha256(saltBytes, ikmBytes); var hkdfResult = hkdfSha256.Expand(infoBytes, length); Assert.Equal(prkFromSpec, hkdfSha256.Prk); Assert.Equal(okmFromSpec, hkdfResult); }
public void TestHkdfVector1() { // Expected Values var prkFromSepc = CognitoAuthHelper.StringToByteArray("077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3" + "122ec844ad7c2b3e5"); var okmFromSpec = CognitoAuthHelper.StringToByteArray("3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4" + "c5db02d56ecc4c5bf34007208d5b887185865"); var ikmBytes = CognitoAuthHelper.StringToByteArray("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"); var saltBytes = CognitoAuthHelper.StringToByteArray("000102030405060708090a0b0c"); var infoBytes = CognitoAuthHelper.StringToByteArray("f0f1f2f3f4f5f6f7f8f9"); var length = 42; var hkdfSha256 = new HkdfSha256(saltBytes, ikmBytes); var hkdfResult = hkdfSha256.Expand(infoBytes, length); Assert.Equal(prkFromSepc, hkdfSha256.Prk); Assert.Equal(okmFromSpec, hkdfResult); }
/// <summary> /// Internal mehtod which updates CognitoUser's username, secret hash, and device key from challege parameters /// </summary> /// <param name="challengeParameters">Dictionary containing the key-value pairs for challenge parameters</param> private void UpdateUsernameAndSecretHash(IDictionary <string, string> challengeParameters) { bool canSetUsername = string.IsNullOrEmpty(Username) || string.Equals(UserID, Username, StringComparison.Ordinal); bool challengeParamIsUsername = challengeParameters != null && challengeParameters.ContainsKey(CognitoConstants.ChlgParamUsername); bool shouldUpdate = canSetUsername || challengeParamIsUsername; if (!shouldUpdate) { return; } if (challengeParameters.ContainsKey(CognitoConstants.ChlgParamUsername)) { Username = challengeParameters[CognitoConstants.ChlgParamUsername]; } if (!string.IsNullOrEmpty(ClientSecret)) { SecretHash = CognitoAuthHelper.GetUserPoolSecretHash(Username, ClientID, ClientSecret); } }
/// <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> /// Performs the "Expand" portion of the Hkdf protocol to make /// the ouput key material of the desired length /// </summary> /// <param name="info">Contextual information for the expansion hash</param> /// <param name="length">The desired length of the output key material in bytes</param> /// <returns>Returns the output key material for the expansion protion of the HKDF protocol</returns> internal byte[] Expand(byte[] info, int length) { byte[] outputKeyMaterial = new byte[length]; HmacSha256 = new HMACSHA256(Prk); byte currentByte; byte[] hashedBlock = new byte[0]; byte[] currentBlock; int bytesRemaining = length; for (int i = 0; bytesRemaining > 0; i++) { currentByte = Convert.ToByte(i + 1); currentBlock = CognitoAuthHelper.CombineBytes(new byte[][] { hashedBlock, info, new byte[] { currentByte } }); hashedBlock = HmacSha256.ComputeHash(currentBlock); Buffer.BlockCopy(hashedBlock, 0, outputKeyMaterial, length - bytesRemaining, Math.Min(hashedBlock.Length, bytesRemaining)); bytesRemaining -= hashedBlock.Length; } return(outputKeyMaterial); }
/// <summary> /// Internal method to aid in the sign up flow for a new user /// </summary> /// <param name="userID">The userID of the user being created</param> /// <param name="password">The password of the user being created</param> /// <param name="userAttributes">The user attributes of the user being created</param> /// <param name="validationData">The validation data of the user being created</param> /// <returns>Returns the SignUpResponse for the sign up API request using the provided information</returns> private SignUpRequest CreateSignUpRequest(string userID, string password, IDictionary <string, string> userAttributes, IDictionary <string, string> validationData) { List <AttributeType> userAttributesList = null; if (userAttributes != null) { userAttributesList = CognitoAuthHelper.CreateAttributeList(userAttributes); } else { throw new ArgumentNullException("userAttributes", "userAttributes cannot be null."); } var validationDataList = validationData != null?CognitoAuthHelper.CreateAttributeList(validationData) : null; // Create User registration request var signUpUserRequest = new SignUpRequest() { Username = userID, Password = password, ClientId = ClientID, UserAttributes = userAttributesList, ValidationData = validationDataList }; if (!string.IsNullOrEmpty(ClientSecret)) { signUpUserRequest.SecretHash = CognitoAuthHelper.GetUserPoolSecretHash(userID, ClientID, ClientSecret); } return(signUpUserRequest); }
public void TestSecretHash() { string hash = CognitoAuthHelper.GetUserPoolSecretHash("Mess", "age", "secret"); Assert.Equal("qnR8UCqJggD55PohusaBNviGoOJ67HC6Btry4qXLVZc=", hash); }
/// <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 }); }