c# - 使用 Rfc2898DeriveBytes 在 C# 中实现 PBKDF2

标签 c# pbkdf2 rfc2898

伙计们,我正在尝试在 C# 中实现一个创建 WPA 共享 key 的 PBKDF2 函数。我在这里找到了一些:http://msdn.microsoft.com/en-us/magazine/cc163913.aspx这似乎产生了一个有效的结果,但它太短了一个字节......而且 PSK 值错误。

为了测试输出,我将其与此进行比较:http://www.xs4all.nl/~rjoris/wpapsk.htmlhttp://anandam.name/pbkdf2/

我确实找到了一种方法来使用 C# 的内置库 Rfc2898DeriveBytes。使用这个,我得到一个有效的输出:

Rfc2898DeriveBytes k3 = new Rfc2898DeriveBytes(pwd1, salt1, 4096);
byte[] answers = k3.GetBytes(32);

现在,我使用 Rfc2898DeriveBytes 的一个限制是“salt”必须是 8 个八位字节长。如果它更短,则 Rfc2898DeriveBytes 会抛出异常。我在想我所要做的就是将盐(如果它更短)填充到 8 个字节,我会很好。但不是!我已经尝试了几乎所有填充与较短盐的组合,但我无法复制从上面这两个网站获得的结果。

所以底线是,这是否意味着 Rfc2898DeriveBytes 根本无法使用短于 8 字节的源盐?如果是这样,有谁知道我可以使用的任何 C# 代码来为 WPA 预共享 key 实现 PBKDF2?

最佳答案

这是一个不需要 8 字节盐的实现。

您可以按如下方式计算 WPA key :

Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(passphrase, Encoding.UTF8.GetBytes(name), 4096);
key = rfc2898.GetBytes(32);

public class Rfc2898DeriveBytes : DeriveBytes
    {
        const int BlockSize = 20;
        uint block;
        byte[] buffer;
        int endIndex;
        readonly HMACSHA1 hmacsha1;
        uint iterations;
        byte[] salt;
        int startIndex;

        public Rfc2898DeriveBytes(string password, int saltSize)
            : this(password, saltSize, 1000)
        {
        }

        public Rfc2898DeriveBytes(string password, byte[] salt)
            : this(password, salt, 1000)
        {
        }

        public Rfc2898DeriveBytes(string password, int saltSize, int iterations)
        {
            if (saltSize < 0)
            {
                throw new ArgumentOutOfRangeException("saltSize");
            }
            byte[] data = new byte[saltSize];
            new RNGCryptoServiceProvider().GetBytes(data);
            Salt = data;
            IterationCount = iterations;
            hmacsha1 = new HMACSHA1(new UTF8Encoding(false).GetBytes(password));
            Initialize();
        }

        public Rfc2898DeriveBytes(string password, byte[] salt, int iterations) : this(new UTF8Encoding(false).GetBytes(password), salt, iterations)
        {
        }

        public Rfc2898DeriveBytes(byte[] password, byte[] salt, int iterations)
        {
            Salt = salt;
            IterationCount = iterations;
            hmacsha1 = new HMACSHA1(password);
            Initialize();
        }

        static byte[] Int(uint i)
        {
            byte[] bytes = BitConverter.GetBytes(i);
            byte[] buffer2 = new byte[] {bytes[3], bytes[2], bytes[1], bytes[0]};
            if (!BitConverter.IsLittleEndian)
            {
                return bytes;
            }
            return buffer2;
        }


        byte[] DeriveKey()
        {
            byte[] inputBuffer = Int(block);
            hmacsha1.TransformBlock(salt, 0, salt.Length, salt, 0);
            hmacsha1.TransformFinalBlock(inputBuffer, 0, inputBuffer.Length);
            byte[] hash = hmacsha1.Hash;
            hmacsha1.Initialize();
            byte[] buffer3 = hash;
            for (int i = 2; i <= iterations; i++)
            {
                hash = hmacsha1.ComputeHash(hash);
                for (int j = 0; j < BlockSize; j++)
                {
                    buffer3[j] = (byte) (buffer3[j] ^ hash[j]);
                }
            }
            block++;
            return buffer3;
        }

        public override byte[] GetBytes(int bytesToGet)
        {
            if (bytesToGet <= 0)
            {
                throw new ArgumentOutOfRangeException("bytesToGet");
            }
            byte[] dst = new byte[bytesToGet];
            int dstOffset = 0;
            int count = endIndex - startIndex;
            if (count > 0)
            {
                if (bytesToGet < count)
                {
                    Buffer.BlockCopy(buffer, startIndex, dst, 0, bytesToGet);
                    startIndex += bytesToGet;
                    return dst;
                }
                Buffer.BlockCopy(buffer, startIndex, dst, 0, count);
                startIndex = endIndex = 0;
                dstOffset += count;
            }
            while (dstOffset < bytesToGet)
            {
                byte[] src = DeriveKey();
                int num3 = bytesToGet - dstOffset;
                if (num3 > BlockSize)
                {
                    Buffer.BlockCopy(src, 0, dst, dstOffset, BlockSize);
                    dstOffset += BlockSize;
                }
                else
                {
                    Buffer.BlockCopy(src, 0, dst, dstOffset, num3);
                    dstOffset += num3;
                    Buffer.BlockCopy(src, num3, buffer, startIndex, BlockSize - num3);
                    endIndex += BlockSize - num3;
                    return dst;
                }
            }
            return dst;
        }

        void Initialize()
        {
            if (buffer != null)
            {
                Array.Clear(buffer, 0, buffer.Length);
            }
            buffer = new byte[BlockSize];
            block = 1;
            startIndex = endIndex = 0;
        }

        public override void Reset()
        {
            Initialize();
        }

        public int IterationCount
        {
            get
            {
                return (int) iterations;
            }
            set
            {
                if (value <= 0)
                {
                    throw new ArgumentOutOfRangeException("value");
                }
                iterations = (uint) value;
                Initialize();
            }
        }

        public byte[] Salt
        {
            get
            {
                return (byte[]) salt.Clone();
            }
            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException("value");
                }
                salt = (byte[]) value.Clone();
                Initialize();
            }
        }
    }

关于c# - 使用 Rfc2898DeriveBytes 在 C# 中实现 PBKDF2,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1046599/

相关文章:

javascript - PBKDF2 Java 脚本实现与 Apache 许可证

c# - 为什么我需要使用 Rfc2898DeriveBytes 类(在 .NET 中)而不是直接使用密码作为 key 或 IV?

security - 公共(public)重写函数 GetBytes() 因为 Byte() 已过时

c# - 使用用户选择的维度创建数组

Java 使用 HMAC SHA1 实现 PBKDF2 每次按下按钮时都会返回不同的哈希值?

c# - Entity Framework 4.1 RTW Code First - POCO 一对多是否需要引用子实体和子实体主键?

php - 使用 PBKDF2 在 MySQL 数据库中存储密码和盐

asp-classic - 如何使用 AES 在 VBScript 中加密?

c# - 删除匿名事件处理程序

C# - 从 List3 中删除 List1 和 List2 中的项目时出现问题