// Tests are taken from: // https://github.com/Anti-weakpasswords/PBKDF2-Test-Vectors/releases // found https://stackoverflow.com/questions/5130513/pbkdf2-hmac-sha2-test-vectors public static IEnumerable <object[]> GetKDFCases() { foreach (var item in Helper.ReadResource <JArray>("PBKDF2TestData")) { foreach (var item2 in item["Data"]) { // Set a new HMAC instance for each test (avoids ObjectDisposedException) IHmacFunction hmac = (item["HmacName"].ToString()) switch { "HMACSHA256" => new HmacSha256(), "HMACSHA512" => new HmacSha512(), _ => throw new Exception("Test data file contains an undefined HMAC name."), }; byte[] pass = Encoding.UTF8.GetBytes(item2[0].ToString()); byte[] salt = Encoding.UTF8.GetBytes(item2[1].ToString()); int iter = (int)item2[2]; // The following condition skips 68 out of 128 test vectors that have huge iteratio values // since they are very time consuming (~17min in debug mode) to avoid repeating them // every time all tests are run. Change this if anything in the class changed or // if you want to perform these test for any reason. if (iter > 5000) { continue; } int len = (int)item2[3]; byte[] derivedBytes = Helper.HexToBytes(item2[4].ToString()); yield return(new object[] { hmac, iter, pass, salt, len, derivedBytes }); } } }
/// <summary> /// Releases all resources used by the current instance of the <see cref="PBKDF2"/> class. /// </summary> public void Dispose() { if (!isDisposed) { if (!(hmacFunc is null)) { hmacFunc.Dispose(); } hmacFunc = null; isDisposed = true; } }
/// <summary> /// Initializes a new instance of <see cref="PBKDF2"/> with the given parameters. /// </summary> /// <exception cref="ArgumentNullException"/> /// <exception cref="ArgumentOutOfRangeException"/> /// <param name="iteration"> /// Iteration (c) /// <para/>* RFC-8018 recommends 1,000 as minimum and 10,000,000 for non-performance critical cases /// </param> /// <param name="hmac">HMAC-SHA function (PRF)</param> public PBKDF2(int iteration, IHmacFunction hmac) { if (iteration <= 0) { throw new ArgumentOutOfRangeException(nameof(iteration), "Iteration can not be negative or zero!"); } if (hmac is null) { throw new ArgumentNullException(nameof(hmac), "HMAC function can not be null."); } this.iteration = iteration; hmacFunc = hmac; }
private bool isDisposed = false; // To detect redundant calls protected virtual void Dispose(bool disposing) { if (!isDisposed) { if (disposing) { if (hmacFunc != null) { hmacFunc.Dispose(); } hmacFunc = null; } isDisposed = true; } }
public void GetBytesTest(IHmacFunction hmac, int iter, byte[] pass, byte[] salt, int len, byte[] expected) { using PBKDF2 kdf = new PBKDF2(iter, hmac); byte[] actual = kdf.GetBytes(pass, salt, len); Assert.Equal(expected, actual); }