diff --git a/src/KeyKeeper/PasswordStore/Crypto/KeyDerivation/AesKdf.cs b/src/KeyKeeper/PasswordStore/Crypto/KeyDerivation/AesKdf.cs new file mode 100644 index 0000000..64ce007 --- /dev/null +++ b/src/KeyKeeper/PasswordStore/Crypto/KeyDerivation/AesKdf.cs @@ -0,0 +1,42 @@ +using System; +using System.Security.Cryptography; + +namespace KeyKeeper.PasswordStore.Crypto.KeyDerivation; + +public class AesKdf : MasterKeyDerivationFunction +{ + public const int MIN_ROUNDS = 10; + public const int MAX_ROUNDS = 25_000_000; + public const int SEED_LENGTH = 32; + + private int rounds; + private byte[] seed; + + public AesKdf(int rounds, byte[] seed) + { + if (rounds < MIN_ROUNDS || rounds > MAX_ROUNDS) + throw new ArgumentOutOfRangeException(nameof(rounds)); + if (seed.Length != SEED_LENGTH) + throw new ArgumentException("seed length must be " + SEED_LENGTH); + this.rounds = rounds; + this.seed = seed; + } + + public override byte[] Derive(CompositeKey source, int keySizeBytes) + { + if (keySizeBytes > SEED_LENGTH) + throw new ArgumentOutOfRangeException(nameof(keySizeBytes)); + + byte[] key = source.Hash()[..SEED_LENGTH]; + byte[] nextKey = new byte[SEED_LENGTH]; + Aes cipher = Aes.Create(); + cipher.KeySize = SEED_LENGTH; + for (int i = 0; i < rounds; ++i) + { + cipher.Key = key; + cipher.EncryptEcb(seed, nextKey, PaddingMode.None); + (nextKey, key) = (key, nextKey); + } + return key; + } +} diff --git a/src/KeyKeeper/PasswordStore/Crypto/KeyDerivation/MasterKeyDerivationFunction.cs b/src/KeyKeeper/PasswordStore/Crypto/KeyDerivation/MasterKeyDerivationFunction.cs new file mode 100644 index 0000000..6118e25 --- /dev/null +++ b/src/KeyKeeper/PasswordStore/Crypto/KeyDerivation/MasterKeyDerivationFunction.cs @@ -0,0 +1,6 @@ +namespace KeyKeeper.PasswordStore.Crypto; + +public abstract class MasterKeyDerivationFunction +{ + public abstract byte[] Derive(CompositeKey source, int keySizeBytes); +} diff --git a/src/KeyKeeper/PasswordStore/FileFormatConstants.cs b/src/KeyKeeper/PasswordStore/FileFormatConstants.cs index 6f755f7..c45e49e 100644 --- a/src/KeyKeeper/PasswordStore/FileFormatConstants.cs +++ b/src/KeyKeeper/PasswordStore/FileFormatConstants.cs @@ -1,4 +1,5 @@ using System.Security.Cryptography; +using KeyKeeper.PasswordStore.Crypto.KeyDerivation; namespace KeyKeeper.PasswordStore; @@ -6,8 +7,8 @@ static class FileFormatConstants { public const int MIN_MASTER_SALT_LEN = 8; public const int MAX_MASTER_SALT_LEN = 40; - public const int MIN_AESKDF_ROUNDS = 10; - public const int MAX_AESKDF_ROUNDS = 65536; + public const int MIN_AESKDF_ROUNDS = AesKdf.MIN_ROUNDS; + public const int MAX_AESKDF_ROUNDS = AesKdf.MAX_ROUNDS; public const byte ENCRYPT_ALGO_AES = 14; public const byte KDF_TYPE_AESKDF = 195; public const int HMAC_SIZE = HMACSHA3_512.HashSizeInBytes;