Search code examples
c++hashcrypto++pbkdf2

Constant time password digest compares using Crypto++


I'm writing a program which hashes passwords with the pbkdf2 method using cryptopp.

I have problems with validating the passwords. I have tried to compare the output in "length-constant" time but it always fails and returns false.

// a and b are std strings containing the output of the DeriveKey function

unsigned diff = a.length() ^ b.length();
for(unsigned i = 0; i < a.length() && i < b.length(); i++)
{
      diff |= (unsigned)a[i] ^ (unsigned)b[i];
}

bool equal = diff == 0;

Is using "slow equals" even the right way to validate pbkdf2 passwords? I am a bit confused on this.


Solution

  • I'm writing a program which hashes passwords with the pbkdf2 method using cryptopp.

    You linked to the Crypto++ main page, and not a your particular use of PBKDF. Here's some code just in case (it uses the IETF test vectors from RFC 6070):

    int main(int argc, char* argv[])
    {
        byte password[] ="password";
        size_t plen = strlen((const char*)password);
    
        byte salt[] = "salt";
        size_t slen = strlen((const char*)salt);
    
        int c = 1;
        byte derived[20];
    
        PKCS5_PBKDF2_HMAC<CryptoPP::SHA1> pbkdf2;
        pbkdf2.DeriveKey(derived, sizeof(derived), 0, password, plen, salt, slen, c);
    
        string result;
        HexEncoder encoder(new StringSink(result));
    
        encoder.Put(derived, sizeof(derived));
        encoder.MessageEnd();
    
        cout << "Derived: " << result << endl;
    
        return 0;
    }
    

    I have tried to compare the output in "length-constant" time but it always fails and returns false.

    Crypto++ has a constant time compare built in. Use VerifyBufsEqual from misc.h. The source is available in misc.cpp.

    $ cd cryptopp
    $ grep -R VerifyBufsEqual *
    cryptlib.cpp:   return VerifyBufsEqual(digest, digestIn, digestLength);
    default.cpp:    if (!VerifyBufsEqual(check, check+BLOCKSIZE, BLOCKSIZE))
    fipstest.cpp:   if (!VerifyBufsEqual(expectedModuleMac, actualMac, macSize))
    fipstest.cpp:   if (VerifyBufsEqual(expectedModuleMac, actualMac, macSize))
    misc.cpp:bool VerifyBufsEqual(const byte *buf, const byte *mask, size_t count)
    misc.h:CRYPTOPP_DLL bool CRYPTOPP_API VerifyBufsEqual(const byte *buf1, const byte *buf2, size_t count);
    pssr.cpp:   valid = VerifyBufsEqual(representative + representativeByteLength - u, hashIdentifier.first, hashIdentifier.second) && valid;
    pubkey.cpp: return VerifyBufsEqual(representative, computedRepresentative, computedRepresentative.size());
    secblock.h:     return m_size == t.m_size && VerifyBufsEqual(m_ptr, t.m_ptr, m_size*sizeof(T));
    

    What I'm not clear about: VerifyBufsEqual is predicated upon buffers of equal lengths. I'm not sure if its OK to overlook the "not-equal length" case.


    There's also a question on the Information Stack Exchange that may be relevant: Timing attacks on password hashes. But I'm not certain if/how it generalizes to arbitrary buffer compares.

    The question piqued my interest in an answer to the general problem (the question has always been there): Constant time compares when array sizes are not equal?. That should tell us if we have the proper tools in VerifyBufsEqual (Crypto++), CRYPTO_memcmp (OpenSSL), etc.