Как RFC2898DeriveBytes генерирует ключ AES?

Я видел некоторый код как

string password = "11111111";
byte[] salt = Encoding.ASCII.GetBytes("22222222");
Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(password, salt);
RijndaelAlg.Key = key.GetBytes(RijndaelAlg.KeySize / 8);

Я вижу, что ключ сгенерирован Rfc2898DeriveBytes с паролем и солью. Затем AES получает ключ GetBytes.

Но вопрос, что RFC2898DeriveBytes делает и что ключ. GetBytes (cb) делают? Кто-либо мог разработать это? Я не мог получить его из документации.

6
задан Paŭlo Ebermann 13 August 2011 в 01:16
поделиться

2 ответа

RFC2898 ссылается на спецификацию криптографии на основе пароля, опубликованную в сентябре 2000 года. Фактически, Rfc2898DeriveBytes принимает пароль и соль для генерации ключей. Используемый метод известен как PBKDF2 (Password Based Key Derivation Function #2) и определен в разделе 5.2 RFC2898. Из раздела 5.2:

PBKDF2 применяет псевдослучайные функции (см. приложение B.1 в качестве примера) для получения ключей. Длина производного ключа по существу не ограничена. (Однако максимальное эффективное пространство поиска производного ключа может быть ограничено структурой лежащей в основе псевдослучайной функции. Подробнее см. в Приложении В.1). Для новых применений рекомендуется использовать PBKDF2.

Подробнее см. RFC2898.

Что касается того, что делает Rfc2898DeriveBytes.GetBytes, то при каждом вызове он возвращает разный ключ; по сути, он просто многократно применяет PBKDF2 с одним и тем же паролем и солью, но также и счетчиком итераций.

Это описано в документе RFC, где PBKDF2 определяется как

PBKDF2 (P, S, c, dkLen)

, где P - пароль, S - соль, c - счетчик итераций, а dkLen - длина требуемого ключа.

В целом, RFC очень интересны и исторически очень важны. RFC 1149, как и RFC 2324, весьма важны.

.
12
ответ дан 8 December 2019 в 13:46
поделиться

Из рассмотрения реализации в рефлекторе:

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

public Rfc2898DeriveBytes(string password, int saltSize, int iterations)
{
    if (saltSize < 0)
    {
        throw new ArgumentOutOfRangeException("saltSize", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
    }
    byte[] data = new byte[saltSize];
    Utils.StaticRandomNumberGenerator.GetBytes(data);
    this.Salt = data;
    this.IterationCount = iterations;
    this.m_hmacsha1 = new HMACSHA1(new UTF8Encoding(false).GetBytes(password));
    this.Initialize();
}


public override byte[] GetBytes(int cb)
{
    if (cb <= 0)
    {
        throw new ArgumentOutOfRangeException("cb", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
    }
    byte[] dst = new byte[cb];
    int dstOffset = 0;
    int count = this.m_endIndex - this.m_startIndex;
    if (count > 0)
    {
        if (cb < count)
        {
            Buffer.InternalBlockCopy(this.m_buffer, this.m_startIndex, dst, 0, cb);
            this.m_startIndex += cb;
            return dst;
        }
        Buffer.InternalBlockCopy(this.m_buffer, this.m_startIndex, dst, 0, count);
        this.m_startIndex = this.m_endIndex = 0;
        dstOffset += count;
    }
    while (dstOffset < cb)
    {
        byte[] src = this.Func();
        int num3 = cb - dstOffset;
        if (num3 > 20)
        {
            Buffer.InternalBlockCopy(src, 0, dst, dstOffset, 20);
            dstOffset += 20;
        }
        else
        {
            Buffer.InternalBlockCopy(src, 0, dst, dstOffset, num3);
            dstOffset += num3;
            Buffer.InternalBlockCopy(src, num3, this.m_buffer, this.m_startIndex, 20 - num3);
            this.m_endIndex += 20 - num3;
            return dst;
        }
    }
    return dst;
}
5
ответ дан 8 December 2019 в 13:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: