VirtualBox

Changeset 102375 in vbox for trunk/src/VBox/Runtime


Ignore:
Timestamp:
Nov 29, 2023 10:58:18 AM (12 months ago)
Author:
vboxsync
Message:

IPRT/crypto: Implemented handing-in crypt password strings as the salt into RTCrShaCrypt256/512(). This approach is used by many *crypt implementations -- it allows feeding the user-provided password and the crypted password from "the password file" to the function. If it returns the same crypted password then the user-provided password must be the correct one.Extended testcases. bugref:10551

Location:
trunk/src/VBox/Runtime
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/common/crypto/shacrypt.cpp

    r102372 r102375  
    4848
    4949
     50/** The digest prefix for SHAcrypt256 strings. */
     51#define RT_SHACRYPT_DIGEST_PREFIX_256_STR       "$5$"
     52/** The digest prefix for SHAcrypt512 strings. */
     53#define RT_SHACRYPT_DIGEST_PREFIX_512_STR       "$6$"
     54
    5055
    5156RTR3DECL(int) RTCrShaCryptGenerateSalt(char *pszSalt, size_t cchSalt)
     
    6368
    6469
     70/**
     71 * Extracts the salt from a given string.
     72 *
     73 * @returns Pointer to the salt string, or NULL if not found / invalid.
     74 * @param   pszStr              String to extract salt from.
     75 * @param   pcchSalt            Where to reutrn the extracted salt length (in characters).
     76 */
     77static const char *rtCrShaCryptExtractSalt(const char *pszStr, size_t *pcchSalt)
     78{
     79    size_t cchSalt = strlen(pszStr);
     80
     81    /* Searches for a known SHAcrypt string prefix and skips it. */
     82#define BEGINS_WITH(a_szMatch) \
     83        (cchSalt >= sizeof(a_szMatch) - 1U && memcmp(pszStr, a_szMatch, sizeof(a_szMatch) - 1U) == 0)
     84    if (BEGINS_WITH(RT_SHACRYPT_DIGEST_PREFIX_256_STR))
     85    {
     86        cchSalt -= sizeof(RT_SHACRYPT_DIGEST_PREFIX_256_STR) - 1;
     87        pszStr  += sizeof(RT_SHACRYPT_DIGEST_PREFIX_256_STR) - 1;
     88    }
     89    else if (BEGINS_WITH(RT_SHACRYPT_DIGEST_PREFIX_512_STR))
     90    {
     91        cchSalt -= sizeof(RT_SHACRYPT_DIGEST_PREFIX_512_STR) - 1;
     92        pszStr  += sizeof(RT_SHACRYPT_DIGEST_PREFIX_512_STR) - 1;
     93    }
     94#undef BEGINS_WITH
     95
     96    /* Search for the end of the salt string, denoted by a '$'. */
     97    size_t cchLen = 0;
     98    while (   cchLen < cchSalt
     99           && pszStr[cchLen] != '$')
     100        cchLen++;
     101
     102    AssertMsgReturn(cchLen >= RT_SHACRYPT_MIN_SALT_LEN && cchLen <= RT_SHACRYPT_MAX_SALT_LEN, ("len=%zu\n", cchLen), NULL);
     103    *pcchSalt = cchLen;
     104
     105    return pszStr;
     106}
     107
     108
    65109RTR3DECL(int) RTCrShaCrypt256(const char *pszKey, const char *pszSalt, uint32_t cRounds, uint8_t abHash[RTSHA256_HASH_SIZE])
    66110{
     
    71115    size_t const cchKey     = strlen(pszKey);
    72116    AssertReturn(cchKey, VERR_INVALID_PARAMETER);
    73     size_t const cchSalt    = strlen(pszSalt);
    74     AssertMsgReturn(cchSalt >= RT_SHACRYPT_MIN_SALT_LEN && cchSalt <= RT_SHACRYPT_MAX_SALT_LEN, ("len=%zu\n", cchSalt),
    75                     VERR_INVALID_PARAMETER);
     117
     118    size_t cchSalt;
     119    pszSalt = rtCrShaCryptExtractSalt(pszSalt, &cchSalt);
     120    AssertPtrReturn(pszSalt, VERR_INVALID_PARAMETER);
    76121
    77122    uint8_t abDigest[RTSHA256_HASH_SIZE];
     
    202247    size_t cchPrefix;
    203248    if (cRounds == RT_SHACRYPT_DEFAULT_ROUNDS)
    204         cchPrefix = RTStrPrintf2(psz, cchString, "$5$%s$", pszSalt);
     249        cchPrefix = RTStrPrintf2(psz, cchString, "%s%s$", RT_SHACRYPT_DIGEST_PREFIX_256_STR, pszSalt);
    205250    else
    206         cchPrefix = RTStrPrintf2(psz, cchString, "$5$rounds=%RU32$%s$", cRounds, pszSalt);
     251        cchPrefix = RTStrPrintf2(psz, cchString, "%srounds=%RU32$%s$", RT_SHACRYPT_DIGEST_PREFIX_256_STR, cRounds, pszSalt);
    207252    AssertReturn(cchPrefix > 0, VERR_BUFFER_OVERFLOW);
    208253    AssertReturn(cch >= cchPrefix, VERR_BUFFER_OVERFLOW);
     
    255300    AssertReturn   (cRounds, VERR_INVALID_PARAMETER);
    256301
    257     size_t const cchKey     = strlen(pszKey);
     302    size_t const cchKey = strlen(pszKey);
    258303    AssertReturn(cchKey, VERR_INVALID_PARAMETER);
    259     size_t const cchSalt    = strlen(pszSalt);
    260     AssertMsgReturn(cchSalt >= RT_SHACRYPT_MIN_SALT_LEN && cchSalt <= RT_SHACRYPT_MAX_SALT_LEN, ("len=%zu\n", cchSalt),
    261                     VERR_INVALID_PARAMETER);
     304
     305    size_t cchSalt;
     306    pszSalt = rtCrShaCryptExtractSalt(pszSalt, &cchSalt);
     307    AssertPtrReturn(pszSalt, VERR_INVALID_PARAMETER);
    262308
    263309    uint8_t abDigest[RTSHA512_HASH_SIZE];
     
    386432    size_t cchPrefix;
    387433    if (cRounds == RT_SHACRYPT_DEFAULT_ROUNDS)
    388         cchPrefix = RTStrPrintf2(psz, cchString, "$6$%s$", pszSalt);
     434        cchPrefix = RTStrPrintf2(psz, cchString, "%s%s$", RT_SHACRYPT_DIGEST_PREFIX_512_STR, pszSalt);
    389435    else
    390         cchPrefix = RTStrPrintf2(psz, cchString, "$6$rounds=%RU32$%s$", cRounds, pszSalt);
     436        cchPrefix = RTStrPrintf2(psz, cchString, "%srounds=%RU32$%s$", RT_SHACRYPT_DIGEST_PREFIX_512_STR, cRounds, pszSalt);
    391437    AssertReturn(cchPrefix > 0, VERR_BUFFER_OVERFLOW);
    392438    AssertReturn(cch >= cchPrefix, VERR_BUFFER_OVERFLOW);
  • trunk/src/VBox/Runtime/testcase/tstRTShaCrypt.cpp

    r102360 r102375  
    247247                if (RTStrCmp(szResult, g_aTests[i].pszResultStr))
    248248                    RTTestIFailed("#%u: Returns '%s', expected '%s'", i, szResult, g_aTests[i].pszResultStr);
     249
     250                /* Now do the same, but hand-in the result string as the salt.
     251                 *
     252                 * This approach is used by many *crypt implementations -- it allows feeding the user-provided password and the
     253                 * crypted password from "the password file" to the function. If it returns the same crypted password then the
     254                 * user-provided password must be the correct one.
     255                 */
     256                switch (enmType)
     257                {
     258                    case TST_DIGESTTYPE_SHA256:
     259                    {
     260                        rc = RTCrShaCrypt256(g_aTests[i].pszPassword, g_aTests[i].pszResultStr, cRounds, abDigest);
     261                        if (RT_SUCCESS(rc))
     262                            rc = RTCrShaCrypt256ToString(abDigest, pszSalt, cRounds, szResult, sizeof(szResult));
     263                        break;
     264                    }
     265
     266                    case TST_DIGESTTYPE_SHA512:
     267                    {
     268                        rc = RTCrShaCrypt512(g_aTests[i].pszPassword, g_aTests[i].pszResultStr, cRounds, abDigest);
     269                        if (RT_SUCCESS(rc))
     270                            rc = RTCrShaCrypt512ToString(abDigest, pszSalt, cRounds, szResult, sizeof(szResult));
     271                        break;
     272                    }
     273
     274                    default:
     275                        AssertFailed();
     276                        break;
     277                }
     278
     279                if (RTStrCmp(szResult, g_aTests[i].pszResultStr))
     280                    RTTestIFailed("#%u (result as hash): Returns '%s', expected '%s'",
     281                                  i, szResult, g_aTests[i].pszResultStr);
    249282            }
    250283        }
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette