Added upgrade method to increase the number of iterations
This commit is contained in:
		
							parent
							
								
									ed83878039
								
							
						
					
					
						commit
						8b117c5e6c
					
				@ -128,5 +128,41 @@ namespace Encrypter_Tests
 | 
				
			|||||||
            var decryptedMessage = await encryptedData.Decrypt(password);
 | 
					            var decryptedMessage = await encryptedData.Decrypt(password);
 | 
				
			||||||
            Assert.That(decryptedMessage, Is.EqualTo(message));
 | 
					            Assert.That(decryptedMessage, Is.EqualTo(message));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Test]
 | 
				
			||||||
 | 
					        public async Task TestUpgradedIterationsBehaviour()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var message = "This is a test with umlauts äüö.";
 | 
				
			||||||
 | 
					            var password = "test password";
 | 
				
			||||||
 | 
					            var previousIterations = 1_000;
 | 
				
			||||||
 | 
					            var upgradedIterations = 1_000_000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var previousEncryptedData = await CryptoProcessor.EncryptString(message, password, previousIterations);
 | 
				
			||||||
 | 
					            var reEncryptedData = await CryptoProcessor.UpgradeIterations(previousEncryptedData, password, previousIterations, upgradedIterations);
 | 
				
			||||||
 | 
					            Assert.That(previousEncryptedData, Is.Not.EqualTo(reEncryptedData));
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            var decryptedMessage = await CryptoProcessor.DecryptString(reEncryptedData, password, upgradedIterations);
 | 
				
			||||||
 | 
					            Assert.That(decryptedMessage, Is.EqualTo(message));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var decryptedMessage2 = await CryptoProcessor.DecryptString(reEncryptedData, password, previousIterations);
 | 
				
			||||||
 | 
					                Assert.Fail("Should not be reached!");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (CryptographicException e)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Assert.That(true);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var decryptedMessage2 = await CryptoProcessor.DecryptString(previousEncryptedData, password, upgradedIterations);
 | 
				
			||||||
 | 
					                Assert.Fail("Should not be reached!");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (CryptographicException e)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Assert.That(true);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -9,7 +9,10 @@ namespace Encrypter
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    public static class CryptoProcessor
 | 
					    public static class CryptoProcessor
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private const int ITERATIONS = 6_000_000;
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// The number of iterations for the year 2020.
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        public const int ITERATIONS_YEAR_2020 = 6_000_000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// Encrypts a string by means of AES. The result gets base64 encoded.
 | 
					        /// Encrypts a string by means of AES. The result gets base64 encoded.
 | 
				
			||||||
@ -20,8 +23,9 @@ namespace Encrypter
 | 
				
			|||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        /// <param name="data">The UTF8 encoded string to encrypt.</param>
 | 
					        /// <param name="data">The UTF8 encoded string to encrypt.</param>
 | 
				
			||||||
        /// <param name="password">The password. Must consists of 6 chars or more.</param>
 | 
					        /// <param name="password">The password. Must consists of 6 chars or more.</param>
 | 
				
			||||||
 | 
					        /// <param name="iterations">The number of iterations to derive the key. Should not be adjusted. The default is secure for the current time.</param>
 | 
				
			||||||
        /// <returns>The base64 encoded and encrypted string. The string is ASCII encoding.</returns>
 | 
					        /// <returns>The base64 encoded and encrypted string. The string is ASCII encoding.</returns>
 | 
				
			||||||
        public static async Task<string> EncryptString(string data, string password)
 | 
					        public static async Task<string> EncryptString(string data, string password, int iterations = ITERATIONS_YEAR_2020)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (string.IsNullOrWhiteSpace(password) || password.Length < 6)
 | 
					            if (string.IsNullOrWhiteSpace(password) || password.Length < 6)
 | 
				
			||||||
                throw new CryptographicException("The password was empty or shorter than 6 characters.");
 | 
					                throw new CryptographicException("The password was empty or shorter than 6 characters.");
 | 
				
			||||||
@ -39,7 +43,7 @@ namespace Encrypter
 | 
				
			|||||||
            // The following operations take several seconds. Thus, using a task:
 | 
					            // The following operations take several seconds. Thus, using a task:
 | 
				
			||||||
            await Task.Run(() =>
 | 
					            await Task.Run(() =>
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                using var keyVectorObj = new Rfc2898DeriveBytes(password, saltBytes, ITERATIONS, HashAlgorithmName.SHA512);
 | 
					                using var keyVectorObj = new Rfc2898DeriveBytes(password, saltBytes, iterations, HashAlgorithmName.SHA512);
 | 
				
			||||||
                key = keyVectorObj.GetBytes(32); // the max valid key length = 256 bit = 32 bytes
 | 
					                key = keyVectorObj.GetBytes(32); // the max valid key length = 256 bit = 32 bytes
 | 
				
			||||||
                iv = keyVectorObj.GetBytes(16); // the only valid block size = 128 bit = 16 bytes
 | 
					                iv = keyVectorObj.GetBytes(16); // the only valid block size = 128 bit = 16 bytes
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
@ -93,8 +97,9 @@ namespace Encrypter
 | 
				
			|||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        /// <param name="base64EncodedAndEncryptedData">The base64 encoded and AES encrypted string. This string must be ASCII encoded.</param>
 | 
					        /// <param name="base64EncodedAndEncryptedData">The base64 encoded and AES encrypted string. This string must be ASCII encoded.</param>
 | 
				
			||||||
        /// <param name="password">The password. Must consists of 6 chars or more.</param>
 | 
					        /// <param name="password">The password. Must consists of 6 chars or more.</param>
 | 
				
			||||||
 | 
					        /// <param name="iterations">The number of iterations to derive the key. Should not be adjusted. The default is secure for the current time.</param>
 | 
				
			||||||
        /// <returns>The decrypted UTF8 encoded string.</returns>
 | 
					        /// <returns>The decrypted UTF8 encoded string.</returns>
 | 
				
			||||||
        public static async Task<string> DecryptString(string base64EncodedAndEncryptedData, string password)
 | 
					        public static async Task<string> DecryptString(string base64EncodedAndEncryptedData, string password, int iterations = ITERATIONS_YEAR_2020)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (string.IsNullOrWhiteSpace(password) || password.Length < 6)
 | 
					            if (string.IsNullOrWhiteSpace(password) || password.Length < 6)
 | 
				
			||||||
                throw new CryptographicException("The password was empty or shorter than 6 characters.");
 | 
					                throw new CryptographicException("The password was empty or shorter than 6 characters.");
 | 
				
			||||||
@ -121,7 +126,7 @@ namespace Encrypter
 | 
				
			|||||||
            // The following operations take several seconds. Thus, using a task:
 | 
					            // The following operations take several seconds. Thus, using a task:
 | 
				
			||||||
            await Task.Run(() =>
 | 
					            await Task.Run(() =>
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                using var keyVectorObj = new Rfc2898DeriveBytes(password, saltBytes, ITERATIONS, HashAlgorithmName.SHA512);
 | 
					                using var keyVectorObj = new Rfc2898DeriveBytes(password, saltBytes, iterations, HashAlgorithmName.SHA512);
 | 
				
			||||||
                key = keyVectorObj.GetBytes(32); // the max valid key length = 256 bit = 32 bytes
 | 
					                key = keyVectorObj.GetBytes(32); // the max valid key length = 256 bit = 32 bytes
 | 
				
			||||||
                iv = keyVectorObj.GetBytes(16); // the only valid block size = 128 bit = 16 bytes
 | 
					                iv = keyVectorObj.GetBytes(16); // the only valid block size = 128 bit = 16 bytes
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
@ -154,5 +159,22 @@ namespace Encrypter
 | 
				
			|||||||
            // it does not create another copy of the data. ToArray would create another copy of the data!
 | 
					            // it does not create another copy of the data. ToArray would create another copy of the data!
 | 
				
			||||||
            return Encoding.UTF8.GetString(decryptedData.GetBuffer()[..(int)decryptedData.Length]);
 | 
					            return Encoding.UTF8.GetString(decryptedData.GetBuffer()[..(int)decryptedData.Length]);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// Upgrades the encryption regarding the used iterations for the key.
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <param name="encryptedDataBeforeUpgrade">The encrypted data with the previous settings.</param>
 | 
				
			||||||
 | 
					        /// <param name="password">The password.</param>
 | 
				
			||||||
 | 
					        /// <param name="previousIterations">The previous number of iterations.</param>
 | 
				
			||||||
 | 
					        /// <param name="upgradedIterations">The upgraded number of iterations.</param>
 | 
				
			||||||
 | 
					        /// <returns>The re-encrypted data.</returns>
 | 
				
			||||||
 | 
					        public static async Task<string> UpgradeIterations(string encryptedDataBeforeUpgrade, string password, int previousIterations, int upgradedIterations)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            // Decrypt the data with the previous settings:
 | 
				
			||||||
 | 
					            var decryptedData = await CryptoProcessor.DecryptString(encryptedDataBeforeUpgrade, password, previousIterations);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Encrypt the data with the new settings:
 | 
				
			||||||
 | 
					            return await CryptoProcessor.EncryptString(decryptedData, password, upgradedIterations);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,12 @@
 | 
				
			|||||||
        <name>Encrypter</name>
 | 
					        <name>Encrypter</name>
 | 
				
			||||||
    </assembly>
 | 
					    </assembly>
 | 
				
			||||||
    <members>
 | 
					    <members>
 | 
				
			||||||
        <member name="M:Encrypter.CryptoProcessor.EncryptString(System.String,System.String)">
 | 
					        <member name="F:Encrypter.CryptoProcessor.ITERATIONS_YEAR_2020">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            The number of iterations for the year 2020.
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:Encrypter.CryptoProcessor.EncryptString(System.String,System.String,System.Int32)">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            Encrypts a string by means of AES. The result gets base64 encoded.
 | 
					            Encrypts a string by means of AES. The result gets base64 encoded.
 | 
				
			||||||
            Due to the necessary millions of SHA512 iterations, the methods runs at least several seconds in the year 2020 (approx. 5-7s).
 | 
					            Due to the necessary millions of SHA512 iterations, the methods runs at least several seconds in the year 2020 (approx. 5-7s).
 | 
				
			||||||
@ -14,9 +19,10 @@
 | 
				
			|||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
            <param name="data">The UTF8 encoded string to encrypt.</param>
 | 
					            <param name="data">The UTF8 encoded string to encrypt.</param>
 | 
				
			||||||
            <param name="password">The password. Must consists of 6 chars or more.</param>
 | 
					            <param name="password">The password. Must consists of 6 chars or more.</param>
 | 
				
			||||||
 | 
					            <param name="iterations">The number of iterations to derive the key. Should not be adjusted. The default is secure for the current time.</param>
 | 
				
			||||||
            <returns>The base64 encoded and encrypted string. The string is ASCII encoding.</returns>
 | 
					            <returns>The base64 encoded and encrypted string. The string is ASCII encoding.</returns>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:Encrypter.CryptoProcessor.DecryptString(System.String,System.String)">
 | 
					        <member name="M:Encrypter.CryptoProcessor.DecryptString(System.String,System.String,System.Int32)">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            Decrypts an base64 encoded and encrypted string. Due to the necessary millions of SHA512 iterations,
 | 
					            Decrypts an base64 encoded and encrypted string. Due to the necessary millions of SHA512 iterations,
 | 
				
			||||||
            the methods runs at least several seconds in the year 2020 (approx. 5-7s).
 | 
					            the methods runs at least several seconds in the year 2020 (approx. 5-7s).
 | 
				
			||||||
@ -26,8 +32,19 @@
 | 
				
			|||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
            <param name="base64EncodedAndEncryptedData">The base64 encoded and AES encrypted string. This string must be ASCII encoded.</param>
 | 
					            <param name="base64EncodedAndEncryptedData">The base64 encoded and AES encrypted string. This string must be ASCII encoded.</param>
 | 
				
			||||||
            <param name="password">The password. Must consists of 6 chars or more.</param>
 | 
					            <param name="password">The password. Must consists of 6 chars or more.</param>
 | 
				
			||||||
 | 
					            <param name="iterations">The number of iterations to derive the key. Should not be adjusted. The default is secure for the current time.</param>
 | 
				
			||||||
            <returns>The decrypted UTF8 encoded string.</returns>
 | 
					            <returns>The decrypted UTF8 encoded string.</returns>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:Encrypter.CryptoProcessor.UpgradeIterations(System.String,System.String,System.Int32,System.Int32)">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            Upgrades the encryption regarding the used iterations for the key.
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <param name="encryptedDataBeforeUpgrade">The encrypted data with the previous settings.</param>
 | 
				
			||||||
 | 
					            <param name="password">The password.</param>
 | 
				
			||||||
 | 
					            <param name="previousIterations">The previous number of iterations.</param>
 | 
				
			||||||
 | 
					            <param name="upgradedIterations">The upgraded number of iterations.</param>
 | 
				
			||||||
 | 
					            <returns>The re-encrypted data.</returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
        <member name="M:Encrypter.Extensions.Encrypt(System.String,System.String)">
 | 
					        <member name="M:Encrypter.Extensions.Encrypt(System.String,System.String)">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            Encrypts this string by means of AES. The result gets base64 encoded.
 | 
					            Encrypts this string by means of AES. The result gets base64 encoded.
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user