#region Copyright 2010 by Roger Knapp, Licensed under the Apache License, Version 2.0 /* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #endregion using System; using System.Collections.Generic; using System.Security.Cryptography; using System.Reflection; namespace CSharpTest.Net.Crypto { /// /// Provided an implementation of Rfc2898DeriveBytes accessable via the IPasswordDerivedBytes /// interface. One primary difference in GetBytes() ensures that the number of bytes /// generated are always rounded to hash size, thus GetBytes(4) + GetBytes(4) != GetBytes(8) /// public class PBKDF2 : System.Security.Cryptography.Rfc2898DeriveBytes, IPasswordDerivedBytes { /// /// Constructs the Rfc2898DeriveBytes implementation. /// public PBKDF2(byte[] password, Salt salt, int iterations) : base(password, salt.ToArray(), iterations) { } /// /// Overloaded, The base implementation is broken for length > 20, further the RFC doesnt /// support lenght > 20 and stipulates that the operation should fail. /// public override byte[] GetBytes(int cb) { byte[] buffer = new byte[cb]; for (int i = 0; i < cb; i += 20) { int step = Math.Min(20, cb - i); Array.Copy(base.GetBytes(20), 0, buffer, i, step); } return buffer; } #if NET20 || NET35 // NOTE: .NET 4.0 finally implemented /// /// Disposes of the object /// public void Dispose() { base.Salt = new byte[8]; base.IterationCount = 1; //The base doesn't clear the key'd hash, which contains the password in clear text when < 20 bytes FieldInfo f_hmacsha1 = GetType().BaseType.GetField("m_hmacsha1", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField); if (f_hmacsha1 != null) { HMACSHA1 m_hmacsha1 = f_hmacsha1.GetValue(this) as HMACSHA1; m_hmacsha1.Clear(); } } #endif } }