public string Create(string password) { // Generate a random salt var salt = new byte[SaltBytes]; using (RandomNumberGenerator rng = RandomNumberGenerator.Create()) { rng.GetBytes(salt); } byte[] hash = Generate(password, salt, Pbkdf2Iterations, KeyDerivationPrf, HashBytes); // format: algorithm:iterations:hashSize:salt:hash string parts = KeyDerivationPrf.ToString("F") + ":" + Pbkdf2Iterations + ":" + hash.Length + ":" + Convert.ToBase64String(salt) + ":" + Convert.ToBase64String(hash); return(parts); }
/// <summary> /// Default constructor for Key Derivation Function Entry /// </summary> /// <param name="prf">KeyDerivationPrf to use</param> /// <param name="saltBytes">Salt byte array</param> /// <param name="iterationsCount">How many iterations</param> /// <param name="howManyBytesAreWanted">How many output bytes are wanted</param> /// <param name="id">Key identifier</param> public KeyDerivationFunctionEntry(KeyDerivationPrf prf, byte[] saltBytes, int iterationsCount, int howManyBytesAreWanted, string id) { // Block SHA-1 if (prf == KeyDerivationPrf.HMACSHA1) { throw new ArgumentException($"{nameof(prf)} cannot be SHA1 for security reasons"); } // Check salt bytes if (saltBytes == null) { throw new ArgumentNullException(nameof(saltBytes)); } else if (saltBytes.Length < 16) { throw new ArgumentException($"{nameof(saltBytes)} should be at least {saltMinLengthInBytes} bytes!"); } // Check iterations count if (iterationsCount < iterationsMin) { throw new ArgumentException($"{nameof(iterationsCount)} should be at least {iterationsMin}!"); } // Check ID if (string.IsNullOrEmpty(id)) { throw new ArgumentException($"{nameof(id)} should contain something!"); } this.algorithm = KDFAlgorithm.PBKDF2.ToString(); this.pseudorandomFunction = prf.ToString(); this.salt = saltBytes; this.iterations = iterationsCount; this.derivedKeyLengthInBytes = howManyBytesAreWanted; this.keyIdentifier = Encoding.UTF8.GetBytes(id); // Calculate new checksum this.CalculateAndUpdateChecksum(); }