public virtual void SetPassword(
            TAccount userAccount,
            string newPassword,
            string oldPassword = null,
            string nameOfExpensiveHashFunctionToUse  = null,
            int?numberOfIterationsToUseForPhase1Hash = null)
        {
            byte[] oldPasswordHashPhase1 = oldPassword == null ? null : ComputePhase1Hash(userAccount, oldPassword);


            if (nameOfExpensiveHashFunctionToUse != null)
            {
                userAccount.PasswordHashPhase1FunctionName = nameOfExpensiveHashFunctionToUse;
            }

            if (numberOfIterationsToUseForPhase1Hash.HasValue)
            {
                userAccount.NumberOfIterationsToUseForPhase1Hash = numberOfIterationsToUseForPhase1Hash.Value;
            }

            byte[] newPasswordHashPhase1 = ComputePhase1Hash(userAccount, newPassword);


            userAccount.PasswordHashPhase2 = ComputePhase2HashFromPhase1Hash(userAccount, newPasswordHashPhase1);


            if (oldPassword != null &&
                ComputePhase2HashFromPhase1Hash(userAccount, oldPasswordHashPhase1) == userAccount.PasswordHashPhase2)
            {
                try
                {
                    if (userAccount.EcPrivateAccountLogKeyEncryptedWithPasswordHashPhase1 == null)
                    {
                        using (Encryption.IPrivateKey accountLogKey =
                                   Encryption.DecryptAesCbcEncryptedPrivateKey(
                                       userAccount.EcPrivateAccountLogKeyEncryptedWithPasswordHashPhase1,
                                       oldPasswordHashPhase1))
                        {
                            if (accountLogKey != null)
                            {
                                SetAccountLogKey(userAccount, accountLogKey, newPasswordHashPhase1);
                            }
                            return;
                        }
                    }
                }
                catch (Exception)
                {
                }
            }


            using (Encryption.IPrivateKey newPrivateKey = Encryption.GenerateNewPrivateKey())
            {
                SetAccountLogKey(userAccount, newPrivateKey, newPasswordHashPhase1);
            }
        }
Esempio n. 2
0
 public virtual void SetAccountLogKey(
     TAccount userAccount,
     Encryption.IPrivateKey accountLogKey,
     byte[] phase1HashOfCorrectPassword)
 {
     //userAccount.EcPrivateAccountLogKeyEncryptedWithPasswordHashPhase1 = Encryption.EncryptPrivateKeyWithAesCbc(ecAccountLogKey,
     //    phase1HashOfCorrectPassword);
     //using (ECDiffieHellmanPublicKey publicKey = accountLogKey.PublicKey)
     //{
     //    userAccount.EcPublicAccountLogKey = publicKey.ToByteArray();
     //}
 }
        /// <summary>
        /// </summary>
        /// <param name="privateKey">The private key that can be used to decrypt the value.</param>
        /// <returns>The decrypted value.</returns>
        public byte[] Read(Encryption.IPrivateKey privateKey)
        {
            if (string.IsNullOrEmpty(Ciphertext))
            {
                throw new MemberAccessException("Cannot decrypt a value that has not been written.");
            }

            EcEncryptedMessageAesCbcHmacSha256 messageDeserializedFromJson =
                JsonConvert.DeserializeObject <EcEncryptedMessageAesCbcHmacSha256>(Ciphertext);

            return(messageDeserializedFromJson.Decrypt(privateKey));
        }
Esempio n. 4
0
        /// <summary>
        /// Decrypt the message by providing the recipient's private EC key.
        /// </summary>
        /// <param name="recipientsPrivateEcKey">The private EC key matching the public key provided for encryption.</param>
        /// <returns>The decrypted message as a byte array</returns>
        public byte[] Decrypt(Encryption.IPrivateKey recipientsPrivateEcKey)
        {
            return(this.EncryptedMessage);
            //byte[] sessionKey;

            //try
            //{
            //    using (CngKey otherPartiesPublicKey = CngKey.Import(PublicOneTimeEcKey, CngKeyBlobFormat.EccPublicBlob))
            //    {
            //        sessionKey = recipientsPrivateEcKey.DeriveKeyMaterial(otherPartiesPublicKey);
            //    }
            //}
            //catch (CryptographicException e)
            //{
            //    throw new Exception("Failed to Decrypt log entry", e);
            //}

            //return Encryption.DecryptAesCbc(EncryptedMessage, sessionKey, checkAndRemoveHmac: true);
        }
Esempio n. 5
0
        protected void AdjustBlockingScoreForPastTyposTreatedAsFullFailures(
            IpHistory clientsIpHistory,
            IUserAccountController <TUserAccount> accountController,
            TUserAccount account,
            DateTime whenUtc,
            string correctPassword,
            byte[] phase1HashOfCorrectPassword)
        {
            double credit = 0d;

            if (clientsIpHistory == null)
            {
                return;
            }

            LoginAttemptSummaryForTypoAnalysis[] recentPotentialTypos = clientsIpHistory.RecentPotentialTypos.MostRecentFirst.ToArray();
            Encryption.IPrivateKey privateAccountLogKey = null;
            try
            {
                foreach (LoginAttemptSummaryForTypoAnalysis potentialTypo in recentPotentialTypos)
                {
                    bool usernameCorrect = potentialTypo.UsernameOrAccountId == account.UsernameOrAccountId;

                    if (usernameCorrect)
                    {
                        string passwordSubmittedInFailedAttempt = null;
                        if (account.GetType().Name == "SimulatedUserAccount")
                        {
                            passwordSubmittedInFailedAttempt = potentialTypo.EncryptedIncorrectPassword.Ciphertext;
                        }
                        else
                        {
                            if (privateAccountLogKey == null)
                            {
                                try
                                {
                                    privateAccountLogKey = accountController.DecryptPrivateAccountLogKey(account,
                                                                                                         phase1HashOfCorrectPassword);
                                }
                                catch (Exception)
                                {
                                    return;
                                }
                            }
                            try
                            {
                                passwordSubmittedInFailedAttempt =
                                    potentialTypo.EncryptedIncorrectPassword.Read(privateAccountLogKey);
                            }
                            catch (Exception)
                            {
                            }
                        }

                        if (passwordSubmittedInFailedAttempt != null)
                        {
                            bool passwordHadTypo =
                                EditDistance.Calculate(passwordSubmittedInFailedAttempt, correctPassword) <=
                                _options.MaxEditDistanceConsideredATypo;

                            if (passwordHadTypo)
                            {
                                credit += potentialTypo.Penalty.GetValue(_options.AccountCreditLimitHalfLife, whenUtc) *
                                          (1d - _options.PenaltyMulitiplierForTypo);
                            }
                        }
                    }

                    clientsIpHistory.RecentPotentialTypos.Remove(potentialTypo);
                }

                clientsIpHistory.CurrentBlockScore.SubtractInPlace(account.CreditHalfLife, credit, whenUtc);
            }
            finally
            {
                privateAccountLogKey?.Dispose();
            }
        }
Esempio n. 6
0
        /// <summary>
        /// Sets the password of a user.
        /// <b>Important</b>: this does not authenticate the user but assumes the user has already been authenticated.
        /// The <paramref name="oldPassword"/> field is used only to optionally recover the EC symmetricKey, not to authenticate the user.
        /// </summary>
        /// <param name="userAccount"></param>
        /// <param name="newPassword">The new password to set.</param>
        /// <param name="oldPassword">If this optional field is provided and correct, the old password will allow us to re-use the old log decryption symmetricKey.
        /// <b>Providing this parameter will not cause this function to authenticate the user first.  The caller must do so beforehand.</b></param>
        /// <param name="nameOfExpensiveHashFunctionToUse">The name of the phase 1 (expenseive) hash to use.</param>
        /// <param name="numberOfIterationsToUseForPhase1Hash">The number of iterations that the hash should be performed.</param>
        public virtual void SetPassword(
            TAccount userAccount,
            string newPassword,
            string oldPassword = null,
            string nameOfExpensiveHashFunctionToUse  = null,
            int?numberOfIterationsToUseForPhase1Hash = null)
        {
            // Calculate the old passwords' phase 1 hash before making any changes to the hash function name or number of iterations.
            byte[] oldPasswordHashPhase1 = oldPassword == null ? null : ComputePhase1Hash(userAccount, oldPassword);

            // If the caller also wants to change the hash function or the number of iterations,
            // make that change here now that we're done hashing the old password and are about to hash the new one.
            if (nameOfExpensiveHashFunctionToUse != null)
            {
                userAccount.PasswordHashPhase1FunctionName = nameOfExpensiveHashFunctionToUse;
            }

            if (numberOfIterationsToUseForPhase1Hash.HasValue)
            {
                userAccount.NumberOfIterationsToUseForPhase1Hash = numberOfIterationsToUseForPhase1Hash.Value;
            }

            // Calculate the Phase1 hash, which is a computationally-heavy hash of the password
            // We will use this for encrypting the EC userAccount log symmetricKey.
            byte[] newPasswordHashPhase1 = ComputePhase1Hash(userAccount, newPassword);

            // Calculate the Phase2 hash by hasing the phase 1 hash with SHA256.
            // We can store this without revealing the phase 1 hash used to encrypt the EC userAccount log symmetricKey.
            // We can use it to verify whether a provided password is correct
            userAccount.PasswordHashPhase2 = ComputePhase2HashFromPhase1Hash(userAccount, newPasswordHashPhase1);

            // Store the ecAccountLogKey encrypted encrypted using symmetric encryption with the phase 1 password hash as its key.

            // First try using the ecAccountLogKey from the prior password
            if (oldPassword != null &&
                ComputePhase2HashFromPhase1Hash(userAccount, oldPasswordHashPhase1) == userAccount.PasswordHashPhase2)
            {
                // If we have a valid old password, Decrypt the private log decryption symmetricKey so we can re-encrypt it
                // with the new password and continue to use it on future logins.
                try
                {
                    using (Encryption.IPrivateKey accountLogKey =
                               Encryption.DecryptAesCbcEncryptedPrivateKey(
                                   userAccount.EcPrivateAccountLogKeyEncryptedWithPasswordHashPhase1,
                                   oldPasswordHashPhase1))
                    {
                        SetAccountLogKey(userAccount, accountLogKey, newPasswordHashPhase1);
                        return;
                    }
                }
                catch (Exception)
                {
                    // Ignore crypto failures.  They just mean we were unsuccessful in decrypting the symmetricKey and should create a new one.
                }
            }

            // We were unable to use an old EC Account Log Key,
            // so we'll create a new one
            using (Encryption.IPrivateKey newPrivateKey = Encryption.GenerateNewPrivateKey())
            {
                SetAccountLogKey(userAccount, newPrivateKey, newPasswordHashPhase1);
            }
        }
Esempio n. 7
0
 /// <summary>
 /// Set the EC account log key
 /// </summary>
 /// <param name="userAccount"></param>
 /// <param name="accountLogKey"></param>
 /// <param name="phase1HashOfCorrectPassword">The phase 1 hash of the correct password</param>
 /// <returns></returns>
 public virtual void SetAccountLogKey(
     SimulatedUserAccount userAccount,
     Encryption.IPrivateKey accountLogKey,
     byte[] phase1HashOfCorrectPassword)
 {
 }
        /// <summary>
        /// This analysis will examine the client IP's previous failed attempts to login to this account
        /// to determine if any failed attempts were due to typos.
        /// </summary>
        /// <param name="clientsIpHistory">Records of this client's previous attempts to examine.</param>
        /// <param name="accountController"></param>
        /// <param name="account">The account that the client is currently trying to login to.</param>
        /// <param name="whenUtc"></param>
        /// <param name="correctPassword">The correct password for this account.  (We can only know it because
        /// the client must have provided the correct one this loginAttempt.)</param>
        /// <param name="phase1HashOfCorrectPassword">The phase1 hash of that correct password (which we could
        /// recalculate from the information in the previous parameters, but doing so would be expensive.)</param>
        /// <returns></returns>
        protected void AdjustBlockingScoreForPastTyposTreatedAsFullFailures(
            IpHistory clientsIpHistory,
            IUserAccountController <TUserAccount> accountController,
            TUserAccount account,
            DateTime whenUtc,
            string correctPassword,
            byte[] phase1HashOfCorrectPassword)
        {
            double credit = 0d;

            if (clientsIpHistory == null)
            {
                return;
            }

            LoginAttemptSummaryForTypoAnalysis[] recentPotentialTypos = clientsIpHistory.RecentPotentialTypos.MostRecentFirst.ToArray();
            Encryption.IPrivateKey privateAccountLogKey = null;
            try
            {
                foreach (LoginAttemptSummaryForTypoAnalysis potentialTypo in recentPotentialTypos)
                {
                    bool usernameCorrect = potentialTypo.UsernameOrAccountId == account.UsernameOrAccountId;
                    //bool usernameHadTypo = !usernameCorrect &&
                    //    EditDistance.Calculate(potentialTypo.UsernameOrAccountId, account.UsernameOrAccountId) <=
                    //_options.MaxEditDistanceConsideredATypo;

                    if (usernameCorrect) // || usernameHadTypo
                    {
                        // Get the plaintext password from the previous login attempt
                        string passwordSubmittedInFailedAttempt = null;
                        if (account.GetType().Name == "SimulatedUserAccount")
                        {
                            passwordSubmittedInFailedAttempt = potentialTypo.EncryptedIncorrectPassword.Ciphertext;
                        }
                        else
                        {
                            if (privateAccountLogKey == null)
                            {
                                // Get the EC decryption key, which is stored encrypted with the Phase1 password hash
                                try
                                {
                                    privateAccountLogKey = accountController.DecryptPrivateAccountLogKey(account,
                                                                                                         phase1HashOfCorrectPassword);
                                }
                                catch (Exception)
                                {
                                    // There's a problem with the key that prevents us from decrypting it.  We won't be able to do this analysis.
                                    return;
                                }
                            }
                            // Now try to decrypt the incorrect password from the previous attempt and perform the typo analysis
                            try
                            {
                                // Attempt to decrypt the password.
                                passwordSubmittedInFailedAttempt =
                                    potentialTypo.EncryptedIncorrectPassword.Read(privateAccountLogKey);
                            }
                            catch (Exception)
                            {
                                // An exception is likely due to an incorrect key (perhaps outdated).
                                // Since we simply can't do anything with a record we can't Decrypt, we carry on
                                // as if nothing ever happened.  No.  Really.  Nothing to see here.
                            }
                        }

                        if (passwordSubmittedInFailedAttempt != null)
                        {
                            //bool passwordCorrect = passwordSubmittedInFailedAttempt == correctPassword;
                            bool passwordHadTypo = // !passwordCorrect &&
                                                   EditDistance.Calculate(passwordSubmittedInFailedAttempt, correctPassword) <=
                                                   _options.MaxEditDistanceConsideredATypo;

                            // Get credit for this nearly-correct attempt to counter penalty
                            if (passwordHadTypo)
                            {
                                credit += potentialTypo.Penalty.GetValue(_options.AccountCreditLimitHalfLife, whenUtc) *
                                          (1d - _options.PenaltyMulitiplierForTypo);
                            }
                        }
                    }

                    // Now that we know whether this past event was a typo or not, we no longer need to keep track
                    // of it (and we should remove it so we don't double credit it).
                    clientsIpHistory.RecentPotentialTypos.Remove(potentialTypo);
                }

                // Remove the amount to be credited from the block score due to the discovery of typos
                clientsIpHistory.CurrentBlockScore.SubtractInPlace(account.CreditHalfLife, credit, whenUtc);
            }
            finally
            {
                privateAccountLogKey?.Dispose();
            }
        }
 public new T Read(Encryption.IPrivateKey privateKey) => JsonConvert.DeserializeObject <T>(base.Read(privateKey));
Esempio n. 10
0
 public new string Read(Encryption.IPrivateKey privateKey) => Encoding.UTF8.GetString(base.Read(privateKey));
Esempio n. 11
0
 public byte[] Decrypt(Encryption.IPrivateKey recipientsPrivateEcKey)
 {
     return(this.EncryptedMessage);
 }