Question

I need to derive a key from a salted password using PBKDF2 encryption in a C# & C++ Metro (WinRT) application. What should I use to derive a key using PBKDF2 (like OpenSSL's PKCS5_PBKDF2_HMAC_SHA1 call does) on Metro? Is there a version of OpenSSL that builds on WinRT? (I've read that it only builds on Windows for the desktop platform.) Or is there some other solution I should use?

BTW I could call the function from either C# or C++, so either is fine. Any advice would be much appreciated!

EDIT: I just found a .NET function named "Rfc2898DeriveBytes" -- details here. If I'm reading that correctly it will do the same thing as OpenSSL's PKCS5_PBKDF2_HMAC_SHA1 call -- is that correct?

EDIT #2: Unfortunately it looks like I can't use Rfc2898DeriveBytes after all in my Windows 8.1 Metro app because despite what the Microsoft documentation for Rfc2898DeriveBytes says, that API method does not exist in the 'Windows.Security.Cryptography' namespace when building a Windows 8.1 app. Is there anything else I can use?

Was it helpful?

Solution

After much digging around I finally found this link. Here is what I ended up doing in my Metro app:

private static bool GetPBKDFDerivedKey(string password, 
    byte[] salt,                    // length = 32 bytes (256 bits)
    out byte[] encryptionKeyOut)    // length = 32 bytes (256 bits)
{            
    IBuffer saltBuffer = CryptographicBuffer.CreateFromByteArray(salt);
    KeyDerivationParameters kdfParameters = KeyDerivationParameters.BuildForPbkdf2(saltBuffer, 10000);  // 10000 iterations

    // Get a KDF provider for PBKDF2 and hash the source password to a Cryptographic Key using the SHA256 algorithm.
    // The generated key for the SHA256 algorithm is 256 bits (32 bytes) in length.
    KeyDerivationAlgorithmProvider kdf = KeyDerivationAlgorithmProvider.OpenAlgorithm(KeyDerivationAlgorithmNames.Pbkdf2Sha256);
    IBuffer passwordBuffer = CryptographicBuffer.ConvertStringToBinary(password, BinaryStringEncoding.Utf8);
    CryptographicKey passwordSourceKey = kdf.CreateKey(passwordBuffer);

    // Generate key material from the source password, salt, and iteration count
    const int keySize = 256 / 8;  // 256 bits = 32 bytes  
    IBuffer key = CryptographicEngine.DeriveKeyMaterial(passwordSourceKey, kdfParameters, keySize);

    // send the generated key back to the caller
    CryptographicBuffer.CopyToByteArray(key, out encryptionKeyOut);

    return true;  // success
}

OTHER TIPS

You can use Rfc2898DeriveBytes as the RFC actually defines PBKDF2. Note that you need to make sure you use the same character encoding, salt size and number of rounds to be compatible. Normally SHA1 is used as underlying hash function (which is fine) but beware that PBKDF2 may also use other hash functions. Rfc2898DeriveBytes utilizes SHA1 for the HMAC functionality.

Note that Rfc2898DeriveBytes utilizes UTF-8; this is not documented (even after multiple requests) by Mickeysoft. You can use byte arrays instead if you are unsure about the encoding on both platforms. You should especially be aware of this if you allow characters out of the US ASCII range.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top