Search code examples
c#c++encryptionwindows-runtimepbkdf2

Using PBKDF2 encryption in a Metro (WinRT) application


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?


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
    }