C ++ Crypto: Część 3-pbkdf2
Rozglądanie się za nowoczesnymi bibliotekami Crypto.
Nie udało się znaleźć nic dobrego.
Wiem, że prawdopodobnie zrobiłem to wszystko źle, więc pracuj ze mną tutaj. Będą cztery różne przeglądy czterech struktur, które wzajemnie się uzupełniają:
- Haszowanie
- Hashed Key
- Klucz hasła
- Odpowiedź na solone wyzwanie
Ta recenzja dotyczy implementacji implementacji pbkdf2. Jest to sposób korzystania z HMAC, który pozwala na stopniowe zwiększanie kosztów tworzenia skrótu w przypadku awarii. Chodzi o to, że możesz spowolnić ataki, utrudniając wiele domysłów.
Struktury danych i implementacja przedstawione w tych pytaniach są oparte na RFC2104 i tym poście w codeproject .
Przykład użycia
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
Odpowiedzi
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 longan inti a std::size_twszyscy weszli do baru…” czyż oni wszyscy nie mogli być std::size_t?
Ponadto zastępowanie loopzmiennej jest niepotrzebnie mylące.
std::copy(std::begin(tmp), std::end(tmp), std::begin(digest));
Wydaje mi się, że może to być po prostu digest = tmp;odpowiedni operator przypisania.
salt + "\x00\x00\x00\x01"s
Czy może to być nazwana stała (lub nawet nazwana funkcja)? A może dodaj komentarz, aby wyjaśnić, dlaczego tak jest.
digest[loop] = digest[loop] ^ tmp[loop];
Nitpick: przydałby się ^=
Być może dane wyjściowe powinny być wartością zwracaną, a nie zapisaną w referencji?
Nie wiem wystarczająco dużo o kryptografii / bezpieczeństwie, aby ocenić algorytm / aspekty bezpieczeństwa.