【问题标题】:BCryptDeriveKeyPBKDF2 replacement for Windows Embedded Compact 2013BCryptDeriveKeyPBKDF2 替代 Windows Embedded Compact 2013
【发布时间】:2018-09-03 17:24:52
【问题描述】:

我必须为 Windows Embedded Compact 2013 使用 CNG (Cryptography API: Next Generation) 函数编译现有 C 代码。此代码使用 BCryptDeriveKeyPBKDF2,这在 Windows Embedded Compact 2013 下不可用。

这意味着我需要替换下面的函数来实现 RFC 2898 第 5.2 节中定义的 PBKDF2 密钥派生算法,但不使用 BCryptDeriveKeyPBKDF2

我发现了一些使用 CryptoAPI 函数 here 的 C 代码,但如果可能,我不想使用第二个已弃用的 API。

BOOL pbkdf2(
    PUCHAR pbPassword,  ULONG cbPassword,
    PUCHAR pbSalt, ULONG cbSalt,
    ULONGLONG cIterations,
    PUCHAR pbDerivedKey, ULONG cbDerivedKey)
{
    NTSTATUS status;
    BCRYPT_ALG_HANDLE hAlgorithm;

    status = BCryptOpenAlgorithmProvider(&hAlgorithm, BCRYPT_SHA1_ALGORITHM, NULL, BCRYPT_ALG_HANDLE_HMAC_FLAG);
    if (BCRYPT_SUCCESS(status))
    {
        status = BCryptDeriveKeyPBKDF2(hAlgorithm, pbPassword, cbPassword, pbSalt, cbSalt, cIterations, pbDerivedKey, cbDerivedKey, 0);
        BCryptCloseAlgorithmProvider(hAlgorithm, 0);
    }

    return BCRYPT_SUCCESS(status);
}

【问题讨论】:

    标签: cryptography windows-embedded-compact cng


    【解决方案1】:

    您可以使用 CNG 原语(例如 BCryptCreateHash)来实现算法。最重要的是在BCryptOpenAlgorithmProvider中使用标志BCRYPT_ALG_HANDLE_HMAC_FLAG:

    void pbkdf2()
    {
        BCRYPT_ALG_HANDLE hAlg = NULL;
        BCRYPT_HASH_HANDLE hHash = NULL;
        std::vector<BYTE> pass = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
        std::vector<BYTE> salt = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
        std::vector<BYTE> derived_key(32);
        std::vector<BYTE> dig(32);
        byte t[] = { 0x00, 0x00, 0x00, 0x01 };
        DWORD itcount = 10000;
    
        SECURITY_STATUS status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_SHA256_ALGORITHM,
            nullptr, BCRYPT_ALG_HANDLE_HMAC_FLAG);
        if (status != ERROR_SUCCESS) {
            goto Exit;
        }
    
        status = BCryptCreateHash(hAlg, &hHash, nullptr, 0, pass.data(), pass.size(), 0);
        if (status != ERROR_SUCCESS) {
            goto Exit;
        }
        status = BCryptHashData(hHash, salt.data(), salt.size(), 0);
        if (status != ERROR_SUCCESS) {
            goto Exit;
        }
        status = BCryptHashData(hHash, t, 4, 0);
        if (status != ERROR_SUCCESS) {
            goto Exit;
        }
        status = BCryptFinishHash(hHash, dig.data(), dig.size(), 0);
        if (status != ERROR_SUCCESS) {
            goto Exit;
        }
        derived_key = dig;
        BCryptDestroyHash(hHash);
    
        for (DWORD i = 1; i < itcount; ++i)
        {
            status = BCryptCreateHash(hAlg, &hHash, nullptr, 0, pass.data(), pass.size(), 0);
            if (status != ERROR_SUCCESS) {
                goto Exit;
            }
            status = BCryptHashData(hHash, dig.data(), dig.size(), 0);
            if (status != ERROR_SUCCESS) {
                goto Exit;
            }
            status = BCryptFinishHash(hHash, dig.data(), dig.size(), 0);
            if (status != ERROR_SUCCESS) {
                goto Exit;
            }
            BCryptDestroyHash(hHash);
            for (DWORD j = 0; j < dig.size(); ++j) {
                derived_key[j] ^= dig[j];
            }
        }
    
    
    Exit:
        if (hHash) {
            BCryptDestroyHash(hHash);
        }
        if (hAlg) {
            BCryptCloseAlgorithmProvider(hAlg, 0);
        }
        return;
    }
    

    编辑:阐明 t[] 的含义。
    根据RFC(5.2):

    对于派生密钥的每个块,应用定义的函数 F 低于密码 P、盐 S、迭代次数 c 和 计算区块的区块索引:

                   T_1 = F (P, S, c, 1) ,
                   T_2 = F (P, S, c, 2) ,
                   ...
                   T_l = F (P, S, c, l) ,
    
         where the function F is defined as the exclusive-or sum of the
         first c iterates of the underlying pseudorandom function PRF
         applied to the password P and the concatenation of the salt S
         and the block index i:  F (P, S, c, i) = U_1 \xor U_2 \xor ... \xor U_c
    
         where
    
                   U_1 = PRF (P, S || INT (i)) ,
                   U_2 = PRF (P, U_1) ,
                   ...
                   U_c = PRF (P, U_{c-1}) .
    
         Here, INT (i) is a four-octet encoding of the integer i, most
         significant octet first.
    

    所以,在我的代码中 t[] - 是整数 1 的四字节编码(对于第一次迭代),最重要的字节在前。

    【讨论】:

    • plstryagain,感谢您的回答。您的代码中 t[] 的目的是什么?我在上面编辑了我的帖子以使事情更清楚
    • 再次感谢您的帮助,我将您的答案标记为有用,但不幸的是,它不算数,因为我的声誉很低。转换现有代码对我来说更容易(请参阅下面的答案),因为我是一个关于密码学的新手。
    【解决方案2】:

    我采用了this code,将已弃用的 wincrypt 调用转换为新的CNG API,对其进行了重构并删除了我不需要的东西。

    虽然我不明白代码在做什么,但似乎它产生的结果与我的问题中使用 BCryptDeriveKeyPBKDF2 的函数相同。

    #define NOCRYPT
    
    #include <windows.h>
    #include <bcrypt.h>
    #include <math.h>
    #include <assert.h>
    
    #define DIGEST_SIZE 20
    #define BLOCK_SIZE 64
    
    typedef struct
    {
        BCRYPT_ALG_HANDLE hAlgorithm;
        BCRYPT_HASH_HANDLE hInnerHash;
        BCRYPT_HASH_HANDLE hOuterHash;
    } PRF_CTX;
    
    static void hmacFree(PRF_CTX* pContext)
    {
        if (pContext->hOuterHash) BCryptDestroyHash(pContext->hOuterHash);
        if (pContext->hInnerHash) BCryptDestroyHash(pContext->hInnerHash);
        if (pContext->hAlgorithm) BCryptCloseAlgorithmProvider(pContext->hAlgorithm, 0);
    }
    
    static BOOL hmacPrecomputeDigest(BCRYPT_HASH_HANDLE hHash, PUCHAR pbPassword, DWORD cbPassword, BYTE mask)
    {
        BYTE buffer[BLOCK_SIZE];
        DWORD i;
        assert(cbPassword <= BLOCK_SIZE);
    
        memset (buffer, mask, sizeof(buffer));
    
        for (i = 0; i < cbPassword; ++i)
        {
            buffer[i] = (char) (pbPassword[i] ^ mask);
        }
    
        return BCRYPT_SUCCESS(BCryptHashData(hHash, buffer, sizeof(buffer), 0));
    }
    
    static BOOL hmacInit(PRF_CTX* pContext, PUCHAR pbPassword, DWORD cbPassword)
    {
        BCRYPT_HASH_HANDLE hHash = NULL;
        BOOL bStatus = FALSE;
        BYTE key[DIGEST_SIZE];
    
        if (!BCRYPT_SUCCESS(BCryptOpenAlgorithmProvider(&pContext->hAlgorithm, BCRYPT_SHA1_ALGORITHM, NULL, 0)) ||
            !BCRYPT_SUCCESS(BCryptCreateHash(pContext->hAlgorithm, &pContext->hInnerHash, NULL, 0, NULL, 0, 0)) ||
            !BCRYPT_SUCCESS(BCryptCreateHash(pContext->hAlgorithm, &pContext->hOuterHash, NULL, 0, NULL, 0, 0)))
        {
            goto hmacInit_end;
        }
    
        if (cbPassword > BLOCK_SIZE)
        {
            ULONG cbResult;
            if (!BCRYPT_SUCCESS(BCryptCreateHash(pContext->hAlgorithm, &hHash, NULL, 0, NULL, 0, 0)) ||
                !BCRYPT_SUCCESS(BCryptHashData(hHash, pbPassword, cbPassword, 0)) ||
                !BCRYPT_SUCCESS(BCryptGetProperty(hHash, BCRYPT_HASH_LENGTH, (PUCHAR)&cbPassword, sizeof(cbPassword), &cbResult, 0)) ||
                !BCRYPT_SUCCESS(BCryptFinishHash(hHash, key, cbPassword, 0)))
            {
                goto hmacInit_end;
            }
    
            pbPassword = key;
        }
    
        bStatus =
            hmacPrecomputeDigest(pContext->hInnerHash, pbPassword, cbPassword, 0x36) &&
            hmacPrecomputeDigest(pContext->hOuterHash, pbPassword, cbPassword, 0x5C);
    
    hmacInit_end:
    
        if (hHash) BCryptDestroyHash(hHash);
        if (bStatus == FALSE) hmacFree(pContext);
    
        return bStatus;
    }
    
    static BOOL hmacCalculateInternal(BCRYPT_HASH_HANDLE hHashTemplate, PUCHAR pbData, DWORD cbData, PUCHAR pbOutput, DWORD cbOutput)
    {
        BOOL success = FALSE;
        BCRYPT_HASH_HANDLE hHash = NULL;
    
        if (BCRYPT_SUCCESS(BCryptDuplicateHash(hHashTemplate, &hHash, NULL, 0, 0)))
        {
            success =
                BCRYPT_SUCCESS(BCryptHashData(hHash, pbData, cbData, 0)) &&
                BCRYPT_SUCCESS(BCryptFinishHash(hHash, pbOutput, cbOutput, 0));
    
            BCryptDestroyHash(hHash);
        }
    
        return success;
    }
    
    static BOOL hmacCalculate(PRF_CTX* pContext, PUCHAR pbData, DWORD cbData, PUCHAR pbDigest)
    {
        return
            hmacCalculateInternal(pContext->hInnerHash, pbData, cbData, pbDigest, DIGEST_SIZE) &&
            hmacCalculateInternal(pContext->hOuterHash, pbDigest, DIGEST_SIZE, pbDigest, DIGEST_SIZE);
    }
    
    static void xor(LPBYTE ptr1, LPBYTE ptr2, DWORD dwLen)
    {
        while (dwLen--)
            *ptr1++ ^= *ptr2++;
    }
    
    BOOL pbkdf2(
        PUCHAR pbPassword, ULONG cbPassword,
        PUCHAR pbSalt, ULONG cbSalt,
        DWORD cIterations,
        PUCHAR pbDerivedKey, ULONG cbDerivedKey)
    {
        BOOL bStatus = FALSE;
        DWORD l, r, dwULen, i, j;
        BYTE Ti[DIGEST_SIZE];
        BYTE V[DIGEST_SIZE];
        LPBYTE U = malloc(max((cbSalt + 4), DIGEST_SIZE));
        PRF_CTX prfCtx = { 0 };
    
        assert(pbPassword != NULL && cbPassword != 0 && pbSalt != NULL && cbSalt != 0);
        assert(cIterations > 0 && pbDerivedKey > 0 && cbDerivedKey > 0);
    
        if (!hmacInit(&prfCtx, pbPassword, cbPassword))
        {
            goto PBKDF2_end;
        }
    
        l = (DWORD) ceil((double) cbDerivedKey / (double) DIGEST_SIZE);
        r = cbDerivedKey - (l - 1) * DIGEST_SIZE;
    
        for (i = 1; i <= l; i++)
        {
            ZeroMemory(Ti, DIGEST_SIZE);
            for (j = 0; j < cIterations; j++)
            {
                if (j == 0)
                {
                    // construct first input for PRF
                    memcpy(U, pbSalt, cbSalt);
                    U[cbSalt] = (BYTE) ((i & 0xFF000000) >> 24);
                    U[cbSalt + 1] = (BYTE) ((i & 0x00FF0000) >> 16);
                    U[cbSalt + 2] = (BYTE) ((i & 0x0000FF00) >> 8);
                    U[cbSalt + 3] = (BYTE) ((i & 0x000000FF));
                    dwULen = cbSalt + 4;
                }
                else
                {
                    memcpy(U, V, DIGEST_SIZE);
                    dwULen = DIGEST_SIZE;
                }
    
                if (!hmacCalculate(&prfCtx, U, dwULen, V))
                {
                    goto PBKDF2_end;
                }
    
                xor(Ti, V, DIGEST_SIZE);
            }
    
            if (i != l)
            {
                memcpy(&pbDerivedKey[(i-1) * DIGEST_SIZE], Ti, DIGEST_SIZE);
            }
            else
            {
                // Take only the first r bytes
                memcpy(&pbDerivedKey[(i-1) * DIGEST_SIZE], Ti, r);
            }
        }
    
        bStatus = TRUE;
    
    PBKDF2_end:
    
        hmacFree(&prfCtx);
        free(U);
        return bStatus;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-26
      • 1970-01-01
      相关资源
      最近更新 更多