C ++ Crypto: Parte 3-pbkdf2

Aug 26 2020

Procurando por bibliotecas Crypto modernas.
Não foi possível encontrar nada de bom.

Eu sei que provavelmente fiz tudo errado, então trabalhe comigo aqui. Haverá quatro análises diferentes para quatro estruturas construídas umas sobre as outras:

  1. Hashing
  2. Hashed Key
  3. Chave de senha
  4. Salted Challenge Response

Esta revisão é para uma implementação da implementação do pbkdf2. Essa é uma maneira de usar o HMAC que permite tornar cada vez mais caro para criar o hash em falhas. A ideia é que você pode desacelerar os ataques tornando mais difícil fazer muitas suposições.

As estruturas de dados e a implementação apresentadas nessas questões são baseadas na RFC2104 e nesta postagem no codeproject .

Exemplo de uso

Digest<Pbkdf2<HMac<Sha1>>>    digest;
Pbkdf2<HMac<Sha1>>            pbkdf2;

pbkdf2.hash("The password", "A Salt", 2048, digest);

pbkdf2.h

#ifndef THORS_ANVIL_CRYPTO_PBKDF2_H
#define THORS_ANVIL_CRYPTO_PBKDF2_H

#include "hmac.h"
#include <string>

// RFC-2898 PKCS #5: Password-Based Cryptography Specification Version 2.0

namespace ThorsAnvil::Crypto
{

// Look in hmac.h for good examples of PRF
// ThorsAnvil::Crypto::HMac
template<typename PRF>
struct Pbkdf2
{
    static constexpr std::size_t digestSize = PRF::digestSize;
    using DigestStore    = typename PRF::DigestStore;

    void hash(std::string const& password, std::string const& salt, long iter, DigestStore& digest)
    {
#pragma vera-pushoff
        using namespace std::string_literals;
#pragma vera-pop
        PRF             prf;
        DigestStore     tmp;

        prf.hash(password, salt + "\x00\x00\x00\x01"s, tmp);
        std::copy(std::begin(tmp), std::end(tmp), std::begin(digest));

        for (int loop = 1; loop < iter; ++loop)
        {
            prf.hash(password, tmp.view(), tmp);
            for (std::size_t loop = 0; loop < digestSize; ++loop)
            {
                digest[loop] = digest[loop] ^ tmp[loop];
            }
        }
    }
};

}

#endif

Respostas

1 user673679 Nov 16 2020 at 03:47
void hash(std::string const& password, std::string const& salt, long iter, DigestStore& digest)
...
for (int loop = 1; loop < iter; ++loop)
        ...
        for (std::size_t loop = 0; loop < digestSize; ++loop)

"A longuma inte std::size_ttudo andou em um bar ..." não poderia todos eles ser std::size_t?

Além disso, substituir a loopvariável é desnecessariamente confuso.


    std::copy(std::begin(tmp), std::end(tmp), std::begin(digest));

Eu sinto que isso poderia ser apenas digest = tmp;com um operador de atribuição apropriado.


salt + "\x00\x00\x00\x01"s

Poderia ser uma constante nomeada (ou mesmo uma função nomeada)? Ou talvez adicione um comentário para explicar por que isso está aqui.


            digest[loop] = digest[loop] ^ tmp[loop];

Nitpick: poderia usar ^=


Talvez a saída deva ser um valor de retorno, não escrito em uma referência?


Não sei o suficiente sobre criptografia / segurança para avaliar os aspectos de algoritmo / segurança disso.