Example #1
0
        /// <summary>
        ///     Compares a given (plain text) password with the (already hashed) password that is inside the hashData object.
        /// </summary>
        /// <param name="givenPassword">Plain text password to compare with</param>
        /// <param name="hashData">
        ///     The <see cref="PasswordHashingData" /> object that contains salt size, current hashed password, etc. for use in the
        ///     comparison
        ///     of the two passwords
        /// </param>
        public CommandResult ComparePasswords(string givenPassword, PasswordHashingData hashData)
        {
            if (String.IsNullOrWhiteSpace(givenPassword) || String.IsNullOrWhiteSpace(hashData?.HashedPassword) ||
                String.IsNullOrWhiteSpace(hashData.Salt))
            {
                return(CommandResultFactory.Fail("The given data to compare passwords was invalid.", false));
            }

            var saltByteArray = hashData.Salt.ToHexBytes();

            // Run initial hash at an application level
            var appHashedPassword = GetAppLevelPasswordHash(givenPassword);

            // Take the output of the initial hashing and run it through proper hashing with key stretching
            var hashedPasswordResult =
                ComputePasswordAndSaltBytes(saltByteArray, appHashedPassword, hashData.NumberOfIterations)
                .Then(computedBytes =>
            {
                var hashedPassword = computedBytes.ToHexString();
                return(CommandResultFactory.Ok <string>(hashedPassword));
            });

            if (hashedPasswordResult.IsFailure)
            {
                return(CommandResultFactory.Fail(
                           $"Computing the hash for the given password was not successful due to the following:\n{hashedPasswordResult.Message}"));
            }

            return(hashedPasswordResult.Value == hashData.HashedPassword
                ? CommandResultFactory.Ok()
                : CommandResultFactory.Fail("Passwords did not match"));
        }
Example #2
0
        /// <summary>
        ///     This is a way to chain a "Finally" handling callback method onto the end of the method chain. You can think of this
        ///     as being
        ///     similar to a "finally" call in .Net. The "Finally" will always call the callback method parameter. The callback
        ///     itself can
        ///     be responsible for whether or not to pass along a success or fail. There are also overloads that will simply call
        ///     the callback
        ///     and return the current success/fail status.
        ///     <para>
        ///         For example: When there is an error and there is a way for the error to be corrected or an attempt to correct
        ///         the error can be made. The Catch
        ///         chained method can correct the error and then allow the method chain to continue in a successful manner.
        ///     </para>
        ///     <para>
        ///         Another example is where the Catch method can log an error.
        ///     </para>
        /// </summary>
        /// <param name="callback">Method to be called (no matter what).</param>
        public static CommandResult <TOutput> Finally <TOutput>(this CommandResult @this, Func <CommandResult, CommandResult <TOutput> > callback)
        {
            var result = @this.IsSuccessful
                ? callback(CommandResultFactory.Ok(@this.Message))
                : callback(CommandResultFactory.Fail(@this.Message));

            return(result);
        }
        /// <summary>
        ///     Decrypts the given encrypted text (cipher text) using the given key and key size.
        /// </summary>
        /// <param name="cipherText">The encrypted text to decrypt</param>
        /// <param name="key">The (HEXADECIMAL) key used to encrypt the text and that will be used to decrypt it</param>
        /// <param name="keySize">The size of the key for the creation of the cipher</param>
        public CommandResult <string> Decrypt(string cipherText, string key, AesKeySize keySize)
        {
            if (String.IsNullOrWhiteSpace(cipherText))
            {
                return(CommandResultFactory.Fail("There was no text given to decrypt", (string)null));
            }
            if (String.IsNullOrWhiteSpace(key))
            {
                return(CommandResultFactory.Fail("Could not decrypt the text. The given key was null or empty.", (string)null));
            }

            try
            {
                CommandResult <string> result;
                using (var aesCipher = Aes.Create())
                {
                    result = SetupCipher(aesCipher, key, keySize)
                             .Then(aes =>
                    {
                        var splitCipher = cipherText.Split('_');
                        if (splitCipher.Length != 2)
                        {
                            return(CommandResultFactory.Fail("The given cipher text was not in the correct encrypted format for decryption",
                                                             (string)null));
                        }
                        var initVector      = splitCipher[0];
                        var encryptedString = splitCipher[1];
                        if (initVector.Length % 2 != 0 || encryptedString.Length % 2 != 0)
                        {
                            return(CommandResultFactory.Fail("The given cipher text was not in the correct encrypted format for decryption",
                                                             (string)null));
                        }
                        aes.IV = initVector.ToHexBytes();
                        var cryptoTransform = aes.CreateDecryptor();
                        var cipherBytes     = encryptedString.ToHexBytes();
                        if (cipherBytes == null)
                        {
                            return(CommandResultFactory.Fail(
                                       "The encrypted string could not be converted into a Hexadecimal Byte Array and therefore could not be decrypted.",
                                       (string)null));
                        }
                        var resultTextBytes = cryptoTransform.TransformFinalBlock(cipherBytes, 0, cipherBytes.Length);
                        var resultText      = resultTextBytes.ToUTF8String();

                        return(resultText == null
                                ? CommandResultFactory.Fail("Could not convert the decrypted bytes into a string.", (string)null)
                                : CommandResultFactory.Ok <string>(resultText));
                    });
                }

                return(result);
            }
            catch (Exception e)
            {
                var message = $"An exception was thrown while trying to decrypt the text. It is as follows:\n{e.Message}";
                return(CommandResultFactory.Fail(message, (string)null));
            }
        }
Example #4
0
        /// <summary>
        ///     This is a way to chain a error handling callback method onto the end of the method chain. The "Catch" will always
        ///     call the callback
        ///     method parameter. The callback itself is responsible for whether or not to pass along a success or fail.
        ///     <para>
        ///         For example: When there is an error and there is a way for the error to be corrected or an attempt to correct
        ///         the error can be made. The Catch
        ///         chained method can correct the error and then allow the method chain to continue in a successful manner.
        ///     </para>
        ///     <para>
        ///         Another example is where the Catch method can log an error.
        ///     </para>
        /// </summary>
        /// <param name="callback">Method to be called (no matter what).</param>
        public static CommandResult Catch(this CommandResult @this, Func <CommandResult, CommandResult> callback)
        {
            if (@this.IsSuccessful)
            {
                return(CommandResultFactory.Ok(@this.Message));
            }
            var errorFunq = callback(@this);

            return(errorFunq);
        }
Example #5
0
        /// <summary>
        ///     This is a way to chain a error handling callback method onto the end of the method chain. The "Catch" will always
        ///     call the callback
        ///     method parameter. The callback itself is responsible for whether or not to pass along a success or fail.
        ///     <para>
        ///         For example: When there is an error and there is a way for the error to be corrected or an attempt to correct
        ///         the error can be made. The Catch
        ///         chained method can correct the error and then allow the method chain to continue in a successful manner.
        ///     </para>
        ///     <para>
        ///         Another example is where the Catch method can log an error.
        ///     </para>
        /// </summary>
        /// <param name="callback">Method to be called (no matter what).</param>
        public static CommandResult Catch <TInput>(this CommandResult <TInput> @this, Func <CommandResult <TInput>, CommandResult> callback)
        {
            if (@this.IsSuccessful)
            {
                return(CommandResultFactory.Ok(@this.Message));
            }
            var funq = callback(@this);

            return(funq);
        }
Example #6
0
        /// <summary>
        ///     Chains a method onto a <see cref="CommandResult{T}" />.
        /// </summary>
        /// <param name="callback">Method to be used as long as <see cref="CommandResult.IsSuccessful" /> is true</param>
        public static CommandResult <TOutput> Then <TOutput>(this CommandResult @this, Func <CommandResult <TOutput> > callback)
        {
            if (@this.IsFailure)
            {
                return(CommandResultFactory.Fail <TOutput>(@this.Message, null));
            }
            var funq = callback();

            return(funq);
        }
Example #7
0
        /// <summary>
        ///     This is an async way to chain a "Finally" handling callback method onto the end of the method chain. You can think
        ///     of this as being
        ///     similar to a "finally" call in .Net. The "Finally" will always call the callback method parameter. The callback
        ///     itself can
        ///     be responsible for whether or not to pass along a success or fail. There are also overloads that will simply call
        ///     the callback
        ///     and return the current success/fail status.
        ///     <para>
        ///         For example: When there is an error and there is a way for the error to be corrected or an attempt to correct
        ///         the error can be made. The Catch
        ///         chained method can correct the error and then allow the method chain to continue in a successful manner.
        ///     </para>
        ///     <para>
        ///         Another example is where the Catch method can log an error.
        ///     </para>
        /// </summary>
        /// <param name="callback">Method to be called (no matter what).</param>
        public static async Task <CommandResult> FinallyAsync(this Task <CommandResult> thisAsync, Func <CommandResult, Task <CommandResult> > callback)
        {
            var @this = await thisAsync.ConfigureAwait(false);

            var result = @this.IsSuccessful
                ? await callback(CommandResultFactory.Ok(@this)).ConfigureAwait(false)
                : await callback(CommandResultFactory.Fail(@this.Message, @this)).ConfigureAwait(false);

            return(result);
        }
Example #8
0
        /// <summary>
        ///     Chains a method onto a <see cref="CommandResult{T}" />.
        /// </summary>
        /// <param name="callback">Method to be used as long as <see cref="CommandResult.IsSuccessful" /> is true</param>
        public static CommandResult <TOutput> Then <TInput, TOutput>(this CommandResult <TInput> @this, Func <TInput, CommandResult <TOutput> > callback)
        {
            if (@this.IsFailure)
            {
                return(CommandResultFactory.Fail(@this.Message, default(TOutput)));
            }
            var result = callback(@this.Value);

            return(result);
        }
Example #9
0
        /// <summary>
        ///     This is an async way to chain a error handling callback method onto the end of the method chain. The "Catch" will
        ///     always call the callback
        ///     method parameter. The callback itself is responsible for whether or not to pass along a success or fail.
        ///     <para>
        ///         For example: When there is an error and there is a way for the error to be corrected or an attempt to correct
        ///         the error can be made. The Catch
        ///         chained method can correct the error and then allow the method chain to continue in a successful manner.
        ///     </para>
        ///     <para>
        ///         Another example is where the Catch method can log an error.
        ///     </para>
        /// </summary>
        /// <param name="callback">Method to be called (no matter what).</param>
        public static async Task <CommandResult> CatchAsync(this Task <CommandResult> thisTask, Func <Task <CommandResult> > callback)
        {
            var @this = await thisTask.ConfigureAwait(false);

            if (@this.IsSuccessful)
            {
                return(await Task.FromResult(CommandResultFactory.Ok(@this.Message)).ConfigureAwait(false));
            }
            var errorFunq = await callback().ConfigureAwait(false);

            return(errorFunq);
        }
Example #10
0
        /// <summary>
        ///     Chains a method onto a <see cref="CommandResult{T}" /> in an async manner to allow for Async usage.
        /// </summary>
        /// <param name="callback">Method to be used as long as <see cref="CommandResult.IsSuccessful" /> is true</param>
        public static async Task <CommandResult> ThenAsync(this Task <CommandResult> thisTask, Func <Task <CommandResult> > callback)
        {
            var @this = await thisTask;

            if (@this.IsFailure)
            {
                return(await Task.FromResult(CommandResultFactory.Fail(@this.Message)).ConfigureAwait(false));
            }
            var funq = await callback().ConfigureAwait(false);

            return(funq);
        }
Example #11
0
        /// <summary>
        ///     Chains a method onto a <see cref="CommandResult{T}" /> in an async manner to allow for Async usage.
        /// </summary>
        /// <param name="callback">Method to be used as long as <see cref="CommandResult.IsSuccessful" /> is true</param>
        public static async Task <CommandResult <TOutput> > ThenAsync <TOutput>(this Task <CommandResult <TOutput> > thisTask, Func <TOutput, Task <CommandResult <TOutput> > > callback)
        {
            var @this = await thisTask;

            if (@this.IsFailure)
            {
                return(await Task.FromResult(CommandResultFactory.Fail(@this.Message, default(TOutput))));
            }
            var funq = await callback(@this.Value).ConfigureAwait(false);

            return(funq);
        }
Example #12
0
        /// <summary>
        ///     Decrypts the cipher text by using the given key material, key size, and block size.
        /// </summary>
        /// <param name="cipherText">Encrypted text for decryption</param>
        /// <param name="key">The (HEXADECIMAL) key used for decryption</param>
        /// <param name="keySize">size of key used in the cipher creation</param>
        /// <param name="blockSize">block size used in the creation of the cipher</param>
        /// <returns></returns>
        public CommandResult <string> CustomDecrypt(string cipherText, string key, AesKeySize keySize, BlockSize blockSize)
        {
            if (String.IsNullOrWhiteSpace(cipherText))
            {
                return(CommandResultFactory.Fail("There was nothing to encrypt", (string)null));
            }
            if (String.IsNullOrWhiteSpace(key))
            {
                return(CommandResultFactory.Fail("The given encryption key was null or empty", cipherText));
            }

            try
            {
                var result = CreateCustomCipher(key, blockSize, keySize)
                             .Then(cipher =>
                {
                    var splitCipher = cipherText.Split('_');
                    if (splitCipher.Length != 2)
                    {
                        return(CommandResultFactory.Fail("The given cipher text was not in the correct encrypted format for decryption",
                                                         (string)null));
                    }
                    var initVector      = splitCipher[0];
                    var encryptedString = splitCipher[1];
                    if (initVector.Length % 2 != 0 || encryptedString.Length % 2 != 0)
                    {
                        return(CommandResultFactory.Fail("The given cipher text was not in the correct encrypted format for decryption",
                                                         (string)null));
                    }
                    cipher.IV           = initVector.ToHexBytes();
                    var cryptoTransform = cipher.CreateDecryptor();
                    var cipherBytes     = encryptedString.ToHexBytes();
                    if (cipherBytes == null)
                    {
                        return(CommandResultFactory.Fail(
                                   "The encrypted string could not be converted into a Hexadecimal Byte Array and therefore could not be decrypted.",
                                   (string)null));
                    }
                    var resultTextBytes = cryptoTransform.TransformFinalBlock(cipherBytes, 0, cipherBytes.Length);
                    var resultText      = resultTextBytes.ToUTF8String();

                    return(resultText == null
                            ? CommandResultFactory.Fail("Could not convert the decrypted bytes into a string.", (string)null)
                            : CommandResultFactory.Ok <string>(resultText));
                });
                return(result);
            }
            catch (Exception e)
            {
                Trace.WriteLine(e);
                return(CommandResultFactory.Fail($"An exception was thrown while attempting to decrypt the given text. It is as follows:\n\t{e.Message}", (string)null));
            }
        }
Example #13
0
        /// <summary>
        ///     This is a way to chain a "Finally" handling callback method onto the end of the method chain. You can think of this
        ///     as being
        ///     similar to a "finally" call in .Net. The "Finally" will always call the callback method parameter. The callback
        ///     itself can
        ///     be responsible for whether or not to pass along a success or fail. There are also overloads that will simply call
        ///     the callback
        ///     and return the current success/fail status.
        ///     <para>
        ///         For example: When there is an error and there is a way for the error to be corrected or an attempt to correct
        ///         the error can be made. The Catch
        ///         chained method can correct the error and then allow the method chain to continue in a successful manner.
        ///     </para>
        ///     <para>
        ///         Another example is where the Catch method can log an error.
        ///     </para>
        /// </summary>
        /// <param name="callback">Method to be called (no matter what).</param>
        public static CommandResult Finally(this CommandResult @this, Action <CommandResult> callback)
        {
            if (@this.IsSuccessful)
            {
                var okResult = CommandResultFactory.Ok(@this, @this.Message);
                callback(okResult);
                return(okResult);
            }

            var failResult = CommandResultFactory.Fail(@this.Message);

            callback(failResult);
            return(failResult);
        }
Example #14
0
        /// <summary>
        ///     This will compute a hash for the given password and salt using the iterationCount parameter to determine how many
        ///     times the
        ///     hashing will occur on the password + salt.
        /// </summary>
        /// <param name="salt">The salt that is added on to the end of the password</param>
        /// <param name="password">The password to be hashed</param>
        /// <param name="iterationCount">The number of times the password+salt will have a hash computed</param>
        /// <returns></returns>
        public CommandResult <byte[]> ComputePasswordAndSaltBytes(byte[] salt, string password, int iterationCount = MinIterationRange)
        {
            if (String.IsNullOrWhiteSpace(password))
            {
                return(CommandResultFactory.Fail("Password was null", (byte[])null));
            }
            if (salt == null || salt.Length < 1)
            {
                return(CommandResultFactory.Fail("The salt did not meet the minimum length", (byte[])null));
            }
            if (salt.Length > MaxSaltSize)
            {
                return(CommandResultFactory.Fail("The salt length was greater than the maximum allowed", (byte[])null));
            }

            var convertedPassword = password.ToUtf8Bytes();

            if (convertedPassword.Length > MaxPasswordSize)
            {
                return(CommandResultFactory.Fail($"The password length was greater than the maximum allowed. Please make it less than {MaxPasswordSize}",
                                                 (byte[])null));
            }

            if (convertedPassword.Length < MinPasswordSize)
            {
                return(CommandResultFactory.Fail($"The password length was less than the minimum allowed. Please make it greater than {MinPasswordSize}",
                                                 (byte[])null));
            }

            try
            {
                var resultValue = new Rfc2898(convertedPassword, salt, iterationCount).GetDerivedKeyBytes_PBKDF2_HMACSHA512(KeyLength);
                return(CommandResultFactory.Ok(resultValue));
            }
            catch (IterationsLessThanRecommended)
            {
                return(CommandResultFactory.Fail("The number of hash iterations did not meet minimum standards", (byte[])null));
            }
            catch (SaltLessThanRecommended)
            {
                return(CommandResultFactory.Fail("The salt length is less than the minimum standards", (byte[])null));
            }
            catch (Exception e)
            {
                return(CommandResultFactory.Fail(
                           $"There was an unspecified error that ocurred from an exception being thrown. The exception is as follows:\n{e.Message}",
                           (byte[])null));
            }
        }
Example #15
0
        /// <summary>
        ///     This is an async way to chain a "Finally" handling callback method onto the end of the method chain. You can think
        ///     of this as being
        ///     similar to a "finally" call in .Net. The "Finally" will always call the callback method parameter. The callback
        ///     itself can
        ///     be responsible for whether or not to pass along a success or fail. There are also overloads that will simply call
        ///     the callback
        ///     and return the current success/fail status.
        ///     <para>
        ///         For example: When there is an error and there is a way for the error to be corrected or an attempt to correct
        ///         the error can be made. The Catch
        ///         chained method can correct the error and then allow the method chain to continue in a successful manner.
        ///     </para>
        ///     <para>
        ///         Another example is where the Catch method can log an error.
        ///     </para>
        /// </summary>
        /// <param name="callback">Method to be called (no matter what).</param>
        public static async Task <CommandResult> Finally(this Task <CommandResult> thisAsync, Func <CommandResult, Task> callback)
        {
            var @this = await thisAsync.ConfigureAwait(false);

            if (@this.IsSuccessful)
            {
                var okResult = CommandResultFactory.Ok(@this, @this.Message);
                await callback(okResult).ConfigureAwait(false);

                return(okResult);
            }

            var failResult = CommandResultFactory.Fail(@this.Message);

            await callback(failResult).ConfigureAwait(false);

            return(failResult);
        }
        /// <summary>
        /// Hashes the given plain-text password using the global application hash. If there is no global application hash then the given password
        /// is returned simply hashed without the global app salt.
        /// </summary>
        /// <param name="givenPassword"></param>
        public string GetAppLevelPasswordHash(string givenPassword)
        {
            if (String.IsNullOrWhiteSpace(givenPassword))
            {
                return(givenPassword);
            }

            if (String.IsNullOrWhiteSpace(_globalApplicationSalt))
            {
                var hash512Password = ComputeSha512HexString(givenPassword);
                return(hash512Password);
            }
            var appSaltByteArray     = _globalApplicationSalt.ToHexBytes();
            var hashedPasswordResult = ComputePasswordAndSaltBytes(appSaltByteArray, givenPassword, AppHashIterations)
                                       .Then(byteResult =>
            {
                var hashedPassword = byteResult.ToHexString();
                return(CommandResultFactory.Ok <string>(hashedPassword));
            });

            return(hashedPasswordResult.IsFailure ? givenPassword : hashedPasswordResult.Value);
        }
        /// <summary>
        ///     Sets up all the parameters and properties for the AES cipher used in the encryption.
        /// </summary>
        /// <param name="cipher">
        ///     The already created AES cipher. This should be created within a using statement and then handed
        ///     off to this method.
        /// </param>
        /// <param name="key">The (HEXADECIMAL) key used for encryption inside the cipher</param>
        /// <param name="keySize">Key size used for setting up the cipher</param>
        public CommandResult <Aes> SetupCipher(Aes cipher, string key, AesKeySize keySize)
        {
            if (cipher == null)
            {
                return(CommandResultFactory.Fail("The given AES cipher object was null", (Aes)null));
            }
            if (String.IsNullOrWhiteSpace(key))
            {
                return(CommandResultFactory.Fail("The cipher creation key for the encryption was null or empty", (Aes)null));
            }

            byte[] keyBytes;
            try
            {
                keyBytes = key.ToHexBytes();
                if (keyBytes == null || keyBytes.Length != (int)keySize / 8)
                {
                    return(CommandResultFactory.Fail($"The cipher creation key for the encryption did not match the specified key size of {keySize}",
                                                     (Aes)null));
                }
            }
            catch (FormatException)
            {
                return(CommandResultFactory.Fail("The key was malformed and therefore threw a Format Exception when converting to a byte array.", (Aes)null));
            }
            catch (Exception e)
            {
                return(CommandResultFactory.Fail($"There was an exception thrown while trying to create the cipher. It is as follows:\n\t{e.Message}", (Aes)null));
            }

            cipher.KeySize   = (int)keySize;
            cipher.BlockSize = 128; // This is the default block size for AES encryption and apparently should not be changed according to what I'm reading
            cipher.Padding   = PaddingMode.PKCS7;
            cipher.Mode      = CipherMode.CBC;
            cipher.Key       = keyBytes;
            cipher.GenerateIV();
            return(CommandResultFactory.Ok(cipher));
        }
Example #18
0
        /// <summary>
        ///     Encrypts a string using the given key. To Decrypt you will need the proper initialization vector that gets randomly
        ///     generated for each encryption process (i.e. different every time the encryption is run). This will happen
        ///     automatically in
        ///     our Decrypt method on this class because we're prefixing those initialization vectors with the encrypted text.
        /// </summary>
        /// <param name="textForEncryption">Text value to be encrypted</param>
        /// <param name="key">
        ///     MUST be a hexadecimal string that is at least 16 bytes in length. Should be more like 32 bytes in
        ///     length
        /// </param>
        /// <param name="keySize">Size of the key used in creating the cipher</param>
        /// <param name="blockSize">Size of the block used in the creation of the Rijndael Managed cipher</param>
        public CommandResult <string> CustomEncrypt(string textForEncryption, string key, AesKeySize keySize, BlockSize blockSize)
        {
            if (String.IsNullOrWhiteSpace(textForEncryption))
            {
                return(CommandResultFactory.Fail("There was nothing to encrypt", (string)null));
            }
            if (String.IsNullOrWhiteSpace(key))
            {
                return(CommandResultFactory.Fail("The given encryption key was null or empty", textForEncryption));
            }

            try
            {
                var encryptResult = CreateCustomCipher(key, blockSize, keySize)
                                    .Then(cipher =>
                {
                    var initVector = cipher.IV.ToHexString();

                    // Create the encryptor, convert to bytes, and encrypt the plainText string
                    var cryptoTransform = cipher.CreateEncryptor();
                    var plainTextBytes  = textForEncryption.ToUtf8Bytes();
                    var cipherTextBytes = cryptoTransform.TransformFinalBlock(plainTextBytes, 0, plainTextBytes.Length);

                    // Get the Hexadecimal string of the cipherTextBytes, hash it, and prefix the Initialization Vector to it.
                    // We're using a hexadecimal string so that the cipherText can be used in URL's. Yes, there are other ways of doing that, but it's a style
                    // choice.
                    var cipherText    = cipherTextBytes.ToHexString();
                    var encryptedText = initVector + "_" + cipherText;
                    return(CommandResultFactory.Ok <string>(encryptedText));
                });
                return(encryptResult);
            }
            catch (Exception e)
            {
                Trace.WriteLine(e);
                return(CommandResultFactory.Fail($"An exception was thrown while attempting to encrypt the given text. It is as follows:\n\t{e.Message}", (string)null));
            }
        }
        /// <summary>
        ///     Encrypts the given text using the given key and key size for cipher creation.
        /// </summary>
        /// <param name="textForEncryption">Text to encrypt</param>
        /// <param name="key">The (HEXADECIMAL) encryption key to use for creating the cipher</param>
        /// <param name="keySize">Size of the key used for creating the cipher</param>
        public CommandResult <string> Encrypt(string textForEncryption, string key, AesKeySize keySize)
        {
            if (String.IsNullOrWhiteSpace(textForEncryption))
            {
                return(CommandResultFactory.Fail("There was nothing to encrypt", (string)null));
            }
            if (String.IsNullOrWhiteSpace(key))
            {
                return(CommandResultFactory.Fail("The given encryption key was null or empty", textForEncryption));
            }

            try
            {
                CommandResult <string> result;
                using (var aesCipher = Aes.Create())
                {
                    result = SetupCipher(aesCipher, key, keySize)
                             .Then(aes =>
                    {
                        var initVector          = aes.IV.ToHexString();
                        var textForEncryptBytes = textForEncryption.ToUtf8Bytes();
                        var cryptoTransform     = aes.CreateEncryptor();
                        var cipherTextBytes     = cryptoTransform.TransformFinalBlock(textForEncryptBytes, 0, textForEncryption.Length);
                        var cipherText          = cipherTextBytes.ToHexString();
                        var textResult          = $"{initVector}_{cipherText}";
                        return(CommandResultFactory.Ok <string>(textResult));
                    });
                }

                return(result);
            }
            catch (Exception e)
            {
                var message = $"An exception was thrown while trying to encrypt the text. It is as follows:\n{e.Message}";
                return(CommandResultFactory.Fail(message, (string)null));
            }
        }
Example #20
0
        /// <summary>
        ///     Creates a RijndaelManaged cipher based on the given key material and the given block and key size.
        /// </summary>
        /// <param name="key">The (HEXADECIMAL) key used during the creation of the cipher for encryption</param>
        /// <param name="blockSize">Block size of the cipher</param>
        /// <param name="keySize">Key Size of the cipher</param>
        public CommandResult <RijndaelManaged> CreateCustomCipher(string key, BlockSize blockSize, AesKeySize keySize)
        {
            if (String.IsNullOrWhiteSpace(key))
            {
                return(CommandResultFactory.Fail("There was no key provided for the cipher", (RijndaelManaged)null));
            }

            byte[] byteKey;
            try
            {
                byteKey = key.ToHexBytes();
                if (byteKey == null || byteKey.Length != (int)keySize / 8)
                {
                    return(CommandResultFactory.Fail($"The cipher creation key for the encryption did not match the specified key size of {keySize}", (RijndaelManaged)null));
                }
            }
            catch (FormatException)
            {
                return(CommandResultFactory.Fail("The key was malformed and therefore threw a Format Exception when converting to a byte array.", (RijndaelManaged)null));
            }
            catch (Exception e)
            {
                return(CommandResultFactory.Fail($"There was an exception thrown while trying to create the cipher. It is as follows:\n\t{e.Message}", (RijndaelManaged)null));
            }

            var cipher = new RijndaelManaged
            {
                KeySize   = (int)keySize,
                BlockSize = (int)blockSize,
                Padding   = PaddingMode.ISO10126,
                Mode      = CipherMode.CBC,
                Key       = byteKey
            };

            return(CommandResultFactory.Ok(cipher));
        }
Example #21
0
        /// <summary>
        ///     Computes a hash for a given password and returns a <see cref="PasswordHashingData" /> object to hold the elements
        ///     that made up the
        ///     hashed password
        /// </summary>
        /// <param name="givenPassword"></param>
        public CommandResult <PasswordHashingData> HashPassword(string givenPassword)
        {
            if (String.IsNullOrWhiteSpace(givenPassword))
            {
                return(CommandResultFactory.Fail("The given password was null or empty", (PasswordHashingData)null));
            }

            var hashData = new PasswordHashingData();
            var rand     = new Random();

            // Set the hash data
            hashData.NumberOfIterations = rand.Next(MinIterationRange, MaxIterationRange);
            hashData.SaltSize           = rand.Next(MinSaltSize, MaxSaltSize);
            var saltByteArray = GetRandomSalt(hashData.SaltSize);

            hashData.Salt = saltByteArray.ToHexString();

            // Run initial hash at an application level
            var appHashedPassword = GetAppLevelPasswordHash(givenPassword);

            // Take the output of the initial hashing and run it through proper hashing with key stretching
            var hashedPasswordResult =
                ComputePasswordAndSaltBytes(saltByteArray, appHashedPassword, hashData.NumberOfIterations)
                .Then(computedBytes =>
            {
                var hashedPassword = computedBytes.ToHexString();
                return(CommandResultFactory.Ok <string>(hashedPassword));
            });

            if (hashedPasswordResult.IsFailure)
            {
                return(CommandResultFactory.Fail(hashedPasswordResult.Message, hashData));
            }
            hashData.HashedPassword = hashedPasswordResult.Value;
            return(CommandResultFactory.Ok(hashData));
        }
Example #22
0
 /// <summary>
 ///     Chains a method onto a <see cref="CommandResult{T}" />.
 /// </summary>
 /// <param name="callback">Method to be used as long as <see cref="CommandResult.IsSuccessful" /> is true</param>
 public static CommandResult Then <TInput>(this CommandResult <TInput> @this, Func <TInput, CommandResult> callback)
 {
     return(@this.IsFailure ? CommandResultFactory.Fail(@this.Message) : callback(@this.Value));
 }
Example #23
0
 /// <summary>
 ///     Chains a method onto a <see cref="CommandResult{T}" />.
 /// </summary>
 /// <param name="callback">Method to be used as long as <see cref="CommandResult.IsSuccessful" /> is true</param>
 public static CommandResult Then(this CommandResult @this, Func <CommandResult> callback)
 {
     return(@this.IsFailure ? CommandResultFactory.Fail(@this.Message) : callback());
 }