Beispiel #1
0
        /// <summary>
        /// Generates the claim for authenticating a user through the SRP protocol
        /// </summary>
        /// <param name="username"> Username of CognitoUser</param>
        /// <param name="password"> Password of CognitoUser</param>
        /// <param name="poolName"> PoolName of CognitoUserPool (from poolID: <region>_<poolName>)</param>
        /// <param name="tupleAa"> TupleAa from CreateAaTuple</param>
        /// <param name="saltString"> salt provided in ChallengeParameters from Cognito </param>
        /// <param name="srpbString"> srpb provided in ChallengeParameters from Cognito</param>
        /// <param name="secretBlockBase64">secret block provided in ChallengeParameters from Cognito</param>
        /// <param name="formattedTimestamp">En-US Culture of Current Time</param>
        /// <returns>Returns the claim for authenticating the given user</returns>
        public static byte[] AuthenticateUser(
            string username,
            string password,
            string poolName,
            Tuple <BigInteger, BigInteger> tupleAa,
            string saltString,
            string srpbString,
            string secretBlockBase64,
            string formattedTimestamp)
        {
            var B = BigIntegerExtensions.FromUnsignedLittleEndianHex(srpbString);

            if (B.TrueMod(N).Equals(BigInteger.Zero))
            {
                throw new ArgumentException("B mod N cannot be zero.", nameof(srpbString));
            }

            var secretBlockBytes = Convert.FromBase64String(secretBlockBase64);
            var salt             = BigIntegerExtensions.FromUnsignedLittleEndianHex(saltString);

            // Need to generate the key to hash the response based on our A and what AWS sent back
            var key = GetPasswordAuthenticationKey(username, password, poolName, tupleAa, B, salt);

            // HMAC our data with key (HKDF(S)) (the shared secret)
            var contentBytes = CognitoAuthHelper.CombineBytes(new [] { Encoding.UTF8.GetBytes(poolName), Encoding.UTF8.GetBytes(username),
                                                                       secretBlockBytes, Encoding.UTF8.GetBytes(formattedTimestamp) });

            using (var hashAlgorithm = new HMACSHA256(key))
            {
                return(hashAlgorithm.ComputeHash(contentBytes));
            }
        }
Beispiel #2
0
        /// <summary>
        /// Computes the device key hash given the device group key, device key, and user password
        /// </summary>
        /// <param name="deviceGroupKey">The device group key for the CognitoDevice</param>
        /// <param name="deviceKey">The device key for the CognitoDevice</param>
        /// <param name="password">The password for the CognitoUser associated with the device</param>
        /// <returns>Returns the device key hash for the given device</returns>
        public static byte[] GetDeviceKeyHash(string deviceGroupKey, string deviceKey, string password)
        {
            byte[] contentBytes = CognitoAuthHelper.CombineBytes(Encoding.UTF8.GetBytes(deviceGroupKey),
                                                                 Encoding.UTF8.GetBytes(deviceKey), Encoding.UTF8.GetBytes(":"), Encoding.UTF8.GetBytes(password));

            return(CognitoAuthHelper.Sha256.ComputeHash(contentBytes));
        }
Beispiel #3
0
        /// <summary>
        /// Creates the Password Authentication Key based on the SRP protocol
        /// </summary>
        /// <param name="userID"> Username of CognitoUser</param>
        /// <param name="userPassword">Password of CognitoUser</param>
        /// <param name="poolName">PoolName of CognitoUserPool (part of poolID after "_")</param>
        /// <param name="Aa">Returned from TupleAa</param>
        /// <param name="B">BigInteger SRPB from AWS ChallengeParameters</param>
        /// <param name="salt">BigInteger salt from AWS ChallengeParameters</param>
        /// <returns>Returns the password authentication key for the SRP protocol</returns>
        public static byte[] GetPasswordAuthenticationKey(string userID,
                                                          string userPassword,
                                                          string poolName,
                                                          Tuple <BigInteger, BigInteger> Aa,
                                                          BigInteger B,
                                                          BigInteger salt)
        {
            // Authenticate the password
            // u = H(A, B)
            byte[] contentBytes = CognitoAuthHelper.CombineBytes(new [] { Aa.Item1.ToBigEndianByteArray(), B.ToBigEndianByteArray() });
            byte[] digest       = CognitoAuthHelper.Sha256.ComputeHash(contentBytes);

            BigInteger u = BigIntegerExtensions.FromUnsignedBigEndian(digest);

            if (u.Equals(BigInteger.Zero))
            {
                throw new ArgumentException("Hash of A and B cannot be zero.");
            }

            // x = H(salt | H(poolName | userId | ":" | password))
            byte[] userIdContent = CognitoAuthHelper.CombineBytes(new byte[][] { Encoding.UTF8.GetBytes(poolName), Encoding.UTF8.GetBytes(userID),
                                                                                 Encoding.UTF8.GetBytes(":"), Encoding.UTF8.GetBytes(userPassword) });
            byte[] userIdHash = CognitoAuthHelper.Sha256.ComputeHash(userIdContent);
            byte[] xBytes     = CognitoAuthHelper.CombineBytes(new byte[][] { salt.ToBigEndianByteArray(), userIdHash });

            byte[]     xDigest = CognitoAuthHelper.Sha256.ComputeHash(xBytes);
            BigInteger x       = BigIntegerExtensions.FromUnsignedBigEndian(xDigest);

            // Use HKDF to get final password authentication key
            var        first      = (B - k * BigInteger.ModPow(g, x, N)).TrueMod(N);
            var        second     = BigInteger.ModPow(first, Aa.Item2 + u * x, N);
            HkdfSha256 hkdfSha256 = new HkdfSha256(u.ToBigEndianByteArray(), second.ToBigEndianByteArray());

            return(hkdfSha256.Expand(Encoding.UTF8.GetBytes(DerivedKeyInfo), DerivedKeySizeBytes));
        }
        /// <summary>
        /// Generates a DeviceSecretVerifierConfigType object based on a CognitoDevice's Key, Group Key, and Password
        /// </summary>
        /// <param name="deviceGroupKey">The Group Key of the CognitoDevice</param>
        /// <param name="devicePass">A random password for the CognitoDevice (used in the future for logging in via this device)</param>
        /// <param name="username">The username of the CognitoDevice user</param>
        /// <returns></returns>
        public static DeviceSecretVerifierConfigType GenerateDeviceVerifier(string deviceGroupKey, string devicePass, string username)
        {
            Random r = new Random();

            byte[] userIdContent = CognitoAuthHelper.CombineBytes(
                Encoding.UTF8.GetBytes(deviceGroupKey),
                Encoding.UTF8.GetBytes(username),
                Encoding.UTF8.GetBytes(":"),
                Encoding.UTF8.GetBytes(devicePass)
                );

            byte[] userIdHash = CognitoAuthHelper.Sha256.ComputeHash(userIdContent);

            byte[] saltBytes = new byte[16];
            RandomNumberGenerator.Create().GetBytes(saltBytes);
            // setting the initial byte to 0-127 to avoid negative salt or password verifier error
            saltBytes[0] = (byte)r.Next(sbyte.MaxValue);

            byte[]     xBytes  = CognitoAuthHelper.CombineBytes(saltBytes, userIdHash);
            byte[]     xDigest = CognitoAuthHelper.Sha256.ComputeHash(xBytes);
            BigInteger x       = BigIntegerExtensions.FromUnsignedBigEndian(xDigest);

            var v = BigInteger.ModPow(g, x, N);

            byte[] vBytes = v.ToBigEndianByteArray();

            return(new DeviceSecretVerifierConfigType
            {
                PasswordVerifier = Convert.ToBase64String(vBytes),
                Salt = Convert.ToBase64String(saltBytes)
            });
        }
Beispiel #5
0
        /// <summary>
        /// Internal method for generating k for the input key material to HKDF
        /// </summary>
        /// <returns>Returns the BigInteger k value for the HKDF protocol's ikm</returns>
        private static BigInteger CreateKForGeneratingIkm()
        {
            var content       = CognitoAuthHelper.CombineBytes(new[] { N.ToBigEndianByteArray(), g.ToBigEndianByteArray() });
            var messageDigest = CognitoAuthHelper.Sha256.ComputeHash(content);

            return(BigIntegerExtensions.FromBigEndian(messageDigest));
        }
Beispiel #6
0
        static AuthenticationHelper()
        {
            // generate k for the input key material to HKDF
            var content       = CognitoAuthHelper.CombineBytes(new[] { N.ToBigEndianByteArray(), g.ToBigEndianByteArray() });
            var messageDigest = CognitoAuthHelper.Sha256.ComputeHash(content);

            k = BigIntegerExtensions.FromUnsignedBigEndian(messageDigest);
        }
Beispiel #7
0
        /// <summary>
        /// Calculates the device verifier for the device given the salt and device key hash
        /// </summary>
        /// <param name="salt">The salt for the SHA256 hash to compute the device verifier</param>
        /// <param name="deviceKeyHash">The device key hash for the associated CognitoDevice</param>
        /// <returns>Returns the device verifier for the associated CognitoDevice</returns>
        public static BigInteger CalculateVerifier(byte[] salt, byte[] deviceKeyHash)
        {
            var contentBytes = CognitoAuthHelper.CombineBytes(new[] { salt, deviceKeyHash });
            var digest       = CognitoAuthHelper.Sha256.ComputeHash(contentBytes);

            var x = new BigInteger(digest);

            return(BigInteger.ModPow(x, AuthenticationHelper.g, AuthenticationHelper.N));
        }
        /// <summary>
        /// Creates the Device Password Authentication Key based on the SRP protocol
        /// </summary>
        /// <param name="username"> Username of Cognito User</param>
        /// <param name="devicePass">Password of CognitoDevice</param>
        /// <param name="deviceGroup">GroupKey of CognitoDevice</param>
        /// <param name="Aa">Returned from TupleAa</param>
        /// <param name="B">BigInteger SRPB from AWS ChallengeParameters</param>
        /// <param name="salt">BigInteger salt from AWS ChallengeParameters</param>
        /// <returns>Returns the password authentication key for the SRP protocol</returns>
        public static byte[] GetDeviceAuthenticationKey(
            string username,
            string devicePass,
            string deviceGroup,
            Tuple <BigInteger, BigInteger> Aa,
            BigInteger B,
            BigInteger salt)
        {
            // Authenticate the password
            // u = H(A, B)
            byte[] contentBytes = CognitoAuthHelper.CombineBytes(Aa.Item1.ToBigEndianByteArray(), B.ToBigEndianByteArray());
            byte[] digest       = CognitoAuthHelper.Sha256.ComputeHash(contentBytes);

            BigInteger u = BigIntegerExtensions.FromUnsignedBigEndian(digest);

            if (u.Equals(BigInteger.Zero))
            {
                throw new ArgumentException("Hash of A and B cannot be zero.");
            }

            // x = H(salt | H(deviceGroupKey | deviceKey | ":" | devicePassword))
            byte[] deviceContent = CognitoAuthHelper.CombineBytes(Encoding.UTF8.GetBytes(deviceGroup), Encoding.UTF8.GetBytes(username),
                                                                  Encoding.UTF8.GetBytes(":"), Encoding.UTF8.GetBytes(devicePass));
            byte[] deviceHash = CognitoAuthHelper.Sha256.ComputeHash(deviceContent);
            byte[] xBytes     = CognitoAuthHelper.CombineBytes(salt.ToBigEndianByteArray(), deviceHash);

            byte[]     xDigest = CognitoAuthHelper.Sha256.ComputeHash(xBytes);
            BigInteger x       = BigIntegerExtensions.FromUnsignedBigEndian(xDigest);

            var gX = BigInteger.ModPow(g, x, N);
            // Use HKDF to get final password authentication key
            var intValue2 = (B - k * gX).TrueMod(N);
            var s_value   = BigInteger.ModPow(intValue2, Aa.Item2 + u * x, N);

            HkdfSha256 hkdfSha256 = new HkdfSha256(u.ToBigEndianByteArray(), s_value.ToBigEndianByteArray());

            return(hkdfSha256.Expand(Encoding.UTF8.GetBytes(DerivedKeyInfo), DerivedKeySizeBytes));
        }