VirtualBox

Changeset 102488 in vbox for trunk/src


Ignore:
Timestamp:
Dec 5, 2023 11:53:09 PM (14 months ago)
Author:
vboxsync
Message:

IPRT,Main/Unattended: Added a simplified API for the SHAcrypt functionality (the two step approach isn't really something we'll be needing). Corrected documentation, added constant for max output size (RTSHA512_HASH_SIZE*4 isn't a good choice) and whatnot. Added missing round count range checks. Fixed rounding error in output string buffer requirements; actually replacing the whole stuff by just calculating the size upfront before formatting anything. bugref:10551

Location:
trunk/src/VBox
Files:
4 edited
2 copied
1 moved

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/src-server/UnattendedScript.cpp

    r102398 r102488  
    635635int UnattendedScriptTemplate::shaCryptGenerateSalt(char *pszSalt, size_t cchSalt)
    636636{
    637     AssertPtrReturn(pszSalt, VERR_INVALID_POINTER);
    638637#ifdef IN_TST_UNATTENDED_SCRIPT
    639638    /* Use a fixed salt to predict the hashing result with the testcases. */
    640     return RTStrPrintf2(pszSalt, cchSalt, "testcase123") > 0 ? VINF_SUCCESS : VERR_BUFFER_OVERFLOW;
     639    return RTStrCopy(pszSalt, cchSalt + 1, "testcase123");
    641640#else
    642641    return RTCrShaCryptGenerateSalt(pszSalt, cchSalt);
     
    648647#define IS_MATCH(a_szMatch) \
    649648        (cchName == sizeof(a_szMatch) - 1U && memcmp(pchName, a_szMatch, sizeof(a_szMatch) - 1U) == 0)
    650 /** Uses the RTCrShaCrypt APIs to hash and crypt data. Uses a randomized salt + (recommended) default rounds. */
    651 #define SHACRYPT_AND_ASSIGN(a_szKey, a_fnHashAndCrypt, a_cbHashSize) \
     649
     650/** Uses the RTCrShaCrypt APIs to hash and crypt data. Uses a randomized salt + (recommended) default rounds.
     651 * @todo r=bird: Iff a template needs the salted password more than once,
     652 *        this approach will not deliver the same value.
     653 */
     654#define SHACRYPT_AND_ASSIGN(a_szKey, a_fnCrypt, a_cchMaxResult) \
    652655        do { \
    653             uint8_t abHash[a_cbHashSize]; \
    654             char    szSalt[RT_SHACRYPT_MAX_SALT_LEN + 1]; \
    655             int vrc = UnattendedScriptTemplate::shaCryptGenerateSalt(szSalt, RT_SHACRYPT_MAX_SALT_LEN); \
    656             if (RT_SUCCESS(vrc)) \
     656            if (ppszValue) \
    657657            { \
    658                 vrc = a_fnHashAndCrypt(a_szKey, szSalt, RT_SHACRYPT_DEFAULT_ROUNDS, abHash); \
    659                 if (RT_SUCCESS(vrc)) \
    660                 { \
    661                     char szDigest[a_cbHashSize * 4]; \
    662                     vrc = a_fnHashAndCrypt##ToString(abHash, szSalt, RT_SHACRYPT_DEFAULT_ROUNDS, szDigest, sizeof(szDigest)); \
    663                     if (RT_SUCCESS(vrc)) \
    664                         pszValue = rstrTmp.assign(szDigest, strlen(szDigest)).c_str(); \
    665                 } \
     658                char szSalt[RT_SHACRYPT_SALT_MAX_LEN + 1]; \
     659                int vrc = UnattendedScriptTemplate::shaCryptGenerateSalt(szSalt, sizeof(szSalt) - 1); \
     660                AssertRCReturnStmt(vrc, mpSetError->setErrorBoth(E_FAIL, vrc, tr("RTCrShaCryptGenerateSalt failed: %Rrc"), vrc), \
     661                                   vrc); \
     662                rstrTmp.reserve(a_cchMaxResult); \
     663                vrc = a_fnCrypt(a_szKey, szSalt, RT_SHACRYPT_ROUNDS_DEFAULT, rstrTmp.mutableRaw(), a_cchMaxResult); \
     664                AssertRCReturnStmt(vrc, mpSetError->setErrorBoth(E_FAIL, vrc, tr(#a_fnCrypt " failed: %Rrc"), vrc), vrc); \
     665                rstrTmp.jolt(); \
     666                pszValue = rstrTmp.c_str(); \
    666667            } \
    667668        } while (0)
     
    677678        pszValue = mpUnattended->i_getPassword().c_str();
    678679    else if (IS_MATCH("USER_PASSWORD_SHACRYPT512"))
    679         SHACRYPT_AND_ASSIGN(mpUnattended->i_getPassword().c_str(), RTCrShaCrypt512, RTSHA512_HASH_SIZE);
     680        SHACRYPT_AND_ASSIGN(mpUnattended->i_getPassword().c_str(), RTCrShaCrypt512, RT_SHACRYPT_512_MAX_SIZE);
    680681    else if (IS_MATCH("ROOT_PASSWORD"))
    681682        pszValue = mpUnattended->i_getPassword().c_str();
    682683    else if (IS_MATCH("ROOT_PASSWORD_SHACRYPT512"))
    683         SHACRYPT_AND_ASSIGN(mpUnattended->i_getPassword().c_str(), RTCrShaCrypt512, RTSHA512_HASH_SIZE);
     684        SHACRYPT_AND_ASSIGN(mpUnattended->i_getPassword().c_str(), RTCrShaCrypt512, RT_SHACRYPT_512_MAX_SIZE);
    684685    else if (IS_MATCH("USER_FULL_NAME"))
    685686        pszValue = mpUnattended->i_getFullUserName().c_str();
  • trunk/src/VBox/Runtime/common/crypto/shacrypt-256.cpp.h

    r102476 r102488  
    11/* $Id$ */
    22/** @file
    3  * IPRT - Crypto - SHA-crypt.
     3 * IPRT - Crypto - SHA-crypt, code template for SHA-256 core.
     4 *
     5 * This is almost identical to shacrypt-512.cpp.h, fixes generally applies to
     6 * both. Diff the files after updates!
    47 */
    58
     
    3639
    3740
    38 /*********************************************************************************************************************************
    39 *   Header Files                                                                                                                 *
    40 *********************************************************************************************************************************/
    41 
    42 #include <iprt/crypto/shacrypt.h>
    43 #include <iprt/types.h>
    44 #include <iprt/mem.h>
    45 #include <iprt/rand.h>
    46 #include <iprt/sha.h>
    47 #include <iprt/string.h>
    48 
    49 
    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 
    55 
    56 RTR3DECL(int) RTCrShaCryptGenerateSalt(char *pszSalt, size_t cchSalt)
     41RTDECL(int) RTCrShaCrypt256(const char *pszPhrase, const char *pszSalt, uint32_t cRounds, char *pszString, size_t cbString)
    5742{
    58     AssertMsgReturn(cchSalt >= RT_SHACRYPT_MIN_SALT_LEN && cchSalt <= RT_SHACRYPT_MAX_SALT_LEN, ("len=%zu\n", cchSalt),
    59                     VERR_INVALID_PARAMETER);
    60 
    61     static const char aRange[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890./";
    62     for (size_t i = 0; i < cchSalt; i++)
    63         pszSalt[i] = aRange[RTRandU32Ex(0, sizeof(aRange) - 2)];
    64 
    65     pszSalt[cchSalt] = '\0';
    66     return VINF_SUCCESS;
     43    uint8_t abHash[RTSHA256_HASH_SIZE];
     44    int rc = RTCrShaCrypt256Ex(pszPhrase, pszSalt, cRounds, abHash);
     45    if (RT_SUCCESS(rc))
     46        rc = RTCrShaCrypt256ToString(abHash, pszSalt, cRounds, pszString, cbString);
     47    return rc;
    6748}
    6849
    6950
    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  */
    77 static const char *rtCrShaCryptExtractSalt(const char *pszStr, size_t *pcchSalt)
     51RTR3DECL(int) RTCrShaCrypt256Ex(const char *pszPhrase, const char *pszSalt, uint32_t cRounds, uint8_t pabHash[RTSHA256_HASH_SIZE])
    7852{
    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 
    109 RTR3DECL(int) RTCrShaCrypt256(const char *pszKey, const char *pszSalt, uint32_t cRounds, uint8_t abHash[RTSHA256_HASH_SIZE])
    110 {
    111     AssertPtrReturn(pszKey,   VERR_INVALID_POINTER);
    112     AssertPtrReturn(pszSalt,  VERR_INVALID_POINTER);
    113     AssertReturn   (cRounds, VERR_INVALID_PARAMETER);
    114 
    115     size_t const cchKey     = strlen(pszKey);
    116     AssertReturn(cchKey, VERR_INVALID_PARAMETER);
    117 
     53    /*
     54     * Validate and adjust input.
     55     */
     56    AssertPtrReturn(pszPhrase, VERR_INVALID_POINTER);
     57    size_t const cchPhrase = strlen(pszPhrase);
     58    AssertReturn(cchPhrase, VERR_INVALID_PARAMETER);
     59
     60    AssertPtrReturn(pszSalt, VERR_INVALID_POINTER);
    11861    size_t cchSalt;
    119     pszSalt = rtCrShaCryptExtractSalt(pszSalt, &cchSalt);
    120     AssertPtrReturn(pszSalt, VERR_INVALID_PARAMETER);
    121 
     62    pszSalt = rtCrShaCryptExtractSaltAndRounds(pszSalt, &cchSalt, &cRounds);
     63    AssertReturn(pszSalt != NULL, VERR_INVALID_PARAMETER);
     64    AssertReturn(cchSalt >= RT_SHACRYPT_SALT_MIN_LEN, VERR_BUFFER_UNDERFLOW);
     65    AssertReturn(cchSalt <= RT_SHACRYPT_SALT_MAX_LEN, VERR_TOO_MUCH_DATA);
     66    AssertReturn(cRounds >= RT_SHACRYPT_ROUNDS_MIN && cRounds <= RT_SHACRYPT_ROUNDS_MAX, VERR_OUT_OF_RANGE);
     67
     68    /*
     69     * Get started...
     70     */
     71    RTSHA256CONTEXT CtxA;
     72    RTSha256Init(&CtxA);                                                        /* Step 1. */
     73    RTSha256Update(&CtxA, pszPhrase, cchPhrase);                                /* Step 2. */
     74    RTSha256Update(&CtxA, pszSalt, cchSalt);                                    /* Step 3. */
     75
     76    RTSHA256CONTEXT CtxB;
     77    RTSha256Init(&CtxB);                                                        /* Step 4. */
     78    RTSha256Update(&CtxB, pszPhrase, cchPhrase);                                /* Step 5. */
     79    RTSha256Update(&CtxB, pszSalt, cchSalt);                                    /* Step 6. */
     80    RTSha256Update(&CtxB, pszPhrase, cchPhrase);                                /* Step 7. */
    12281    uint8_t abDigest[RTSHA256_HASH_SIZE];
     82    RTSha256Final(&CtxB, abDigest);                                             /* Step 8. */
     83
     84    size_t i = cchPhrase;
     85    for (; i > RTSHA256_HASH_SIZE; i -= RTSHA256_HASH_SIZE)                     /* Step 9. */
     86        RTSha256Update(&CtxA, abDigest, sizeof(abDigest));
     87    RTSha256Update(&CtxA, abDigest, i);                                         /* Step 10. */
     88
     89    size_t iPhraseBit = cchPhrase;
     90    while (iPhraseBit)                                                          /* Step 11. */
     91    {
     92        if ((iPhraseBit & 1) != 0)
     93            RTSha256Update(&CtxA, abDigest, sizeof(abDigest));                  /* a) */
     94        else
     95            RTSha256Update(&CtxA, pszPhrase, cchPhrase);                        /* b) */
     96        iPhraseBit >>= 1;
     97    }
     98
     99    RTSha256Final(&CtxA, abDigest);                                             /* Step 12. */
     100
     101    RTSha256Init(&CtxB);                                                        /* Step 13. */
     102    for (i = 0; i < cchPhrase; i++)                                             /* Step 14. */
     103        RTSha256Update(&CtxB, pszPhrase, cchPhrase);
     104
    123105    uint8_t abDigestTemp[RTSHA256_HASH_SIZE];
    124 
    125     RTSHA256CONTEXT Ctx;
    126     RTSha256Init(&Ctx);                                                         /* Step 1. */
    127     RTSha256Update(&Ctx, pszKey, cchKey);                                       /* Step 2. */
    128     RTSha256Update(&Ctx, pszSalt, cchSalt);                                     /* Step 3. */
    129 
    130     RTSHA256CONTEXT CtxAlt;
    131     RTSha256Init(&CtxAlt);                                                      /* Step 4. */
    132     RTSha256Update(&CtxAlt, pszKey, cchKey);                                    /* Step 5. */
    133     RTSha256Update(&CtxAlt, pszSalt, cchSalt);                                  /* Step 6. */
    134     RTSha256Update(&CtxAlt, pszKey, cchKey);                                    /* Step 7. */
    135     RTSha256Final(&CtxAlt, abDigest);                                           /* Step 8. */
    136 
    137     size_t i = cchKey;
    138     for (; i > RTSHA256_HASH_SIZE; i -= RTSHA256_HASH_SIZE)                     /* Step 9. */
    139         RTSha256Update(&Ctx, abDigest, sizeof(abDigest));
    140     RTSha256Update(&Ctx, abDigest, i);                                          /* Step 10. */
    141 
    142     size_t keyBits = cchKey;
    143     while (keyBits)                                                             /* Step 11. */
    144     {
    145         if ((keyBits & 1) != 0)
    146             RTSha256Update(&Ctx, abDigest, sizeof(abDigest));                   /* a) */
    147         else
    148             RTSha256Update(&Ctx, pszKey, cchKey);                               /* b) */
    149         keyBits >>= 1;
    150     }
    151 
    152     RTSha256Final(&Ctx, abDigest);                                              /* Step 12. */
    153 
    154     RTSha256Init(&CtxAlt);                                                      /* Step 13. */
    155     for (i = 0; i < cchKey; i++)                                                /* Step 14. */
    156         RTSha256Update(&CtxAlt, pszKey, cchKey);
    157     RTSha256Final(&CtxAlt, abDigestTemp);                                       /* Step 15. */
     106    RTSha256Final(&CtxB, abDigestTemp);                                         /* Step 15. */
    158107
    159108    /*
    160109     * Byte sequence P (= password).
    161110     */
    162     size_t const cbSeqP  = cchKey;
    163     uint8_t     *pabSeqP = (uint8_t *)RTMemDup(pszKey, cbSeqP);
    164     uint8_t     *p       = pabSeqP;
     111    size_t const cbSeqP  = cchPhrase;
     112    uint8_t     *pabSeqP = (uint8_t *)RTMemDup(pszPhrase, cbSeqP + 1);          /* +1 because the password may be empty */
     113    uint8_t     *pb       = pabSeqP;
    165114    AssertPtrReturn(pabSeqP, VERR_NO_MEMORY);
    166115
    167116    for (i = cbSeqP; i > RTSHA256_HASH_SIZE; i -= RTSHA256_HASH_SIZE)           /* Step 16. */
    168117    {
    169         memcpy(p, (void *)abDigestTemp, sizeof(abDigestTemp));                  /* a) */
    170         p += RTSHA256_HASH_SIZE;
    171     }
    172     memcpy(p, abDigestTemp, i);                                                 /* b) */
    173 
    174     RTSha256Init(&CtxAlt);                                                      /* Step 17. */
     118        memcpy(pb, abDigestTemp, sizeof(abDigestTemp));                         /* a) */
     119        pb += RTSHA256_HASH_SIZE;
     120    }
     121    memcpy(pb, abDigestTemp, i);                                                /* b) */
     122
     123    RTSha256Init(&CtxB);                                                        /* Step 17. */
    175124
    176125    for (i = 0; i < 16 + (unsigned)abDigest[0]; i++)                            /* Step 18. */
    177         RTSha256Update(&CtxAlt, pszSalt, cchSalt);
    178 
    179     RTSha256Final(&CtxAlt, abDigestTemp);                                       /* Step 19. */
     126        RTSha256Update(&CtxB, pszSalt, cchSalt);
     127
     128    RTSha256Final(&CtxB, abDigestTemp);                                         /* Step 19. */
    180129
    181130    /*
    182131     * Byte sequence S (= salt).
    183132     */
    184     size_t   const cbSeqS  = cchSalt;
    185     uint8_t       *pabSeqS = (uint8_t *)RTMemDup(pszSalt, cbSeqS);
    186                    p       = pabSeqS;
     133    /* Step 20. */
     134    size_t   const  cbSeqS  = cchSalt;
     135#if 0 /* Given that the salt has a fixed range (8 thru 16 bytes), and SHA-256
     136       * producing 64 bytes, we can safely skip the loop part here (a) and go
     137       * straight for step (b). Further, we can drop the whole memory allocation,
     138       * let alone duplication (it's all overwritten!), and use an uninitalized
     139       * stack buffer. */
     140    uint8_t * const pabSeqS = (uint8_t *)RTMemDup(pszSalt, cbSeqS + 1);
    187141    AssertPtrReturn(pabSeqS, VERR_NO_MEMORY);
    188142
    189     for (i = cbSeqS; i > RTSHA256_HASH_SIZE; i -= RTSHA256_HASH_SIZE)           /* Step 20. */
    190     {
    191         memcpy(p, (void *)abDigestTemp, sizeof(abDigestTemp));                  /* a) */
    192         p += RTSHA256_HASH_SIZE;
    193     }
    194     memcpy(p, abDigestTemp, i);                                                 /* b) */
     143    pb = pabSeqS;
     144    for (i = cbSeqS; i > RTSHA256_HASH_SIZE; i -= RTSHA256_HASH_SIZE)
     145    {
     146        memcpy(pb, (void *)abDigestTemp, sizeof(abDigestTemp));                 /* a) */
     147        pb += RTSHA256_HASH_SIZE;
     148    }
     149    memcpy(pb, abDigestTemp, i);                                                /* b) */
     150#else
     151    AssertCompile(RT_SHACRYPT_SALT_MAX_LEN < RTSHA256_HASH_SIZE);
     152    uint8_t         abSeqS[RT_SHACRYPT_SALT_MAX_LEN + 2];
     153    uint8_t * const pabSeqS = abSeqS;
     154    memcpy(abSeqS, abDigestTemp, cbSeqS);                                       /* b) */
     155#endif
    195156
    196157    /* Step 21. */
    197     for (uint32_t r = 0; r < cRounds; r++)
     158    for (uint32_t iRound = 0; iRound < cRounds; iRound++)
    198159    {
    199160        RTSHA256CONTEXT CtxC;
    200161        RTSha256Init(&CtxC);                                                    /* a) */
    201162
    202         if ((r & 1) != 0)
     163        if ((iRound & 1) != 0)
    203164            RTSha256Update(&CtxC, pabSeqP, cbSeqP);                             /* b) */
    204165        else
    205166            RTSha256Update(&CtxC, abDigest, sizeof(abDigest));                  /* c) */
    206167
    207         if (r % 3 != 0)                                                         /* d) */
     168        if (iRound % 3 != 0)                                                    /* d) */
    208169            RTSha256Update(&CtxC, pabSeqS, cbSeqS);
    209170
    210         if (r % 7 != 0)
     171        if (iRound % 7 != 0)
    211172            RTSha256Update(&CtxC, pabSeqP, cbSeqP);                             /* e) */
    212173
    213         if ((r & 1) != 0)
     174        if ((iRound & 1) != 0)
    214175            RTSha256Update(&CtxC, abDigest, sizeof(abDigest));                  /* f) */
    215176        else
     
    219180    }
    220181
    221     memcpy(abHash, abDigest, RTSHA256_HASH_SIZE);
    222 
     182    /*
     183     * Done.
     184     */
     185    memcpy(pabHash, abDigest, RTSHA256_HASH_SIZE);
     186
     187    /*
     188     * Cleanup.
     189     */
    223190    RTMemWipeThoroughly(abDigestTemp, RTSHA256_HASH_SIZE, 3);
    224191    RTMemWipeThoroughly(pabSeqP, cbSeqP, 3);
    225     RTMemWipeThoroughly(pabSeqP, cbSeqP, 3);
    226192    RTMemFree(pabSeqP);
     193#if 0
    227194    RTMemWipeThoroughly(pabSeqS, cbSeqS, 3);
    228195    RTMemFree(pabSeqS);
     196#else
     197    RTMemWipeThoroughly(abSeqS, sizeof(abSeqS), 3);
     198#endif
    229199
    230200    return VINF_SUCCESS;
     
    232202
    233203
    234 RTR3DECL(int) RTCrShaCrypt256ToString(uint8_t abHash[RTSHA256_HASH_SIZE], const char *pszSalt, uint32_t cRounds,
    235                                       char *pszString, size_t cchString)
     204RTR3DECL(int) RTCrShaCrypt256ToString(uint8_t const pabHash[RTSHA256_HASH_SIZE], const char *pszSalt, uint32_t cRounds,
     205                                      char *pszString, size_t cbString)
    236206{
    237     AssertPtrReturn(pszSalt,   VERR_INVALID_POINTER);
    238     AssertReturn   (cRounds,   VERR_INVALID_PARAMETER);
    239     AssertReturn   (cchString >= RTSHA256_DIGEST_LEN + 1, VERR_INVALID_PARAMETER);
     207    /*
     208     * Validate and adjust input.
     209     */
     210    AssertPtrReturn(pszSalt, VERR_INVALID_POINTER);
     211    size_t cchSalt;
     212    pszSalt = rtCrShaCryptExtractSaltAndRounds(pszSalt, &cchSalt, &cRounds);
     213    AssertReturn(pszSalt != NULL, VERR_INVALID_PARAMETER);
     214    AssertReturn(cchSalt >= RT_SHACRYPT_SALT_MIN_LEN, VERR_BUFFER_UNDERFLOW);
     215    AssertReturn(cchSalt <= RT_SHACRYPT_SALT_MAX_LEN, VERR_TOO_MUCH_DATA);
     216    AssertReturn(cRounds >= RT_SHACRYPT_ROUNDS_MIN && cRounds <= RT_SHACRYPT_ROUNDS_MAX, VERR_OUT_OF_RANGE);
     217
    240218    AssertPtrReturn(pszString, VERR_INVALID_POINTER);
    241219
    242     char  *psz = pszString;
    243     size_t cch = cchString;
    244 
    245     *psz = '\0';
    246 
    247     size_t cchPrefix;
    248     if (cRounds == RT_SHACRYPT_DEFAULT_ROUNDS)
    249         cchPrefix = RTStrPrintf2(psz, cchString, "%s%s$", RT_SHACRYPT_DIGEST_PREFIX_256_STR, pszSalt);
    250     else
    251         cchPrefix = RTStrPrintf2(psz, cchString, "%srounds=%RU32$%s$", RT_SHACRYPT_DIGEST_PREFIX_256_STR, cRounds, pszSalt);
    252     AssertReturn(cchPrefix > 0, VERR_BUFFER_OVERFLOW);
    253     AssertReturn(cch >= cchPrefix, VERR_BUFFER_OVERFLOW);
    254     cch -= cchPrefix;
    255     psz += cchPrefix;
    256 
    257     /* Make sure that there is enough room to store the base64-encoded hash. */
    258     AssertReturn(cch >= ((RTSHA256_HASH_SIZE / 3) * 4) + 1, VERR_BUFFER_OVERFLOW);
    259 
    260     static const char acBase64[64 + 1] =
    261         "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    262 
    263 #define BASE64_ENCODE(a_Val2, a_Val1, a_Val0, a_Cnt) \
    264     do { \
    265         unsigned int w = ((a_Val2) << 16) | ((a_Val1) << 8) | (a_Val0); \
    266         int n = (a_Cnt); \
    267         while (n-- > 0 && cch > 0) \
    268         { \
    269             *psz++ = acBase64[w & 0x3f]; \
    270             --cch; \
    271             w >>= 6; \
    272         } \
    273     } while (0)
    274 
    275     BASE64_ENCODE(abHash[0],  abHash[10], abHash[20], 4);
    276     BASE64_ENCODE(abHash[21], abHash[1],  abHash[11], 4);
    277     BASE64_ENCODE(abHash[12], abHash[22], abHash[2], 4);
    278     BASE64_ENCODE(abHash[3],  abHash[13], abHash[23], 4);
    279     BASE64_ENCODE(abHash[24], abHash[4],  abHash[14], 4);
    280     BASE64_ENCODE(abHash[15], abHash[25], abHash[5], 4);
    281     BASE64_ENCODE(abHash[6],  abHash[16], abHash[26], 4);
    282     BASE64_ENCODE(abHash[27], abHash[7],  abHash[17], 4);
    283     BASE64_ENCODE(abHash[18], abHash[28], abHash[8], 4);
    284     BASE64_ENCODE(abHash[9],  abHash[19], abHash[29], 4);
    285     BASE64_ENCODE(0,          abHash[31], abHash[30], 3);
    286 
    287 #undef BASE64_ENCODE
    288 
    289     if (cch)
    290         *psz = '\0';
     220    /*
     221     * Calc the necessary buffer space and check that the caller supplied enough.
     222     */
     223    char    szRounds[64];
     224    ssize_t cchRounds = 0;
     225    if (cRounds != RT_SHACRYPT_ROUNDS_DEFAULT)
     226    {
     227        cchRounds = RTStrFormatU32(szRounds, sizeof(szRounds), cRounds, 10, 0, 0, 0);
     228        Assert(cchRounds > 0 && cchRounds <= 9);
     229    }
     230
     231    size_t const cchNeeded = sizeof(RT_SHACRYPT_ID_STR_256) - 1
     232                           + (cRounds != RT_SHACRYPT_ROUNDS_DEFAULT ? cchRounds + sizeof("rounds=$") - 1 : 0)
     233                           + cchSalt + 1
     234                           + RTSHA256_HASH_SIZE * 4 / 3
     235                           + 1;
     236    AssertReturn(cbString > cchNeeded, VERR_BUFFER_OVERFLOW);
     237
     238    /*
     239     * Do the formatting.
     240     */
     241    memcpy(pszString, RT_STR_TUPLE(RT_SHACRYPT_ID_STR_256));
     242    size_t off = sizeof(RT_SHACRYPT_ID_STR_256) - 1;
     243
     244    if (cRounds != RT_SHACRYPT_ROUNDS_DEFAULT)
     245    {
     246        memcpy(&pszString[off], RT_STR_TUPLE("rounds="));
     247        off += sizeof("rounds=") - 1;
     248
     249        memcpy(&pszString[off], szRounds, cchRounds);
     250        off += cchRounds;
     251        pszString[off++] = '$';
     252    }
     253
     254    memcpy(&pszString[off], pszSalt, cchSalt);
     255    off += cchSalt;
     256    pszString[off++] = '$';
     257
     258    BASE64_ENCODE(pszString, off, pabHash[00], pabHash[10], pabHash[20], 4);
     259    BASE64_ENCODE(pszString, off, pabHash[21], pabHash[ 1], pabHash[11], 4);
     260    BASE64_ENCODE(pszString, off, pabHash[12], pabHash[22], pabHash[ 2], 4);
     261    BASE64_ENCODE(pszString, off, pabHash[ 3], pabHash[13], pabHash[23], 4);
     262    BASE64_ENCODE(pszString, off, pabHash[24], pabHash[ 4], pabHash[14], 4);
     263    BASE64_ENCODE(pszString, off, pabHash[15], pabHash[25], pabHash[ 5], 4);
     264    BASE64_ENCODE(pszString, off, pabHash[ 6], pabHash[16], pabHash[26], 4);
     265    BASE64_ENCODE(pszString, off, pabHash[27], pabHash[ 7], pabHash[17], 4);
     266    BASE64_ENCODE(pszString, off, pabHash[18], pabHash[28], pabHash[ 8], 4);
     267    BASE64_ENCODE(pszString, off, pabHash[ 9], pabHash[19], pabHash[29], 4);
     268    BASE64_ENCODE(pszString, off, 0,           pabHash[31], pabHash[30], 3);
     269
     270    pszString[off] = '\0';
     271    Assert(off < cbString);
    291272
    292273    return VINF_SUCCESS;
    293274}
    294275
    295 
    296 RTR3DECL(int) RTCrShaCrypt512(const char *pszKey, const char *pszSalt, uint32_t cRounds, uint8_t abHash[RTSHA512_HASH_SIZE])
    297 {
    298     AssertPtrReturn(pszKey,   VERR_INVALID_POINTER);
    299     AssertPtrReturn(pszSalt,  VERR_INVALID_POINTER);
    300     AssertReturn   (cRounds, VERR_INVALID_PARAMETER);
    301 
    302     size_t const cchKey = strlen(pszKey);
    303     AssertReturn(cchKey, VERR_INVALID_PARAMETER);
    304 
    305     size_t cchSalt;
    306     pszSalt = rtCrShaCryptExtractSalt(pszSalt, &cchSalt);
    307     AssertPtrReturn(pszSalt, VERR_INVALID_PARAMETER);
    308 
    309     uint8_t abDigest[RTSHA512_HASH_SIZE];
    310     uint8_t abDigestTemp[RTSHA512_HASH_SIZE];
    311 
    312     RTSHA512CONTEXT Ctx;
    313     RTSha512Init(&Ctx);                                                         /* Step 1. */
    314     RTSha512Update(&Ctx, pszKey, cchKey);                                       /* Step 2. */
    315     RTSha512Update(&Ctx, pszSalt, cchSalt);                                     /* Step 3. */
    316 
    317     RTSHA512CONTEXT CtxAlt;
    318     RTSha512Init(&CtxAlt);                                                      /* Step 4. */
    319     RTSha512Update(&CtxAlt, pszKey, cchKey);                                    /* Step 5. */
    320     RTSha512Update(&CtxAlt, pszSalt, cchSalt);                                  /* Step 6. */
    321     RTSha512Update(&CtxAlt, pszKey, cchKey);                                    /* Step 7. */
    322     RTSha512Final(&CtxAlt, abDigest);                                           /* Step 8. */
    323 
    324     size_t i = cchKey;
    325     for (; i > RTSHA512_HASH_SIZE; i -= RTSHA512_HASH_SIZE)                     /* Step 9. */
    326         RTSha512Update(&Ctx, abDigest, sizeof(abDigest));
    327     RTSha512Update(&Ctx, abDigest, i);                                          /* Step 10. */
    328 
    329     size_t keyBits = cchKey;
    330     while (keyBits)                                                             /* Step 11. */
    331     {
    332         if ((keyBits & 1) != 0)
    333             RTSha512Update(&Ctx, abDigest, sizeof(abDigest));                   /* a) */
    334         else
    335             RTSha512Update(&Ctx, pszKey, cchKey);                               /* b) */
    336         keyBits >>= 1;
    337     }
    338 
    339     RTSha512Final(&Ctx, abDigest);                                              /* Step 12. */
    340 
    341     RTSha512Init(&CtxAlt);                                                      /* Step 13. */
    342     for (i = 0; i < cchKey; i++)                                                /* Step 14. */
    343         RTSha512Update(&CtxAlt, pszKey, cchKey);
    344     RTSha512Final(&CtxAlt, abDigestTemp);                                       /* Step 15. */
    345 
    346     /*
    347      * Byte sequence P (= password).
    348      */
    349     size_t const cbSeqP  = cchKey;
    350     uint8_t     *pabSeqP = (uint8_t *)RTMemDup(pszKey, cbSeqP);
    351     uint8_t     *p       = pabSeqP;
    352     AssertPtrReturn(pabSeqP, VERR_NO_MEMORY);
    353 
    354     for (i = cbSeqP; i > RTSHA512_HASH_SIZE; i -= RTSHA512_HASH_SIZE)           /* Step 16. */
    355     {
    356         memcpy(p, (void *)abDigestTemp, sizeof(abDigestTemp));                  /* a) */
    357         p += RTSHA512_HASH_SIZE;
    358     }
    359     memcpy(p, abDigestTemp, i);                                                 /* b) */
    360 
    361     RTSha512Init(&CtxAlt);                                                      /* Step 17. */
    362 
    363     for (i = 0; i < 16 + (unsigned)abDigest[0]; i++)                            /* Step 18. */
    364         RTSha512Update(&CtxAlt, pszSalt, cchSalt);
    365 
    366     RTSha512Final(&CtxAlt, abDigestTemp);                                       /* Step 19. */
    367 
    368     /*
    369      * Byte sequence S (= salt).
    370      */
    371     size_t   const cbSeqS  = cchSalt;
    372     uint8_t       *pabSeqS = (uint8_t *)RTMemDup(pszSalt, cbSeqS);
    373                    p       = pabSeqS;
    374     AssertPtrReturn(pabSeqS, VERR_NO_MEMORY);
    375 
    376     for (i = cbSeqS; i > RTSHA512_HASH_SIZE; i -= RTSHA512_HASH_SIZE)           /* Step 20. */
    377     {
    378         memcpy(p, (void *)abDigestTemp, sizeof(abDigestTemp));                  /* a) */
    379         p += RTSHA512_HASH_SIZE;
    380     }
    381     memcpy(p, abDigestTemp, i);                                                 /* b) */
    382 
    383     /* Step 21. */
    384     for (uint32_t r = 0; r < cRounds; r++)
    385     {
    386         RTSHA512CONTEXT CtxC;
    387         RTSha512Init(&CtxC);                                                    /* a) */
    388 
    389         if ((r & 1) != 0)
    390             RTSha512Update(&CtxC, pabSeqP, cbSeqP);                             /* b) */
    391         else
    392             RTSha512Update(&CtxC, abDigest, sizeof(abDigest));                  /* c) */
    393 
    394         if (r % 3 != 0)                                                         /* d) */
    395             RTSha512Update(&CtxC, pabSeqS, cbSeqS);
    396 
    397         if (r % 7 != 0)
    398             RTSha512Update(&CtxC, pabSeqP, cbSeqP);                             /* e) */
    399 
    400         if ((r & 1) != 0)
    401             RTSha512Update(&CtxC, abDigest, sizeof(abDigest));                  /* f) */
    402         else
    403             RTSha512Update(&CtxC, pabSeqP, cbSeqP);                             /* g) */
    404 
    405         RTSha512Final(&CtxC, abDigest);                                         /* h) */
    406     }
    407 
    408     memcpy(abHash, abDigest, RTSHA512_HASH_SIZE);
    409 
    410     RTMemWipeThoroughly(abDigestTemp, RTSHA512_HASH_SIZE, 3);
    411     RTMemWipeThoroughly(pabSeqP, cbSeqP, 3);
    412     RTMemWipeThoroughly(pabSeqP, cbSeqP, 3);
    413     RTMemFree(pabSeqP);
    414     RTMemWipeThoroughly(pabSeqS, cbSeqS, 3);
    415     RTMemFree(pabSeqS);
    416 
    417     return VINF_SUCCESS;
    418 }
    419 
    420 
    421 RTR3DECL(int) RTCrShaCrypt512ToString(uint8_t abHash[RTSHA512_HASH_SIZE], const char *pszSalt, uint32_t cRounds,
    422                                       char *pszString, size_t cchString)
    423 {
    424     AssertPtrReturn(pszSalt,   VERR_INVALID_POINTER);
    425     AssertReturn   (cRounds,   VERR_INVALID_PARAMETER);
    426     AssertReturn   (cchString >= RTSHA512_DIGEST_LEN + 1, VERR_INVALID_PARAMETER);
    427     AssertPtrReturn(pszString, VERR_INVALID_POINTER);
    428 
    429     char  *psz = pszString;
    430     size_t cch = cchString;
    431 
    432     size_t cchPrefix;
    433     if (cRounds == RT_SHACRYPT_DEFAULT_ROUNDS)
    434         cchPrefix = RTStrPrintf2(psz, cchString, "%s%s$", RT_SHACRYPT_DIGEST_PREFIX_512_STR, pszSalt);
    435     else
    436         cchPrefix = RTStrPrintf2(psz, cchString, "%srounds=%RU32$%s$", RT_SHACRYPT_DIGEST_PREFIX_512_STR, cRounds, pszSalt);
    437     AssertReturn(cchPrefix > 0, VERR_BUFFER_OVERFLOW);
    438     AssertReturn(cch >= cchPrefix, VERR_BUFFER_OVERFLOW);
    439     cch -= cchPrefix;
    440     psz += cchPrefix;
    441 
    442     /* Make sure that there is enough room to store the base64-encoded hash. */
    443     AssertReturn(cch >= ((RTSHA512_HASH_SIZE / 3) * 4) + 1, VERR_BUFFER_OVERFLOW);
    444 
    445     static const char acBase64[64 + 1] =
    446         "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    447 
    448 #define BASE64_ENCODE(a_Val2, a_Val1, a_Val0, a_Cnt) \
    449     do { \
    450         unsigned int w = ((a_Val2) << 16) | ((a_Val1) << 8) | (a_Val0); \
    451         int n = (a_Cnt); \
    452         while (n-- > 0 && cch > 0) \
    453         { \
    454             *psz++ = acBase64[w & 0x3f]; \
    455             --cch; \
    456             w >>= 6; \
    457         } \
    458     } while (0)
    459 
    460     BASE64_ENCODE(abHash[0],  abHash[21], abHash[42], 4);
    461     BASE64_ENCODE(abHash[22], abHash[43], abHash[1], 4);
    462     BASE64_ENCODE(abHash[44], abHash[2],  abHash[23], 4);
    463     BASE64_ENCODE(abHash[3],  abHash[24], abHash[45], 4);
    464     BASE64_ENCODE(abHash[25], abHash[46], abHash[4], 4);
    465     BASE64_ENCODE(abHash[47], abHash[5],  abHash[26], 4);
    466     BASE64_ENCODE(abHash[6],  abHash[27], abHash[48], 4);
    467     BASE64_ENCODE(abHash[28], abHash[49], abHash[7], 4);
    468     BASE64_ENCODE(abHash[50], abHash[8],  abHash[29], 4);
    469     BASE64_ENCODE(abHash[9],  abHash[30], abHash[51], 4);
    470     BASE64_ENCODE(abHash[31], abHash[52], abHash[10], 4);
    471     BASE64_ENCODE(abHash[53], abHash[11], abHash[32], 4);
    472     BASE64_ENCODE(abHash[12], abHash[33], abHash[54], 4);
    473     BASE64_ENCODE(abHash[34], abHash[55], abHash[13], 4);
    474     BASE64_ENCODE(abHash[56], abHash[14], abHash[35], 4);
    475     BASE64_ENCODE(abHash[15], abHash[36], abHash[57], 4);
    476     BASE64_ENCODE(abHash[37], abHash[58], abHash[16], 4);
    477     BASE64_ENCODE(abHash[59], abHash[17], abHash[38], 4);
    478     BASE64_ENCODE(abHash[18], abHash[39], abHash[60], 4);
    479     BASE64_ENCODE(abHash[40], abHash[61], abHash[19], 4);
    480     BASE64_ENCODE(abHash[62], abHash[20], abHash[41], 4);
    481     BASE64_ENCODE(0, 0, abHash[63], 2);
    482 
    483 #undef BASE64_ENCODE
    484 
    485     if (cch)
    486         *psz = '\0';
    487 
    488     return VINF_SUCCESS;
    489 }
    490 
  • trunk/src/VBox/Runtime/common/crypto/shacrypt-512.cpp.h

    r102476 r102488  
    11/* $Id$ */
    22/** @file
    3  * IPRT - Crypto - SHA-crypt.
     3 * IPRT - Crypto - SHA-crypt, code template for SHA-512 core.
     4 *
     5 * This is almost identical to shacrypt-256.cpp.h, fixes generally applies to
     6 * both. Diff the files after updates!
    47 */
    58
     
    3639
    3740
    38 /*********************************************************************************************************************************
    39 *   Header Files                                                                                                                 *
    40 *********************************************************************************************************************************/
    41 
    42 #include <iprt/crypto/shacrypt.h>
    43 #include <iprt/types.h>
    44 #include <iprt/mem.h>
    45 #include <iprt/rand.h>
    46 #include <iprt/sha.h>
    47 #include <iprt/string.h>
    48 
    49 
    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 
    55 
    56 RTR3DECL(int) RTCrShaCryptGenerateSalt(char *pszSalt, size_t cchSalt)
     41RTDECL(int) RTCrShaCrypt512(const char *pszPhrase, const char *pszSalt, uint32_t cRounds, char *pszString, size_t cbString)
    5742{
    58     AssertMsgReturn(cchSalt >= RT_SHACRYPT_MIN_SALT_LEN && cchSalt <= RT_SHACRYPT_MAX_SALT_LEN, ("len=%zu\n", cchSalt),
    59                     VERR_INVALID_PARAMETER);
    60 
    61     static const char aRange[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890./";
    62     for (size_t i = 0; i < cchSalt; i++)
    63         pszSalt[i] = aRange[RTRandU32Ex(0, sizeof(aRange) - 2)];
    64 
    65     pszSalt[cchSalt] = '\0';
    66     return VINF_SUCCESS;
     43    uint8_t abHash[RTSHA512_HASH_SIZE];
     44    int rc = RTCrShaCrypt512Ex(pszPhrase, pszSalt, cRounds, abHash);
     45    if (RT_SUCCESS(rc))
     46        rc = RTCrShaCrypt512ToString(abHash, pszSalt, cRounds, pszString, cbString);
     47    return rc;
    6748}
    6849
    6950
    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  */
    77 static const char *rtCrShaCryptExtractSalt(const char *pszStr, size_t *pcchSalt)
     51
     52RTR3DECL(int) RTCrShaCrypt512Ex(const char *pszPhrase, const char *pszSalt, uint32_t cRounds, uint8_t pabHash[RTSHA512_HASH_SIZE])
    7853{
    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 
    109 RTR3DECL(int) RTCrShaCrypt256(const char *pszKey, const char *pszSalt, uint32_t cRounds, uint8_t abHash[RTSHA256_HASH_SIZE])
    110 {
    111     AssertPtrReturn(pszKey,   VERR_INVALID_POINTER);
    112     AssertPtrReturn(pszSalt,  VERR_INVALID_POINTER);
    113     AssertReturn   (cRounds, VERR_INVALID_PARAMETER);
    114 
    115     size_t const cchKey     = strlen(pszKey);
    116     AssertReturn(cchKey, VERR_INVALID_PARAMETER);
    117 
     54    /*
     55     * Validate and adjust input.
     56     */
     57    AssertPtrReturn(pszPhrase, VERR_INVALID_POINTER);
     58    size_t const cchPhrase = strlen(pszPhrase);
     59    AssertReturn(cchPhrase, VERR_INVALID_PARAMETER);
     60
     61    AssertPtrReturn(pszSalt, VERR_INVALID_POINTER);
    11862    size_t cchSalt;
    119     pszSalt = rtCrShaCryptExtractSalt(pszSalt, &cchSalt);
    120     AssertPtrReturn(pszSalt, VERR_INVALID_PARAMETER);
    121 
    122     uint8_t abDigest[RTSHA256_HASH_SIZE];
    123     uint8_t abDigestTemp[RTSHA256_HASH_SIZE];
    124 
    125     RTSHA256CONTEXT Ctx;
    126     RTSha256Init(&Ctx);                                                         /* Step 1. */
    127     RTSha256Update(&Ctx, pszKey, cchKey);                                       /* Step 2. */
    128     RTSha256Update(&Ctx, pszSalt, cchSalt);                                     /* Step 3. */
    129 
    130     RTSHA256CONTEXT CtxAlt;
    131     RTSha256Init(&CtxAlt);                                                      /* Step 4. */
    132     RTSha256Update(&CtxAlt, pszKey, cchKey);                                    /* Step 5. */
    133     RTSha256Update(&CtxAlt, pszSalt, cchSalt);                                  /* Step 6. */
    134     RTSha256Update(&CtxAlt, pszKey, cchKey);                                    /* Step 7. */
    135     RTSha256Final(&CtxAlt, abDigest);                                           /* Step 8. */
    136 
    137     size_t i = cchKey;
    138     for (; i > RTSHA256_HASH_SIZE; i -= RTSHA256_HASH_SIZE)                     /* Step 9. */
    139         RTSha256Update(&Ctx, abDigest, sizeof(abDigest));
    140     RTSha256Update(&Ctx, abDigest, i);                                          /* Step 10. */
    141 
    142     size_t keyBits = cchKey;
    143     while (keyBits)                                                             /* Step 11. */
    144     {
    145         if ((keyBits & 1) != 0)
    146             RTSha256Update(&Ctx, abDigest, sizeof(abDigest));                   /* a) */
     63    pszSalt = rtCrShaCryptExtractSaltAndRounds(pszSalt, &cchSalt, &cRounds);
     64    AssertReturn(pszSalt != NULL, VERR_INVALID_PARAMETER);
     65    AssertReturn(cchSalt >= RT_SHACRYPT_SALT_MIN_LEN, VERR_BUFFER_UNDERFLOW);
     66    AssertReturn(cchSalt <= RT_SHACRYPT_SALT_MAX_LEN, VERR_TOO_MUCH_DATA);
     67    AssertReturn(cRounds >= RT_SHACRYPT_ROUNDS_MIN && cRounds <= RT_SHACRYPT_ROUNDS_MAX, VERR_OUT_OF_RANGE);
     68
     69    /*
     70     * Get started...
     71     */
     72    RTSHA512CONTEXT CtxA;
     73    RTSha512Init(&CtxA);                                                        /* Step 1. */
     74    RTSha512Update(&CtxA, pszPhrase, cchPhrase);                                /* Step 2. */
     75    RTSha512Update(&CtxA, pszSalt, cchSalt);                                    /* Step 3. */
     76
     77    RTSHA512CONTEXT CtxB;
     78    RTSha512Init(&CtxB);                                                        /* Step 4. */
     79    RTSha512Update(&CtxB, pszPhrase, cchPhrase);                                /* Step 5. */
     80    RTSha512Update(&CtxB, pszSalt, cchSalt);                                    /* Step 6. */
     81    RTSha512Update(&CtxB, pszPhrase, cchPhrase);                                /* Step 7. */
     82    uint8_t abDigest[RTSHA512_HASH_SIZE];
     83    RTSha512Final(&CtxB, abDigest);                                             /* Step 8. */
     84
     85    size_t i = cchPhrase;
     86    for (; i > RTSHA512_HASH_SIZE; i -= RTSHA512_HASH_SIZE)                     /* Step 9. */
     87        RTSha512Update(&CtxA, abDigest, sizeof(abDigest));
     88    RTSha512Update(&CtxA, abDigest, i);                                         /* Step 10. */
     89
     90    size_t iPhraseBit = cchPhrase;
     91    while (iPhraseBit)                                                          /* Step 11. */
     92    {
     93        if ((iPhraseBit & 1) != 0)
     94            RTSha512Update(&CtxA, abDigest, sizeof(abDigest));                  /* a) */
    14795        else
    148             RTSha256Update(&Ctx, pszKey, cchKey);                               /* b) */
    149         keyBits >>= 1;
    150     }
    151 
    152     RTSha256Final(&Ctx, abDigest);                                              /* Step 12. */
    153 
    154     RTSha256Init(&CtxAlt);                                                      /* Step 13. */
    155     for (i = 0; i < cchKey; i++)                                                /* Step 14. */
    156         RTSha256Update(&CtxAlt, pszKey, cchKey);
    157     RTSha256Final(&CtxAlt, abDigestTemp);                                       /* Step 15. */
     96            RTSha512Update(&CtxA, pszPhrase, cchPhrase);                        /* b) */
     97        iPhraseBit >>= 1;
     98    }
     99
     100    RTSha512Final(&CtxA, abDigest);                                             /* Step 12. */
     101
     102    RTSha512Init(&CtxB);                                                        /* Step 13. */
     103    for (i = 0; i < cchPhrase; i++)                                             /* Step 14. */
     104        RTSha512Update(&CtxB, pszPhrase, cchPhrase);
     105
     106    uint8_t abDigestTemp[RTSHA512_HASH_SIZE];
     107    RTSha512Final(&CtxB, abDigestTemp);                                         /* Step 15. */
    158108
    159109    /*
    160110     * Byte sequence P (= password).
    161111     */
    162     size_t const cbSeqP  = cchKey;
    163     uint8_t     *pabSeqP = (uint8_t *)RTMemDup(pszKey, cbSeqP);
    164     uint8_t     *p       = pabSeqP;
     112    size_t const cbSeqP  = cchPhrase;
     113    uint8_t     *pabSeqP = (uint8_t *)RTMemDup(pszPhrase, cbSeqP + 1);          /* +1 because the password may be empty */
     114    uint8_t     *pb       = pabSeqP;
    165115    AssertPtrReturn(pabSeqP, VERR_NO_MEMORY);
    166116
    167     for (i = cbSeqP; i > RTSHA256_HASH_SIZE; i -= RTSHA256_HASH_SIZE)           /* Step 16. */
    168     {
    169         memcpy(p, (void *)abDigestTemp, sizeof(abDigestTemp));                  /* a) */
    170         p += RTSHA256_HASH_SIZE;
    171     }
    172     memcpy(p, abDigestTemp, i);                                                 /* b) */
    173 
    174     RTSha256Init(&CtxAlt);                                                      /* Step 17. */
     117    for (i = cbSeqP; i > RTSHA512_HASH_SIZE; i -= RTSHA512_HASH_SIZE)           /* Step 16. */
     118    {
     119        memcpy(pb, abDigestTemp, sizeof(abDigestTemp));                         /* a) */
     120        pb += RTSHA512_HASH_SIZE;
     121    }
     122    memcpy(pb, abDigestTemp, i);                                                /* b) */
     123
     124    RTSha512Init(&CtxB);                                                        /* Step 17. */
    175125
    176126    for (i = 0; i < 16 + (unsigned)abDigest[0]; i++)                            /* Step 18. */
    177         RTSha256Update(&CtxAlt, pszSalt, cchSalt);
    178 
    179     RTSha256Final(&CtxAlt, abDigestTemp);                                       /* Step 19. */
     127        RTSha512Update(&CtxB, pszSalt, cchSalt);
     128
     129    RTSha512Final(&CtxB, abDigestTemp);                                         /* Step 19. */
    180130
    181131    /*
    182132     * Byte sequence S (= salt).
    183133     */
    184     size_t   const cbSeqS  = cchSalt;
    185     uint8_t       *pabSeqS = (uint8_t *)RTMemDup(pszSalt, cbSeqS);
    186                    p       = pabSeqS;
     134    /* Step 20. */
     135    size_t   const  cbSeqS  = cchSalt;
     136#if 0 /* Given that the salt has a fixed range (8 thru 16 bytes), and SHA-512
     137       * producing 64 bytes, we can safely skip the loop part here (a) and go
     138       * straight for step (b). Further, we can drop the whole memory allocation,
     139       * let alone duplication (it's all overwritten!), and use an uninitalized
     140       * stack buffer. */
     141    uint8_t * const pabSeqS = (uint8_t *)RTMemDup(pszSalt, cbSeqS + 1);
    187142    AssertPtrReturn(pabSeqS, VERR_NO_MEMORY);
    188143
    189     for (i = cbSeqS; i > RTSHA256_HASH_SIZE; i -= RTSHA256_HASH_SIZE)           /* Step 20. */
    190     {
    191         memcpy(p, (void *)abDigestTemp, sizeof(abDigestTemp));                  /* a) */
    192         p += RTSHA256_HASH_SIZE;
    193     }
    194     memcpy(p, abDigestTemp, i);                                                 /* b) */
     144    pb = pabSeqS;
     145    for (i = cbSeqS; i > RTSHA512_HASH_SIZE; i -= RTSHA512_HASH_SIZE)
     146    {
     147        memcpy(pb, (void *)abDigestTemp, sizeof(abDigestTemp));                 /* a) */
     148        pb += RTSHA512_HASH_SIZE;
     149    }
     150    memcpy(pb, abDigestTemp, i);                                                /* b) */
     151#else
     152    AssertCompile(RT_SHACRYPT_SALT_MAX_LEN < RTSHA512_HASH_SIZE);
     153    uint8_t         abSeqS[RT_SHACRYPT_SALT_MAX_LEN + 2];
     154    uint8_t * const pabSeqS = abSeqS;
     155    memcpy(abSeqS, abDigestTemp, cbSeqS);                                       /* b) */
     156#endif
    195157
    196158    /* Step 21. */
    197     for (uint32_t r = 0; r < cRounds; r++)
    198     {
    199         RTSHA256CONTEXT CtxC;
    200         RTSha256Init(&CtxC);                                                    /* a) */
    201 
    202         if ((r & 1) != 0)
    203             RTSha256Update(&CtxC, pabSeqP, cbSeqP);                             /* b) */
    204         else
    205             RTSha256Update(&CtxC, abDigest, sizeof(abDigest));                  /* c) */
    206 
    207         if (r % 3 != 0)                                                         /* d) */
    208             RTSha256Update(&CtxC, pabSeqS, cbSeqS);
    209 
    210         if (r % 7 != 0)
    211             RTSha256Update(&CtxC, pabSeqP, cbSeqP);                             /* e) */
    212 
    213         if ((r & 1) != 0)
    214             RTSha256Update(&CtxC, abDigest, sizeof(abDigest));                  /* f) */
    215         else
    216             RTSha256Update(&CtxC, pabSeqP, cbSeqP);                             /* g) */
    217 
    218         RTSha256Final(&CtxC, abDigest);                                         /* h) */
    219     }
    220 
    221     memcpy(abHash, abDigest, RTSHA256_HASH_SIZE);
    222 
    223     RTMemWipeThoroughly(abDigestTemp, RTSHA256_HASH_SIZE, 3);
    224     RTMemWipeThoroughly(pabSeqP, cbSeqP, 3);
    225     RTMemWipeThoroughly(pabSeqP, cbSeqP, 3);
    226     RTMemFree(pabSeqP);
    227     RTMemWipeThoroughly(pabSeqS, cbSeqS, 3);
    228     RTMemFree(pabSeqS);
    229 
    230     return VINF_SUCCESS;
    231 }
    232 
    233 
    234 RTR3DECL(int) RTCrShaCrypt256ToString(uint8_t abHash[RTSHA256_HASH_SIZE], const char *pszSalt, uint32_t cRounds,
    235                                       char *pszString, size_t cchString)
    236 {
    237     AssertPtrReturn(pszSalt,   VERR_INVALID_POINTER);
    238     AssertReturn   (cRounds,   VERR_INVALID_PARAMETER);
    239     AssertReturn   (cchString >= RTSHA256_DIGEST_LEN + 1, VERR_INVALID_PARAMETER);
    240     AssertPtrReturn(pszString, VERR_INVALID_POINTER);
    241 
    242     char  *psz = pszString;
    243     size_t cch = cchString;
    244 
    245     *psz = '\0';
    246 
    247     size_t cchPrefix;
    248     if (cRounds == RT_SHACRYPT_DEFAULT_ROUNDS)
    249         cchPrefix = RTStrPrintf2(psz, cchString, "%s%s$", RT_SHACRYPT_DIGEST_PREFIX_256_STR, pszSalt);
    250     else
    251         cchPrefix = RTStrPrintf2(psz, cchString, "%srounds=%RU32$%s$", RT_SHACRYPT_DIGEST_PREFIX_256_STR, cRounds, pszSalt);
    252     AssertReturn(cchPrefix > 0, VERR_BUFFER_OVERFLOW);
    253     AssertReturn(cch >= cchPrefix, VERR_BUFFER_OVERFLOW);
    254     cch -= cchPrefix;
    255     psz += cchPrefix;
    256 
    257     /* Make sure that there is enough room to store the base64-encoded hash. */
    258     AssertReturn(cch >= ((RTSHA256_HASH_SIZE / 3) * 4) + 1, VERR_BUFFER_OVERFLOW);
    259 
    260     static const char acBase64[64 + 1] =
    261         "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    262 
    263 #define BASE64_ENCODE(a_Val2, a_Val1, a_Val0, a_Cnt) \
    264     do { \
    265         unsigned int w = ((a_Val2) << 16) | ((a_Val1) << 8) | (a_Val0); \
    266         int n = (a_Cnt); \
    267         while (n-- > 0 && cch > 0) \
    268         { \
    269             *psz++ = acBase64[w & 0x3f]; \
    270             --cch; \
    271             w >>= 6; \
    272         } \
    273     } while (0)
    274 
    275     BASE64_ENCODE(abHash[0],  abHash[10], abHash[20], 4);
    276     BASE64_ENCODE(abHash[21], abHash[1],  abHash[11], 4);
    277     BASE64_ENCODE(abHash[12], abHash[22], abHash[2], 4);
    278     BASE64_ENCODE(abHash[3],  abHash[13], abHash[23], 4);
    279     BASE64_ENCODE(abHash[24], abHash[4],  abHash[14], 4);
    280     BASE64_ENCODE(abHash[15], abHash[25], abHash[5], 4);
    281     BASE64_ENCODE(abHash[6],  abHash[16], abHash[26], 4);
    282     BASE64_ENCODE(abHash[27], abHash[7],  abHash[17], 4);
    283     BASE64_ENCODE(abHash[18], abHash[28], abHash[8], 4);
    284     BASE64_ENCODE(abHash[9],  abHash[19], abHash[29], 4);
    285     BASE64_ENCODE(0,          abHash[31], abHash[30], 3);
    286 
    287 #undef BASE64_ENCODE
    288 
    289     if (cch)
    290         *psz = '\0';
    291 
    292     return VINF_SUCCESS;
    293 }
    294 
    295 
    296 RTR3DECL(int) RTCrShaCrypt512(const char *pszKey, const char *pszSalt, uint32_t cRounds, uint8_t abHash[RTSHA512_HASH_SIZE])
    297 {
    298     AssertPtrReturn(pszKey,   VERR_INVALID_POINTER);
    299     AssertPtrReturn(pszSalt,  VERR_INVALID_POINTER);
    300     AssertReturn   (cRounds, VERR_INVALID_PARAMETER);
    301 
    302     size_t const cchKey = strlen(pszKey);
    303     AssertReturn(cchKey, VERR_INVALID_PARAMETER);
    304 
    305     size_t cchSalt;
    306     pszSalt = rtCrShaCryptExtractSalt(pszSalt, &cchSalt);
    307     AssertPtrReturn(pszSalt, VERR_INVALID_PARAMETER);
    308 
    309     uint8_t abDigest[RTSHA512_HASH_SIZE];
    310     uint8_t abDigestTemp[RTSHA512_HASH_SIZE];
    311 
    312     RTSHA512CONTEXT Ctx;
    313     RTSha512Init(&Ctx);                                                         /* Step 1. */
    314     RTSha512Update(&Ctx, pszKey, cchKey);                                       /* Step 2. */
    315     RTSha512Update(&Ctx, pszSalt, cchSalt);                                     /* Step 3. */
    316 
    317     RTSHA512CONTEXT CtxAlt;
    318     RTSha512Init(&CtxAlt);                                                      /* Step 4. */
    319     RTSha512Update(&CtxAlt, pszKey, cchKey);                                    /* Step 5. */
    320     RTSha512Update(&CtxAlt, pszSalt, cchSalt);                                  /* Step 6. */
    321     RTSha512Update(&CtxAlt, pszKey, cchKey);                                    /* Step 7. */
    322     RTSha512Final(&CtxAlt, abDigest);                                           /* Step 8. */
    323 
    324     size_t i = cchKey;
    325     for (; i > RTSHA512_HASH_SIZE; i -= RTSHA512_HASH_SIZE)                     /* Step 9. */
    326         RTSha512Update(&Ctx, abDigest, sizeof(abDigest));
    327     RTSha512Update(&Ctx, abDigest, i);                                          /* Step 10. */
    328 
    329     size_t keyBits = cchKey;
    330     while (keyBits)                                                             /* Step 11. */
    331     {
    332         if ((keyBits & 1) != 0)
    333             RTSha512Update(&Ctx, abDigest, sizeof(abDigest));                   /* a) */
    334         else
    335             RTSha512Update(&Ctx, pszKey, cchKey);                               /* b) */
    336         keyBits >>= 1;
    337     }
    338 
    339     RTSha512Final(&Ctx, abDigest);                                              /* Step 12. */
    340 
    341     RTSha512Init(&CtxAlt);                                                      /* Step 13. */
    342     for (i = 0; i < cchKey; i++)                                                /* Step 14. */
    343         RTSha512Update(&CtxAlt, pszKey, cchKey);
    344     RTSha512Final(&CtxAlt, abDigestTemp);                                       /* Step 15. */
    345 
    346     /*
    347      * Byte sequence P (= password).
    348      */
    349     size_t const cbSeqP  = cchKey;
    350     uint8_t     *pabSeqP = (uint8_t *)RTMemDup(pszKey, cbSeqP);
    351     uint8_t     *p       = pabSeqP;
    352     AssertPtrReturn(pabSeqP, VERR_NO_MEMORY);
    353 
    354     for (i = cbSeqP; i > RTSHA512_HASH_SIZE; i -= RTSHA512_HASH_SIZE)           /* Step 16. */
    355     {
    356         memcpy(p, (void *)abDigestTemp, sizeof(abDigestTemp));                  /* a) */
    357         p += RTSHA512_HASH_SIZE;
    358     }
    359     memcpy(p, abDigestTemp, i);                                                 /* b) */
    360 
    361     RTSha512Init(&CtxAlt);                                                      /* Step 17. */
    362 
    363     for (i = 0; i < 16 + (unsigned)abDigest[0]; i++)                            /* Step 18. */
    364         RTSha512Update(&CtxAlt, pszSalt, cchSalt);
    365 
    366     RTSha512Final(&CtxAlt, abDigestTemp);                                       /* Step 19. */
    367 
    368     /*
    369      * Byte sequence S (= salt).
    370      */
    371     size_t   const cbSeqS  = cchSalt;
    372     uint8_t       *pabSeqS = (uint8_t *)RTMemDup(pszSalt, cbSeqS);
    373                    p       = pabSeqS;
    374     AssertPtrReturn(pabSeqS, VERR_NO_MEMORY);
    375 
    376     for (i = cbSeqS; i > RTSHA512_HASH_SIZE; i -= RTSHA512_HASH_SIZE)           /* Step 20. */
    377     {
    378         memcpy(p, (void *)abDigestTemp, sizeof(abDigestTemp));                  /* a) */
    379         p += RTSHA512_HASH_SIZE;
    380     }
    381     memcpy(p, abDigestTemp, i);                                                 /* b) */
    382 
    383     /* Step 21. */
    384     for (uint32_t r = 0; r < cRounds; r++)
     159    for (uint32_t iRound = 0; iRound < cRounds; iRound++)
    385160    {
    386161        RTSHA512CONTEXT CtxC;
    387162        RTSha512Init(&CtxC);                                                    /* a) */
    388163
    389         if ((r & 1) != 0)
     164        if ((iRound & 1) != 0)
    390165            RTSha512Update(&CtxC, pabSeqP, cbSeqP);                             /* b) */
    391166        else
    392167            RTSha512Update(&CtxC, abDigest, sizeof(abDigest));                  /* c) */
    393168
    394         if (r % 3 != 0)                                                         /* d) */
     169        if (iRound % 3 != 0)                                                    /* d) */
    395170            RTSha512Update(&CtxC, pabSeqS, cbSeqS);
    396171
    397         if (r % 7 != 0)
     172        if (iRound % 7 != 0)
    398173            RTSha512Update(&CtxC, pabSeqP, cbSeqP);                             /* e) */
    399174
    400         if ((r & 1) != 0)
     175        if ((iRound & 1) != 0)
    401176            RTSha512Update(&CtxC, abDigest, sizeof(abDigest));                  /* f) */
    402177        else
     
    406181    }
    407182
    408     memcpy(abHash, abDigest, RTSHA512_HASH_SIZE);
    409 
     183    /*
     184     * Done.
     185     */
     186    memcpy(pabHash, abDigest, RTSHA512_HASH_SIZE);
     187
     188    /*
     189     * Cleanup.
     190     */
    410191    RTMemWipeThoroughly(abDigestTemp, RTSHA512_HASH_SIZE, 3);
    411192    RTMemWipeThoroughly(pabSeqP, cbSeqP, 3);
    412     RTMemWipeThoroughly(pabSeqP, cbSeqP, 3);
    413193    RTMemFree(pabSeqP);
     194#if 0
    414195    RTMemWipeThoroughly(pabSeqS, cbSeqS, 3);
    415196    RTMemFree(pabSeqS);
     197#else
     198    RTMemWipeThoroughly(abSeqS, sizeof(abSeqS), 3);
     199#endif
    416200
    417201    return VINF_SUCCESS;
     
    419203
    420204
    421 RTR3DECL(int) RTCrShaCrypt512ToString(uint8_t abHash[RTSHA512_HASH_SIZE], const char *pszSalt, uint32_t cRounds,
    422                                       char *pszString, size_t cchString)
     205RTR3DECL(int) RTCrShaCrypt512ToString(uint8_t const pabHash[RTSHA512_HASH_SIZE], const char *pszSalt, uint32_t cRounds,
     206                                      char *pszString, size_t cbString)
    423207{
    424     AssertPtrReturn(pszSalt,   VERR_INVALID_POINTER);
    425     AssertReturn   (cRounds,   VERR_INVALID_PARAMETER);
    426     AssertReturn   (cchString >= RTSHA512_DIGEST_LEN + 1, VERR_INVALID_PARAMETER);
     208    /*
     209     * Validate and adjust input.
     210     */
     211    AssertPtrReturn(pszSalt, VERR_INVALID_POINTER);
     212    size_t cchSalt;
     213    pszSalt = rtCrShaCryptExtractSaltAndRounds(pszSalt, &cchSalt, &cRounds);
     214    AssertReturn(pszSalt != NULL, VERR_INVALID_PARAMETER);
     215    AssertReturn(cchSalt >= RT_SHACRYPT_SALT_MIN_LEN, VERR_BUFFER_UNDERFLOW);
     216    AssertReturn(cchSalt <= RT_SHACRYPT_SALT_MAX_LEN, VERR_TOO_MUCH_DATA);
     217    AssertReturn(cRounds >= RT_SHACRYPT_ROUNDS_MIN && cRounds <= RT_SHACRYPT_ROUNDS_MAX, VERR_OUT_OF_RANGE);
     218
    427219    AssertPtrReturn(pszString, VERR_INVALID_POINTER);
    428220
    429     char  *psz = pszString;
    430     size_t cch = cchString;
    431 
    432     size_t cchPrefix;
    433     if (cRounds == RT_SHACRYPT_DEFAULT_ROUNDS)
    434         cchPrefix = RTStrPrintf2(psz, cchString, "%s%s$", RT_SHACRYPT_DIGEST_PREFIX_512_STR, pszSalt);
    435     else
    436         cchPrefix = RTStrPrintf2(psz, cchString, "%srounds=%RU32$%s$", RT_SHACRYPT_DIGEST_PREFIX_512_STR, cRounds, pszSalt);
    437     AssertReturn(cchPrefix > 0, VERR_BUFFER_OVERFLOW);
    438     AssertReturn(cch >= cchPrefix, VERR_BUFFER_OVERFLOW);
    439     cch -= cchPrefix;
    440     psz += cchPrefix;
    441 
    442     /* Make sure that there is enough room to store the base64-encoded hash. */
    443     AssertReturn(cch >= ((RTSHA512_HASH_SIZE / 3) * 4) + 1, VERR_BUFFER_OVERFLOW);
    444 
    445     static const char acBase64[64 + 1] =
    446         "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    447 
    448 #define BASE64_ENCODE(a_Val2, a_Val1, a_Val0, a_Cnt) \
    449     do { \
    450         unsigned int w = ((a_Val2) << 16) | ((a_Val1) << 8) | (a_Val0); \
    451         int n = (a_Cnt); \
    452         while (n-- > 0 && cch > 0) \
    453         { \
    454             *psz++ = acBase64[w & 0x3f]; \
    455             --cch; \
    456             w >>= 6; \
    457         } \
    458     } while (0)
    459 
    460     BASE64_ENCODE(abHash[0],  abHash[21], abHash[42], 4);
    461     BASE64_ENCODE(abHash[22], abHash[43], abHash[1], 4);
    462     BASE64_ENCODE(abHash[44], abHash[2],  abHash[23], 4);
    463     BASE64_ENCODE(abHash[3],  abHash[24], abHash[45], 4);
    464     BASE64_ENCODE(abHash[25], abHash[46], abHash[4], 4);
    465     BASE64_ENCODE(abHash[47], abHash[5],  abHash[26], 4);
    466     BASE64_ENCODE(abHash[6],  abHash[27], abHash[48], 4);
    467     BASE64_ENCODE(abHash[28], abHash[49], abHash[7], 4);
    468     BASE64_ENCODE(abHash[50], abHash[8],  abHash[29], 4);
    469     BASE64_ENCODE(abHash[9],  abHash[30], abHash[51], 4);
    470     BASE64_ENCODE(abHash[31], abHash[52], abHash[10], 4);
    471     BASE64_ENCODE(abHash[53], abHash[11], abHash[32], 4);
    472     BASE64_ENCODE(abHash[12], abHash[33], abHash[54], 4);
    473     BASE64_ENCODE(abHash[34], abHash[55], abHash[13], 4);
    474     BASE64_ENCODE(abHash[56], abHash[14], abHash[35], 4);
    475     BASE64_ENCODE(abHash[15], abHash[36], abHash[57], 4);
    476     BASE64_ENCODE(abHash[37], abHash[58], abHash[16], 4);
    477     BASE64_ENCODE(abHash[59], abHash[17], abHash[38], 4);
    478     BASE64_ENCODE(abHash[18], abHash[39], abHash[60], 4);
    479     BASE64_ENCODE(abHash[40], abHash[61], abHash[19], 4);
    480     BASE64_ENCODE(abHash[62], abHash[20], abHash[41], 4);
    481     BASE64_ENCODE(0, 0, abHash[63], 2);
    482 
    483 #undef BASE64_ENCODE
    484 
    485     if (cch)
    486         *psz = '\0';
     221    /*
     222     * Calc the necessary buffer space and check that the caller supplied enough.
     223     */
     224    char    szRounds[64];
     225    ssize_t cchRounds = 0;
     226    if (cRounds != RT_SHACRYPT_ROUNDS_DEFAULT)
     227    {
     228        cchRounds = RTStrFormatU32(szRounds, sizeof(szRounds), cRounds, 10, 0, 0, 0);
     229        Assert(cchRounds > 0 && cchRounds <= 9);
     230    }
     231
     232    size_t const cchNeeded = sizeof(RT_SHACRYPT_ID_STR_512) - 1
     233                           + (cRounds != RT_SHACRYPT_ROUNDS_DEFAULT ? cchRounds + sizeof("rounds=$") - 1 : 0)
     234                           + cchSalt + 1
     235                           + RTSHA512_HASH_SIZE * 4 / 3
     236                           + 1;
     237    AssertReturn(cbString > cchNeeded, VERR_BUFFER_OVERFLOW);
     238
     239    /*
     240     * Do the formatting.
     241     */
     242    memcpy(pszString, RT_STR_TUPLE(RT_SHACRYPT_ID_STR_512));
     243    size_t off = sizeof(RT_SHACRYPT_ID_STR_512) - 1;
     244
     245    if (cRounds != RT_SHACRYPT_ROUNDS_DEFAULT)
     246    {
     247        memcpy(&pszString[off], RT_STR_TUPLE("rounds="));
     248        off += sizeof("rounds=") - 1;
     249
     250        memcpy(&pszString[off], szRounds, cchRounds);
     251        off += cchRounds;
     252        pszString[off++] = '$';
     253    }
     254
     255    memcpy(&pszString[off], pszSalt, cchSalt);
     256    off += cchSalt;
     257    pszString[off++] = '$';
     258
     259    BASE64_ENCODE(pszString, off, pabHash[ 0], pabHash[21], pabHash[42], 4);
     260    BASE64_ENCODE(pszString, off, pabHash[22], pabHash[43], pabHash[ 1], 4);
     261    BASE64_ENCODE(pszString, off, pabHash[44], pabHash[ 2], pabHash[23], 4);
     262    BASE64_ENCODE(pszString, off, pabHash[ 3], pabHash[24], pabHash[45], 4);
     263    BASE64_ENCODE(pszString, off, pabHash[25], pabHash[46], pabHash[ 4], 4);
     264    BASE64_ENCODE(pszString, off, pabHash[47], pabHash[ 5], pabHash[26], 4);
     265    BASE64_ENCODE(pszString, off, pabHash[ 6], pabHash[27], pabHash[48], 4);
     266    BASE64_ENCODE(pszString, off, pabHash[28], pabHash[49], pabHash[ 7], 4);
     267    BASE64_ENCODE(pszString, off, pabHash[50], pabHash[ 8], pabHash[29], 4);
     268    BASE64_ENCODE(pszString, off, pabHash[ 9], pabHash[30], pabHash[51], 4);
     269    BASE64_ENCODE(pszString, off, pabHash[31], pabHash[52], pabHash[10], 4);
     270    BASE64_ENCODE(pszString, off, pabHash[53], pabHash[11], pabHash[32], 4);
     271    BASE64_ENCODE(pszString, off, pabHash[12], pabHash[33], pabHash[54], 4);
     272    BASE64_ENCODE(pszString, off, pabHash[34], pabHash[55], pabHash[13], 4);
     273    BASE64_ENCODE(pszString, off, pabHash[56], pabHash[14], pabHash[35], 4);
     274    BASE64_ENCODE(pszString, off, pabHash[15], pabHash[36], pabHash[57], 4);
     275    BASE64_ENCODE(pszString, off, pabHash[37], pabHash[58], pabHash[16], 4);
     276    BASE64_ENCODE(pszString, off, pabHash[59], pabHash[17], pabHash[38], 4);
     277    BASE64_ENCODE(pszString, off, pabHash[18], pabHash[39], pabHash[60], 4);
     278    BASE64_ENCODE(pszString, off, pabHash[40], pabHash[61], pabHash[19], 4);
     279    BASE64_ENCODE(pszString, off, pabHash[62], pabHash[20], pabHash[41], 4);
     280    BASE64_ENCODE(pszString, off,           0,           0, pabHash[63], 2);
     281
     282    pszString[off] = '\0';
     283    Assert(off < cbString);
    487284
    488285    return VINF_SUCCESS;
  • trunk/src/VBox/Runtime/common/crypto/shacrypt.cpp

    r102375 r102488  
    3939*   Header Files                                                                                                                 *
    4040*********************************************************************************************************************************/
     41#include "internal/iprt.h"
     42#include <iprt/crypto/shacrypt.h>
    4143
    42 #include <iprt/crypto/shacrypt.h>
    43 #include <iprt/types.h>
    4444#include <iprt/mem.h>
    4545#include <iprt/rand.h>
     
    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$"
     50/*********************************************************************************************************************************
     51*   Defined Constants And Macros                                                                                                 *
     52*********************************************************************************************************************************/
     53#define BASE64_ENCODE(a_psz, a_off, a_bVal2, a_bVal1, a_bVal0, a_cOutputChars) \
     54    do { \
     55        uint32_t uWord = RT_MAKE_U32_FROM_MSB_U8(0, a_bVal2, a_bVal1, a_bVal0); \
     56        a_psz[(a_off)++] = g_achCryptBase64[uWord & 0x3f]; \
     57        if ((a_cOutputChars) > 1) \
     58        { \
     59            uWord >>= 6; \
     60            a_psz[(a_off)++] = g_achCryptBase64[uWord & 0x3f]; \
     61        } \
     62        if ((a_cOutputChars) > 2) \
     63        { \
     64            uWord >>= 6; \
     65            a_psz[(a_off)++] = g_achCryptBase64[uWord & 0x3f]; \
     66        } \
     67        if ((a_cOutputChars) > 3) \
     68        { \
     69            uWord >>= 6; \
     70            a_psz[(a_off)++] = g_achCryptBase64[uWord & 0x3f]; \
     71        } \
     72    } while (0)
    5473
    5574
    56 RTR3DECL(int) RTCrShaCryptGenerateSalt(char *pszSalt, size_t cchSalt)
    57 {
    58     AssertMsgReturn(cchSalt >= RT_SHACRYPT_MIN_SALT_LEN && cchSalt <= RT_SHACRYPT_MAX_SALT_LEN, ("len=%zu\n", cchSalt),
    59                     VERR_INVALID_PARAMETER);
    60 
    61     static const char aRange[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890./";
    62     for (size_t i = 0; i < cchSalt; i++)
    63         pszSalt[i] = aRange[RTRandU32Ex(0, sizeof(aRange) - 2)];
    64 
    65     pszSalt[cchSalt] = '\0';
    66     return VINF_SUCCESS;
    67 }
     75/*********************************************************************************************************************************
     76*   Global Variables                                                                                                             *
     77*********************************************************************************************************************************/
     78/** This is the non-standard base-64 encoding characters. */
     79static const char g_achCryptBase64[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
     80AssertCompile(sizeof(g_achCryptBase64) == 64 + 1);
    6881
    6982
     
    7285 *
    7386 * @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).
     87 * @param   pszSalt     The string containing the salt.
     88 * @param   pcchSalt    Where to return the extracted salt length (in
     89 *                      characters).
     90 * @param   pcRounds
    7691 */
    77 static const char *rtCrShaCryptExtractSalt(const char *pszStr, size_t *pcchSalt)
     92static const char *rtCrShaCryptExtractSaltAndRounds(const char *pszSalt, size_t *pcchSalt, uint32_t *pcRounds)
    7893{
    79     size_t cchSalt = strlen(pszStr);
     94    /*
     95     * Skip either of the two SHA-2 prefixes.
     96     */
     97    if (   pszSalt[0] == '$'
     98        && (pszSalt[1] == '5' || pszSalt[1] == '6')
     99        && pszSalt[2] == '$')
     100        pszSalt += 3;
    80101
    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))
     102    /* Look for 'rounds=xxxxx$'. */
     103    if (strncmp(pszSalt, RT_STR_TUPLE("rounds=")) == 0)
    85104    {
    86         cchSalt -= sizeof(RT_SHACRYPT_DIGEST_PREFIX_256_STR) - 1;
    87         pszStr  += sizeof(RT_SHACRYPT_DIGEST_PREFIX_256_STR) - 1;
     105        const char * const pszValue  = &pszSalt[sizeof("rounds=") - 1];
     106        const char * const pszDollar = strchr(pszValue, '$');
     107        if (pszDollar)
     108        {
     109            char *pszNext = NULL;
     110            int rc = RTStrToUInt32Ex(pszValue, &pszNext, 10, pcRounds);
     111            if (rc == VWRN_TRAILING_CHARS && pszNext == pszDollar)
     112            { /* likely */ }
     113            else if (rc == VWRN_NUMBER_TOO_BIG)
     114                *pcRounds = UINT32_MAX;
     115            else
     116                return NULL;
     117            pszSalt = pszDollar + 1;
     118        }
    88119    }
    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
    95120
    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;
     121    /* Find the length of the salt - it sends with '$' or '\0'. */
     122    const char * const pszDollar = strchr(pszSalt, '$');
     123    if (!pszDollar)
     124        *pcchSalt = strlen(pszSalt);
     125    else
     126        *pcchSalt = (size_t)(pszDollar - pszSalt);
     127    return pszSalt;
    106128}
    107129
     130#include "shacrypt-256.cpp.h"
     131#include "shacrypt-512.cpp.h"
    108132
    109 RTR3DECL(int) RTCrShaCrypt256(const char *pszKey, const char *pszSalt, uint32_t cRounds, uint8_t abHash[RTSHA256_HASH_SIZE])
     133
     134RTDECL(int) RTCrShaCryptGenerateSalt(char *pszSalt, size_t cchSalt)
    110135{
    111     AssertPtrReturn(pszKey,   VERR_INVALID_POINTER);
    112     AssertPtrReturn(pszSalt,  VERR_INVALID_POINTER);
    113     AssertReturn   (cRounds, VERR_INVALID_PARAMETER);
     136    AssertMsgReturn(cchSalt >= RT_SHACRYPT_SALT_MIN_LEN && cchSalt <= RT_SHACRYPT_SALT_MAX_LEN, ("len=%zu\n", cchSalt),
     137                    VERR_OUT_OF_RANGE);
    114138
    115     size_t const cchKey     = strlen(pszKey);
    116     AssertReturn(cchKey, VERR_INVALID_PARAMETER);
     139    for (size_t i = 0; i < cchSalt; i++)
     140        pszSalt[i] = g_achCryptBase64[RTRandU32Ex(0, sizeof(g_achCryptBase64) - 2)];
    117141
    118     size_t cchSalt;
    119     pszSalt = rtCrShaCryptExtractSalt(pszSalt, &cchSalt);
    120     AssertPtrReturn(pszSalt, VERR_INVALID_PARAMETER);
    121 
    122     uint8_t abDigest[RTSHA256_HASH_SIZE];
    123     uint8_t abDigestTemp[RTSHA256_HASH_SIZE];
    124 
    125     RTSHA256CONTEXT Ctx;
    126     RTSha256Init(&Ctx);                                                         /* Step 1. */
    127     RTSha256Update(&Ctx, pszKey, cchKey);                                       /* Step 2. */
    128     RTSha256Update(&Ctx, pszSalt, cchSalt);                                     /* Step 3. */
    129 
    130     RTSHA256CONTEXT CtxAlt;
    131     RTSha256Init(&CtxAlt);                                                      /* Step 4. */
    132     RTSha256Update(&CtxAlt, pszKey, cchKey);                                    /* Step 5. */
    133     RTSha256Update(&CtxAlt, pszSalt, cchSalt);                                  /* Step 6. */
    134     RTSha256Update(&CtxAlt, pszKey, cchKey);                                    /* Step 7. */
    135     RTSha256Final(&CtxAlt, abDigest);                                           /* Step 8. */
    136 
    137     size_t i = cchKey;
    138     for (; i > RTSHA256_HASH_SIZE; i -= RTSHA256_HASH_SIZE)                     /* Step 9. */
    139         RTSha256Update(&Ctx, abDigest, sizeof(abDigest));
    140     RTSha256Update(&Ctx, abDigest, i);                                          /* Step 10. */
    141 
    142     size_t keyBits = cchKey;
    143     while (keyBits)                                                             /* Step 11. */
    144     {
    145         if ((keyBits & 1) != 0)
    146             RTSha256Update(&Ctx, abDigest, sizeof(abDigest));                   /* a) */
    147         else
    148             RTSha256Update(&Ctx, pszKey, cchKey);                               /* b) */
    149         keyBits >>= 1;
    150     }
    151 
    152     RTSha256Final(&Ctx, abDigest);                                              /* Step 12. */
    153 
    154     RTSha256Init(&CtxAlt);                                                      /* Step 13. */
    155     for (i = 0; i < cchKey; i++)                                                /* Step 14. */
    156         RTSha256Update(&CtxAlt, pszKey, cchKey);
    157     RTSha256Final(&CtxAlt, abDigestTemp);                                       /* Step 15. */
    158 
    159     /*
    160      * Byte sequence P (= password).
    161      */
    162     size_t const cbSeqP  = cchKey;
    163     uint8_t     *pabSeqP = (uint8_t *)RTMemDup(pszKey, cbSeqP);
    164     uint8_t     *p       = pabSeqP;
    165     AssertPtrReturn(pabSeqP, VERR_NO_MEMORY);
    166 
    167     for (i = cbSeqP; i > RTSHA256_HASH_SIZE; i -= RTSHA256_HASH_SIZE)           /* Step 16. */
    168     {
    169         memcpy(p, (void *)abDigestTemp, sizeof(abDigestTemp));                  /* a) */
    170         p += RTSHA256_HASH_SIZE;
    171     }
    172     memcpy(p, abDigestTemp, i);                                                 /* b) */
    173 
    174     RTSha256Init(&CtxAlt);                                                      /* Step 17. */
    175 
    176     for (i = 0; i < 16 + (unsigned)abDigest[0]; i++)                            /* Step 18. */
    177         RTSha256Update(&CtxAlt, pszSalt, cchSalt);
    178 
    179     RTSha256Final(&CtxAlt, abDigestTemp);                                       /* Step 19. */
    180 
    181     /*
    182      * Byte sequence S (= salt).
    183      */
    184     size_t   const cbSeqS  = cchSalt;
    185     uint8_t       *pabSeqS = (uint8_t *)RTMemDup(pszSalt, cbSeqS);
    186                    p       = pabSeqS;
    187     AssertPtrReturn(pabSeqS, VERR_NO_MEMORY);
    188 
    189     for (i = cbSeqS; i > RTSHA256_HASH_SIZE; i -= RTSHA256_HASH_SIZE)           /* Step 20. */
    190     {
    191         memcpy(p, (void *)abDigestTemp, sizeof(abDigestTemp));                  /* a) */
    192         p += RTSHA256_HASH_SIZE;
    193     }
    194     memcpy(p, abDigestTemp, i);                                                 /* b) */
    195 
    196     /* Step 21. */
    197     for (uint32_t r = 0; r < cRounds; r++)
    198     {
    199         RTSHA256CONTEXT CtxC;
    200         RTSha256Init(&CtxC);                                                    /* a) */
    201 
    202         if ((r & 1) != 0)
    203             RTSha256Update(&CtxC, pabSeqP, cbSeqP);                             /* b) */
    204         else
    205             RTSha256Update(&CtxC, abDigest, sizeof(abDigest));                  /* c) */
    206 
    207         if (r % 3 != 0)                                                         /* d) */
    208             RTSha256Update(&CtxC, pabSeqS, cbSeqS);
    209 
    210         if (r % 7 != 0)
    211             RTSha256Update(&CtxC, pabSeqP, cbSeqP);                             /* e) */
    212 
    213         if ((r & 1) != 0)
    214             RTSha256Update(&CtxC, abDigest, sizeof(abDigest));                  /* f) */
    215         else
    216             RTSha256Update(&CtxC, pabSeqP, cbSeqP);                             /* g) */
    217 
    218         RTSha256Final(&CtxC, abDigest);                                         /* h) */
    219     }
    220 
    221     memcpy(abHash, abDigest, RTSHA256_HASH_SIZE);
    222 
    223     RTMemWipeThoroughly(abDigestTemp, RTSHA256_HASH_SIZE, 3);
    224     RTMemWipeThoroughly(pabSeqP, cbSeqP, 3);
    225     RTMemWipeThoroughly(pabSeqP, cbSeqP, 3);
    226     RTMemFree(pabSeqP);
    227     RTMemWipeThoroughly(pabSeqS, cbSeqS, 3);
    228     RTMemFree(pabSeqS);
    229 
     142    pszSalt[cchSalt] = '\0';
    230143    return VINF_SUCCESS;
    231144}
    232145
    233 
    234 RTR3DECL(int) RTCrShaCrypt256ToString(uint8_t abHash[RTSHA256_HASH_SIZE], const char *pszSalt, uint32_t cRounds,
    235                                       char *pszString, size_t cchString)
    236 {
    237     AssertPtrReturn(pszSalt,   VERR_INVALID_POINTER);
    238     AssertReturn   (cRounds,   VERR_INVALID_PARAMETER);
    239     AssertReturn   (cchString >= RTSHA256_DIGEST_LEN + 1, VERR_INVALID_PARAMETER);
    240     AssertPtrReturn(pszString, VERR_INVALID_POINTER);
    241 
    242     char  *psz = pszString;
    243     size_t cch = cchString;
    244 
    245     *psz = '\0';
    246 
    247     size_t cchPrefix;
    248     if (cRounds == RT_SHACRYPT_DEFAULT_ROUNDS)
    249         cchPrefix = RTStrPrintf2(psz, cchString, "%s%s$", RT_SHACRYPT_DIGEST_PREFIX_256_STR, pszSalt);
    250     else
    251         cchPrefix = RTStrPrintf2(psz, cchString, "%srounds=%RU32$%s$", RT_SHACRYPT_DIGEST_PREFIX_256_STR, cRounds, pszSalt);
    252     AssertReturn(cchPrefix > 0, VERR_BUFFER_OVERFLOW);
    253     AssertReturn(cch >= cchPrefix, VERR_BUFFER_OVERFLOW);
    254     cch -= cchPrefix;
    255     psz += cchPrefix;
    256 
    257     /* Make sure that there is enough room to store the base64-encoded hash. */
    258     AssertReturn(cch >= ((RTSHA256_HASH_SIZE / 3) * 4) + 1, VERR_BUFFER_OVERFLOW);
    259 
    260     static const char acBase64[64 + 1] =
    261         "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    262 
    263 #define BASE64_ENCODE(a_Val2, a_Val1, a_Val0, a_Cnt) \
    264     do { \
    265         unsigned int w = ((a_Val2) << 16) | ((a_Val1) << 8) | (a_Val0); \
    266         int n = (a_Cnt); \
    267         while (n-- > 0 && cch > 0) \
    268         { \
    269             *psz++ = acBase64[w & 0x3f]; \
    270             --cch; \
    271             w >>= 6; \
    272         } \
    273     } while (0)
    274 
    275     BASE64_ENCODE(abHash[0],  abHash[10], abHash[20], 4);
    276     BASE64_ENCODE(abHash[21], abHash[1],  abHash[11], 4);
    277     BASE64_ENCODE(abHash[12], abHash[22], abHash[2], 4);
    278     BASE64_ENCODE(abHash[3],  abHash[13], abHash[23], 4);
    279     BASE64_ENCODE(abHash[24], abHash[4],  abHash[14], 4);
    280     BASE64_ENCODE(abHash[15], abHash[25], abHash[5], 4);
    281     BASE64_ENCODE(abHash[6],  abHash[16], abHash[26], 4);
    282     BASE64_ENCODE(abHash[27], abHash[7],  abHash[17], 4);
    283     BASE64_ENCODE(abHash[18], abHash[28], abHash[8], 4);
    284     BASE64_ENCODE(abHash[9],  abHash[19], abHash[29], 4);
    285     BASE64_ENCODE(0,          abHash[31], abHash[30], 3);
    286 
    287 #undef BASE64_ENCODE
    288 
    289     if (cch)
    290         *psz = '\0';
    291 
    292     return VINF_SUCCESS;
    293 }
    294 
    295 
    296 RTR3DECL(int) RTCrShaCrypt512(const char *pszKey, const char *pszSalt, uint32_t cRounds, uint8_t abHash[RTSHA512_HASH_SIZE])
    297 {
    298     AssertPtrReturn(pszKey,   VERR_INVALID_POINTER);
    299     AssertPtrReturn(pszSalt,  VERR_INVALID_POINTER);
    300     AssertReturn   (cRounds, VERR_INVALID_PARAMETER);
    301 
    302     size_t const cchKey = strlen(pszKey);
    303     AssertReturn(cchKey, VERR_INVALID_PARAMETER);
    304 
    305     size_t cchSalt;
    306     pszSalt = rtCrShaCryptExtractSalt(pszSalt, &cchSalt);
    307     AssertPtrReturn(pszSalt, VERR_INVALID_PARAMETER);
    308 
    309     uint8_t abDigest[RTSHA512_HASH_SIZE];
    310     uint8_t abDigestTemp[RTSHA512_HASH_SIZE];
    311 
    312     RTSHA512CONTEXT Ctx;
    313     RTSha512Init(&Ctx);                                                         /* Step 1. */
    314     RTSha512Update(&Ctx, pszKey, cchKey);                                       /* Step 2. */
    315     RTSha512Update(&Ctx, pszSalt, cchSalt);                                     /* Step 3. */
    316 
    317     RTSHA512CONTEXT CtxAlt;
    318     RTSha512Init(&CtxAlt);                                                      /* Step 4. */
    319     RTSha512Update(&CtxAlt, pszKey, cchKey);                                    /* Step 5. */
    320     RTSha512Update(&CtxAlt, pszSalt, cchSalt);                                  /* Step 6. */
    321     RTSha512Update(&CtxAlt, pszKey, cchKey);                                    /* Step 7. */
    322     RTSha512Final(&CtxAlt, abDigest);                                           /* Step 8. */
    323 
    324     size_t i = cchKey;
    325     for (; i > RTSHA512_HASH_SIZE; i -= RTSHA512_HASH_SIZE)                     /* Step 9. */
    326         RTSha512Update(&Ctx, abDigest, sizeof(abDigest));
    327     RTSha512Update(&Ctx, abDigest, i);                                          /* Step 10. */
    328 
    329     size_t keyBits = cchKey;
    330     while (keyBits)                                                             /* Step 11. */
    331     {
    332         if ((keyBits & 1) != 0)
    333             RTSha512Update(&Ctx, abDigest, sizeof(abDigest));                   /* a) */
    334         else
    335             RTSha512Update(&Ctx, pszKey, cchKey);                               /* b) */
    336         keyBits >>= 1;
    337     }
    338 
    339     RTSha512Final(&Ctx, abDigest);                                              /* Step 12. */
    340 
    341     RTSha512Init(&CtxAlt);                                                      /* Step 13. */
    342     for (i = 0; i < cchKey; i++)                                                /* Step 14. */
    343         RTSha512Update(&CtxAlt, pszKey, cchKey);
    344     RTSha512Final(&CtxAlt, abDigestTemp);                                       /* Step 15. */
    345 
    346     /*
    347      * Byte sequence P (= password).
    348      */
    349     size_t const cbSeqP  = cchKey;
    350     uint8_t     *pabSeqP = (uint8_t *)RTMemDup(pszKey, cbSeqP);
    351     uint8_t     *p       = pabSeqP;
    352     AssertPtrReturn(pabSeqP, VERR_NO_MEMORY);
    353 
    354     for (i = cbSeqP; i > RTSHA512_HASH_SIZE; i -= RTSHA512_HASH_SIZE)           /* Step 16. */
    355     {
    356         memcpy(p, (void *)abDigestTemp, sizeof(abDigestTemp));                  /* a) */
    357         p += RTSHA512_HASH_SIZE;
    358     }
    359     memcpy(p, abDigestTemp, i);                                                 /* b) */
    360 
    361     RTSha512Init(&CtxAlt);                                                      /* Step 17. */
    362 
    363     for (i = 0; i < 16 + (unsigned)abDigest[0]; i++)                            /* Step 18. */
    364         RTSha512Update(&CtxAlt, pszSalt, cchSalt);
    365 
    366     RTSha512Final(&CtxAlt, abDigestTemp);                                       /* Step 19. */
    367 
    368     /*
    369      * Byte sequence S (= salt).
    370      */
    371     size_t   const cbSeqS  = cchSalt;
    372     uint8_t       *pabSeqS = (uint8_t *)RTMemDup(pszSalt, cbSeqS);
    373                    p       = pabSeqS;
    374     AssertPtrReturn(pabSeqS, VERR_NO_MEMORY);
    375 
    376     for (i = cbSeqS; i > RTSHA512_HASH_SIZE; i -= RTSHA512_HASH_SIZE)           /* Step 20. */
    377     {
    378         memcpy(p, (void *)abDigestTemp, sizeof(abDigestTemp));                  /* a) */
    379         p += RTSHA512_HASH_SIZE;
    380     }
    381     memcpy(p, abDigestTemp, i);                                                 /* b) */
    382 
    383     /* Step 21. */
    384     for (uint32_t r = 0; r < cRounds; r++)
    385     {
    386         RTSHA512CONTEXT CtxC;
    387         RTSha512Init(&CtxC);                                                    /* a) */
    388 
    389         if ((r & 1) != 0)
    390             RTSha512Update(&CtxC, pabSeqP, cbSeqP);                             /* b) */
    391         else
    392             RTSha512Update(&CtxC, abDigest, sizeof(abDigest));                  /* c) */
    393 
    394         if (r % 3 != 0)                                                         /* d) */
    395             RTSha512Update(&CtxC, pabSeqS, cbSeqS);
    396 
    397         if (r % 7 != 0)
    398             RTSha512Update(&CtxC, pabSeqP, cbSeqP);                             /* e) */
    399 
    400         if ((r & 1) != 0)
    401             RTSha512Update(&CtxC, abDigest, sizeof(abDigest));                  /* f) */
    402         else
    403             RTSha512Update(&CtxC, pabSeqP, cbSeqP);                             /* g) */
    404 
    405         RTSha512Final(&CtxC, abDigest);                                         /* h) */
    406     }
    407 
    408     memcpy(abHash, abDigest, RTSHA512_HASH_SIZE);
    409 
    410     RTMemWipeThoroughly(abDigestTemp, RTSHA512_HASH_SIZE, 3);
    411     RTMemWipeThoroughly(pabSeqP, cbSeqP, 3);
    412     RTMemWipeThoroughly(pabSeqP, cbSeqP, 3);
    413     RTMemFree(pabSeqP);
    414     RTMemWipeThoroughly(pabSeqS, cbSeqS, 3);
    415     RTMemFree(pabSeqS);
    416 
    417     return VINF_SUCCESS;
    418 }
    419 
    420 
    421 RTR3DECL(int) RTCrShaCrypt512ToString(uint8_t abHash[RTSHA512_HASH_SIZE], const char *pszSalt, uint32_t cRounds,
    422                                       char *pszString, size_t cchString)
    423 {
    424     AssertPtrReturn(pszSalt,   VERR_INVALID_POINTER);
    425     AssertReturn   (cRounds,   VERR_INVALID_PARAMETER);
    426     AssertReturn   (cchString >= RTSHA512_DIGEST_LEN + 1, VERR_INVALID_PARAMETER);
    427     AssertPtrReturn(pszString, VERR_INVALID_POINTER);
    428 
    429     char  *psz = pszString;
    430     size_t cch = cchString;
    431 
    432     size_t cchPrefix;
    433     if (cRounds == RT_SHACRYPT_DEFAULT_ROUNDS)
    434         cchPrefix = RTStrPrintf2(psz, cchString, "%s%s$", RT_SHACRYPT_DIGEST_PREFIX_512_STR, pszSalt);
    435     else
    436         cchPrefix = RTStrPrintf2(psz, cchString, "%srounds=%RU32$%s$", RT_SHACRYPT_DIGEST_PREFIX_512_STR, cRounds, pszSalt);
    437     AssertReturn(cchPrefix > 0, VERR_BUFFER_OVERFLOW);
    438     AssertReturn(cch >= cchPrefix, VERR_BUFFER_OVERFLOW);
    439     cch -= cchPrefix;
    440     psz += cchPrefix;
    441 
    442     /* Make sure that there is enough room to store the base64-encoded hash. */
    443     AssertReturn(cch >= ((RTSHA512_HASH_SIZE / 3) * 4) + 1, VERR_BUFFER_OVERFLOW);
    444 
    445     static const char acBase64[64 + 1] =
    446         "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    447 
    448 #define BASE64_ENCODE(a_Val2, a_Val1, a_Val0, a_Cnt) \
    449     do { \
    450         unsigned int w = ((a_Val2) << 16) | ((a_Val1) << 8) | (a_Val0); \
    451         int n = (a_Cnt); \
    452         while (n-- > 0 && cch > 0) \
    453         { \
    454             *psz++ = acBase64[w & 0x3f]; \
    455             --cch; \
    456             w >>= 6; \
    457         } \
    458     } while (0)
    459 
    460     BASE64_ENCODE(abHash[0],  abHash[21], abHash[42], 4);
    461     BASE64_ENCODE(abHash[22], abHash[43], abHash[1], 4);
    462     BASE64_ENCODE(abHash[44], abHash[2],  abHash[23], 4);
    463     BASE64_ENCODE(abHash[3],  abHash[24], abHash[45], 4);
    464     BASE64_ENCODE(abHash[25], abHash[46], abHash[4], 4);
    465     BASE64_ENCODE(abHash[47], abHash[5],  abHash[26], 4);
    466     BASE64_ENCODE(abHash[6],  abHash[27], abHash[48], 4);
    467     BASE64_ENCODE(abHash[28], abHash[49], abHash[7], 4);
    468     BASE64_ENCODE(abHash[50], abHash[8],  abHash[29], 4);
    469     BASE64_ENCODE(abHash[9],  abHash[30], abHash[51], 4);
    470     BASE64_ENCODE(abHash[31], abHash[52], abHash[10], 4);
    471     BASE64_ENCODE(abHash[53], abHash[11], abHash[32], 4);
    472     BASE64_ENCODE(abHash[12], abHash[33], abHash[54], 4);
    473     BASE64_ENCODE(abHash[34], abHash[55], abHash[13], 4);
    474     BASE64_ENCODE(abHash[56], abHash[14], abHash[35], 4);
    475     BASE64_ENCODE(abHash[15], abHash[36], abHash[57], 4);
    476     BASE64_ENCODE(abHash[37], abHash[58], abHash[16], 4);
    477     BASE64_ENCODE(abHash[59], abHash[17], abHash[38], 4);
    478     BASE64_ENCODE(abHash[18], abHash[39], abHash[60], 4);
    479     BASE64_ENCODE(abHash[40], abHash[61], abHash[19], 4);
    480     BASE64_ENCODE(abHash[62], abHash[20], abHash[41], 4);
    481     BASE64_ENCODE(0, 0, abHash[63], 2);
    482 
    483 #undef BASE64_ENCODE
    484 
    485     if (cch)
    486         *psz = '\0';
    487 
    488     return VINF_SUCCESS;
    489 }
    490 
  • trunk/src/VBox/Runtime/testcase/Makefile.kmk

    r102289 r102488  
    7777        tstRTCritSectRw \
    7878        tstRTCrPkix-1 \
     79        tstRTCrShaCrypt \
    7980        tstRTCrX509-1 \
    8081        tstRTCType \
     
    144145        tstRTSemXRoads \
    145146        tstRTSg \
    146         tstRTShaCrypt \
    147147        tstRTSort \
    148148        tstRTStrAlloc \
     
    838838 tstRTSg_SOURCES = tstRTSg.cpp
    839839
    840  tstRTShaCrypt_TEMPLATE = VBoxR3TstExe
    841  tstRTShaCrypt_SOURCES = tstRTShaCrypt.cpp
     840 tstRTCrShaCrypt_TEMPLATE = VBoxR3TstExe
     841 tstRTCrShaCrypt_SOURCES = tstRTCrShaCrypt.cpp
    842842
    843843 tstRTSort_TEMPLATE = VBoxR3TstExe
  • trunk/src/VBox/Runtime/testcase/tstRTCrShaCrypt.cpp

    r102476 r102488  
    4040*********************************************************************************************************************************/
    4141#include <iprt/crypto/shacrypt.h>
     42
    4243#include <iprt/errcore.h>
    4344#include <iprt/initterm.h>
    4445#include <iprt/rand.h>
    45 #include <iprt/sha.h>
    4646#include <iprt/string.h>
    4747#include <iprt/test.h>
    48 
    49 
    50 /*********************************************************************************************************************************
    51 *   Global Variables                                                                                                             *
    52 *********************************************************************************************************************************/
    53 static RTTEST g_hTest;
    5448
    5549
     
    5953
    6054/** Digest type. */
    61 typedef enum TST_DIGESTTYPE
    62 {
    63     TST_DIGESTTYPE_RANDOM = 0,
    64     TST_DIGESTTYPE_SHA256,
    65     TST_DIGESTTYPE_SHA512,
    66     TST_DIGESTTYPE_LAST
    67 } TST_DIGESTTYPE;
     55typedef enum TSTDIGESTTYPE
     56{
     57    TSTDIGESTTYPE_RANDOM = 0,
     58    TSTDIGESTTYPE_SHA256,
     59    TSTDIGESTTYPE_SHA512,
     60    TSTDIGESTTYPE_END
     61} TSTDIGESTTYPE;
    6862
    6963static struct
     
    7670    uint32_t        cRounds;
    7771    /** Digest type to use. If set to 0, a random digest type will be used. */
    78     TST_DIGESTTYPE enmType;
     72    TSTDIGESTTYPE  enmType;
    7973    /** Overall test outcome. */
    80     int            rc;
     74    int             rc;
    8175    /** Expected result as a string. Can be NULL to skip testing this. */
    82     const char    *pszResultStr;
     76    const char     *pszResult;
    8377} g_aTests[] =
    8478{
     
    8781     */
    8882    {   /* No salt */
    89         /* pszPassword */   "changeme",
    90         /* pszSalt */       "",
    91         /* cRounds */       RT_SHACRYPT_DEFAULT_ROUNDS,
    92         /* enmType */       TST_DIGESTTYPE_RANDOM,
    93         /* rc */            VERR_INVALID_PARAMETER,
    94         /* pszResultStr */  ""
     83        /* .pszPassword = */    "changeme",
     84        /* .pszSalt = */        "",
     85        /* .cRounds = */        RT_SHACRYPT_ROUNDS_DEFAULT,
     86        /* .enmType = */        TSTDIGESTTYPE_RANDOM,
     87        /* .rc = */             VERR_BUFFER_UNDERFLOW,
     88        /* .pszResult = */      ""
    9589    },
    9690    {   /* Salt too short */
    97         /* pszPassword */   "changeme",
    98         /* pszSalt */       "1234",
    99         /* cRounds */       RT_SHACRYPT_DEFAULT_ROUNDS,
    100         /* enmType */       TST_DIGESTTYPE_RANDOM,
    101         /* rc */            VERR_INVALID_PARAMETER,
    102         /* pszResultStr */  ""
     91        /* .pszPassword = */    "changeme",
     92        /* .pszSalt = */        "1234",
     93        /* .cRounds = */        RT_SHACRYPT_ROUNDS_DEFAULT,
     94        /* .enmType = */        TSTDIGESTTYPE_RANDOM,
     95        /* .rc = */             VERR_BUFFER_UNDERFLOW,
     96        /* .pszResult = */      ""
    10397    },
    10498    {   /* Salt too long */
    105         /* pszPassword */   "changeme",
    106         /* pszSalt */       "12341234123412341234123412341234",
    107         /* cRounds */       RT_SHACRYPT_DEFAULT_ROUNDS,
    108         /* enmType */       TST_DIGESTTYPE_RANDOM,
    109         /* rc */            VERR_INVALID_PARAMETER,
    110         /* pszResultStr */  ""
     99        /* .pszPassword = */    "changeme",
     100        /* .pszSalt = */        "12341234123412341234123412341234",
     101        /* .cRounds = */        RT_SHACRYPT_ROUNDS_DEFAULT,
     102        /* .enmType = */        TSTDIGESTTYPE_RANDOM,
     103        /* .rc = */             VERR_TOO_MUCH_DATA,
     104        /* .pszResult = */      ""
    111105    },
    112106    {   /* Invalid rounds */
    113         /* pszPassword */   "changeme",
    114         /* pszSalt */       "12341234123412341234123412341234",
    115         /* cRounds */       0,
    116         /* enmType */       TST_DIGESTTYPE_RANDOM,
    117         /* rc */            VERR_INVALID_PARAMETER,
    118         /* pszResultStr */  ""
     107        /* .pszPassword = */    "changeme",
     108        /* .pszSalt = */        "0123456789abcdef",
     109        /* .cRounds = */        42,
     110        /* .enmType = */        TSTDIGESTTYPE_RANDOM,
     111        /* .rc = */             VERR_OUT_OF_RANGE,
     112        /* .pszResult = */      ""
    119113    },
    120114    /*
    121115     * Valid stuff.
    122116     */
    123     {   /* Expected string */
    124         /* pszPassword */   "changeme",
    125         /* pszSalt */       "foo12345",
    126         /* cRounds */       RT_SHACRYPT_DEFAULT_ROUNDS,
    127         /* enmType */       TST_DIGESTTYPE_SHA256,
    128         /* rc */            VINF_SUCCESS,
    129         /* pszResultStr */  "$5$foo12345$KnOIYJmTgZ744xCqNLl1I9qF.Xq47vHTH.yVStiAMZD"
    130     },
    131     {   /* Expected string */
    132         /* pszPassword */   "changeme",
    133         /* pszSalt */       "foo12345",
    134         /* cRounds */       RT_SHACRYPT_DEFAULT_ROUNDS,
    135         /* enmType */       TST_DIGESTTYPE_SHA512,
    136         /* rc */            VINF_SUCCESS,
    137         /* pszResultStr */  "$6$foo12345$cb11CtCP6YgoZr8SyNoD2TAdOY4OmTzA6kfDgju5JrNVzgeCBU1ALbJHVlEuSImPKAoSnT53N7k7BqzjYRRPk/"
    138     },
    139     {   /* Custom rounds */
    140         /* pszPassword */   "changeme",
    141         /* pszSalt */       "foo12345",
    142         /* cRounds */       42,
    143         /* enmType */       TST_DIGESTTYPE_RANDOM,
    144         /* rc */            VINF_SUCCESS,
    145         /* pszResultStr */  NULL
    146     },
    147     {   /* Random salt + rounds */
    148         /* pszPassword */   "changeme",
    149         /* pszSalt */       NULL,
    150         /* cRounds */       UINT32_MAX,
    151         /* enmType */       TST_DIGESTTYPE_RANDOM,
    152         /* rc */            VINF_SUCCESS,
    153         /* pszResultStr */  NULL
    154     },
    155     {   /* Random salt */
    156         /* pszPassword */   "changeme",
    157         /* pszSalt */       NULL,
    158         /* cRounds */       RT_SHACRYPT_DEFAULT_ROUNDS,
    159         /* enmType */       TST_DIGESTTYPE_RANDOM,
    160         /* rc */            VINF_SUCCESS,
    161         /* pszResultStr */  NULL
     117    {
     118        /* .pszPassword = */    "changeme",
     119        /* .pszSalt = */        "foo12345",
     120        /* .cRounds = */        RT_SHACRYPT_ROUNDS_DEFAULT,
     121        /* .enmType = */        TSTDIGESTTYPE_SHA256,
     122        /* .rc = */             VINF_SUCCESS,
     123        /* .pszResult = */      "$5$foo12345$KnOIYJmTgZ744xCqNLl1I9qF.Xq47vHTH.yVStiAMZD"
     124    },
     125    {
     126        /* .pszPassword = */    "really-secure-semi-long-password",
     127        /* .pszSalt = */        "5288d4774fd14289",
     128        /* .cRounds = */        999663,
     129        /* .enmType = */        TSTDIGESTTYPE_SHA256,
     130        /* .rc = */             VINF_SUCCESS,
     131        /* .pszResult = */      "$5$rounds=999663$5288d4774fd14289$KkMAAPiAFgo9bFHnd79MCnBmMeJXlx02ra4e/20WoC4"
     132    },
     133    {
     134        /* .pszPassword = */    "changeme",
     135        /* .pszSalt = */        "foo12345",
     136        /* .cRounds = */        RT_SHACRYPT_ROUNDS_DEFAULT,
     137        /* .enmType = */        TSTDIGESTTYPE_SHA512,
     138        /* .rc = */             VINF_SUCCESS,
     139        /* .pszResult = */      "$6$foo12345$cb11CtCP6YgoZr8SyNoD2TAdOY4OmTzA6kfDgju5JrNVzgeCBU1ALbJHVlEuSImPKAoSnT53N7k7BqzjYRRPk/"
     140    },
     141    {
     142        /* .pszPassword = */    "really-really-really-really-really-long-and-still-insecure-password",
     143        /* .pszSalt = */        "$6$rounds=384836$AbCdEfGhijKLM",
     144        /* .cRounds = */        RT_SHACRYPT_ROUNDS_DEFAULT,
     145        /* .enmType = */        TSTDIGESTTYPE_SHA512,
     146        /* .rc = */             VINF_SUCCESS,
     147        /* .pszResult = */      "$6$rounds=384836$AbCdEfGhijKLM$pJM6Ugvo4IiVCd8KTmDNIvShHX.G6p0SC/FnBNBAf9TBm1Td/s9HsVu.iWiEBxnEDWiB5zn/NBi6VTqhCP7Ii0"
     148    },
     149    {
     150        /* .pszPassword = */    "이것은 테스트입니다", /* "This is a test" in Korean */
     151        /* .pszSalt = */        "foo12345",
     152        /* .cRounds = */        RT_SHACRYPT_ROUNDS_DEFAULT,
     153        /* .enmType = */        TSTDIGESTTYPE_SHA256,
     154        /* .rc = */             VINF_SUCCESS,
     155        /* .pszResult = */      "$5$foo12345$7fumMsJKgCGipks2nNPi185ANXwfTf9Ilz70J4wKqe1"
     156    },
     157    {
     158        /* .pszPassword = */    "이것은 테스트입니다", /* "This is a test" in Korean */
     159        /* .pszSalt = */        "foo12345",
     160        /* .cRounds = */        RT_SHACRYPT_ROUNDS_DEFAULT,
     161        /* .enmType = */        TSTDIGESTTYPE_SHA512,
     162        /* .rc = */             VINF_SUCCESS,
     163        /* .pszResult = */      "$6$foo12345$IWlIz4tyl39ETRpKlQ.R42tdeB2Ax9gz9sazAynilHDFm0zXUdsrm4nXzdlSd5jJhvwV7EPSc./2pBNoL1PIw1"
     164    },
     165    {
     166        /* .pszPassword = */    "changeme",
     167        /* .pszSalt = */        "foo12345",
     168        /* .cRounds = */        40000,
     169        /* .enmType = */        TSTDIGESTTYPE_RANDOM,
     170        /* .rc = */             VINF_SUCCESS,
     171        /* .pszResult = */      NULL
     172    },
     173    {
     174        /* .pszPassword = */    "changeme",
     175        /* .pszSalt = */        NULL,
     176        /* .cRounds = */        UINT32_MAX,
     177        /* .enmType = */        TSTDIGESTTYPE_RANDOM,
     178        /* .rc = */             VINF_SUCCESS,
     179        /* .pszResult = */      NULL
     180    },
     181    {
     182        /* .pszPassword = */    "changeme",
     183        /* .pszSalt = */        NULL,
     184        /* .cRounds = */        RT_SHACRYPT_ROUNDS_DEFAULT,
     185        /* .enmType = */        TSTDIGESTTYPE_RANDOM,
     186        /* .rc = */             VINF_SUCCESS,
     187        /* .pszResult = */      NULL
    162188    }
    163189};
     190
     191
     192static void test1(RTTEST hTest)
     193{
     194    RTTestDisableAssertions(hTest);
     195
     196    char *pszGuardedSalt = NULL;
     197    int rc = RTTestGuardedAlloc(hTest, RT_SHACRYPT_SALT_MAX_LEN + 1, 1, false, (void **)&pszGuardedSalt);
     198    RTTESTI_CHECK_RC_OK_RETV(rc);
     199
     200    char *pszGuardedResult = NULL;
     201    rc = RTTestGuardedAlloc(hTest, RT_SHACRYPT_512_MAX_SIZE, 1, false, (void **)&pszGuardedResult);
     202    RTTESTI_CHECK_RC_OK_RETV(rc);
     203
     204    for (uint32_t i = 0; i < RT_ELEMENTS(g_aTests); i++)
     205    {
     206        const char *pszSalt = g_aTests[i].pszSalt;
     207        if (!pszSalt)
     208        {
     209            uint32_t const cchSalt = RTRandU32Ex(RT_SHACRYPT_SALT_MIN_LEN, RT_SHACRYPT_SALT_MAX_LEN);
     210            rc = RTCrShaCryptGenerateSalt(&pszGuardedSalt[RT_SHACRYPT_SALT_MAX_LEN - cchSalt], cchSalt);
     211            RTTEST_CHECK_RC_OK(hTest, rc);
     212            pszSalt = &pszGuardedSalt[RT_SHACRYPT_SALT_MAX_LEN - cchSalt];
     213        }
     214
     215        uint32_t cRounds = g_aTests[i].cRounds;
     216        if (cRounds == UINT32_MAX)
     217            cRounds = RTRandU32Ex(RT_SHACRYPT_ROUNDS_MIN, _512K /* Save a bit of time on the testboxes */);
     218
     219        TSTDIGESTTYPE enmType = g_aTests[i].enmType;
     220        if (enmType == TSTDIGESTTYPE_RANDOM)
     221            enmType = (TSTDIGESTTYPE)RTRandU32Ex(TSTDIGESTTYPE_RANDOM + 1, TSTDIGESTTYPE_END - 1);
     222
     223        uint8_t abDigest[RTSHA512_HASH_SIZE];
     224        switch (enmType)
     225        {
     226            case TSTDIGESTTYPE_SHA256:
     227                rc = RTCrShaCrypt256Ex(g_aTests[i].pszPassword, pszSalt, cRounds, abDigest);
     228                break;
     229
     230            case TSTDIGESTTYPE_SHA512:
     231                rc = RTCrShaCrypt512Ex(g_aTests[i].pszPassword, pszSalt, cRounds, abDigest);
     232                break;
     233
     234            default:
     235                AssertFailedStmt(rc = VERR_INTERNAL_ERROR);
     236                break;
     237        }
     238        if (rc != g_aTests[i].rc)
     239            RTTestIFailed("#%u: RTCrShaCryptXxxEx(,%s,%#x,) returns %Rrc, expected %Rrc",
     240                          i, pszSalt, cRounds, rc, g_aTests[i].rc);
     241
     242        if (RT_SUCCESS(rc))
     243        {
     244            RT_BZERO(pszGuardedResult, RT_SHACRYPT_512_MAX_SIZE);
     245            switch (enmType)
     246            {
     247                case TSTDIGESTTYPE_SHA256:
     248                    rc = RTCrShaCrypt256ToString(abDigest, pszSalt, cRounds, pszGuardedResult, RT_SHACRYPT_512_MAX_SIZE);
     249                    break;
     250
     251                case TSTDIGESTTYPE_SHA512:
     252                    rc = RTCrShaCrypt512ToString(abDigest, pszSalt, cRounds, pszGuardedResult, RT_SHACRYPT_512_MAX_SIZE);
     253                    break;
     254
     255                default:
     256                    AssertFailedStmt(rc = VERR_INTERNAL_ERROR);
     257                    break;
     258            }
     259            if (RT_SUCCESS(rc))
     260            {
     261                if (g_aTests[i].pszResult && strcmp(pszGuardedResult, g_aTests[i].pszResult))
     262                    RTTestIFailed("#%u: RTCrShaCryptXxxString returns '%s', expected '%s'",
     263                                  i, pszGuardedResult, g_aTests[i].pszResult);
     264
     265                /*
     266                 * Do a verification round, where we pass the above result in as the salt.
     267                 */
     268                char szResult2[RT_SHACRYPT_512_MAX_SIZE] = {0};
     269                switch (enmType)
     270                {
     271                    case TSTDIGESTTYPE_SHA256:
     272                        rc = RTCrShaCrypt256(g_aTests[i].pszPassword, pszGuardedResult, cRounds, szResult2, sizeof(szResult2));
     273                        break;
     274
     275                    case TSTDIGESTTYPE_SHA512:
     276                        rc = RTCrShaCrypt512(g_aTests[i].pszPassword, pszGuardedResult, cRounds, szResult2, sizeof(szResult2));
     277                        break;
     278
     279                    default:
     280                        AssertFailed();
     281                        break;
     282                }
     283
     284                if (strcmp(szResult2, pszGuardedResult))
     285                    RTTestIFailed("#%u (result as salt): Returns '%s', expected '%s'", i, szResult2, pszGuardedResult);
     286
     287                /*
     288                 * Push the buffer limit on the string formatter.
     289                 */
     290                size_t const cchNeeded = strlen(szResult2);
     291                size_t const cbBufMax  = RT_MIN(RT_SHACRYPT_512_MAX_SIZE, cchNeeded + 32);
     292                for (size_t cbBuf = 0; cbBuf <= cbBufMax; cbBuf++)
     293                {
     294                    char * const pszBuf = &pszGuardedResult[RT_SHACRYPT_512_MAX_SIZE - cbBuf];
     295                    switch (enmType)
     296                    {
     297                        case TSTDIGESTTYPE_SHA256:
     298                            rc = RTCrShaCrypt256ToString(abDigest, pszSalt, cRounds, pszBuf, cbBuf);
     299                            break;
     300                        case TSTDIGESTTYPE_SHA512:
     301                            rc = RTCrShaCrypt512ToString(abDigest, pszSalt, cRounds, pszBuf, cbBuf);
     302                            break;
     303                        default:
     304                            AssertFailedStmt(rc = VERR_INTERNAL_ERROR);
     305                            break;
     306                    }
     307                    int rcExpect = cbBuf <= cchNeeded ? VERR_BUFFER_OVERFLOW : VINF_SUCCESS;
     308                    if (rc != rcExpect)
     309                        RTTestIFailed("#%u: cbBuf=%#zx cchNeeded=%#zx: %Rrc, expected %Rrc", i, cbBuf, cchNeeded, rc, rcExpect);
     310                    if (cbBuf > cchNeeded && memcmp(pszBuf, szResult2, cchNeeded + 1))
     311                        RTTestIFailed("#%u: cbBuf=%#zx cchNeeded=%#zx: '%s', expected '%s'",
     312                                      i, cbBuf, cchNeeded, pszBuf, szResult2);
     313                }
     314            }
     315            else
     316                RTTestIFailed("#%u: RTCrShaCryptXxxString returns %Rrc", i, rc);
     317        }
     318    }
     319
     320    RTTestRestoreAssertions(hTest);
     321}
    164322
    165323
     
    170328     */
    171329    RTTEST hTest;
    172     int rc = RTTestInitAndCreate("tstRTShaCrypt", &hTest);
    173     if (rc)
    174         return rc;
     330    RTEXITCODE rcExit = RTTestInitAndCreate("tstRTShaCrypt", &hTest);
     331    if (rcExit != RTEXITCODE_SUCCESS)
     332        return rcExit;
    175333    RTTestBanner(hTest);
    176     g_hTest = hTest;
    177 
    178     bool const fAssertMayPanic = RTAssertMayPanic();
    179     RTAssertSetMayPanic(false); /* To test invalid stuff. */
    180     bool const fAssertQuiet = RTAssertAreQuiet();
    181     RTAssertSetQuiet(true);     /* Ditto. */
    182 
    183     char    szSalt[RT_SHACRYPT_MAX_SALT_LEN + 1];
    184     uint8_t abDigest[RTSHA512_HASH_SIZE];
    185 
    186     for (uint32_t i = 0; i < RT_ELEMENTS(g_aTests); i++)
    187     {
    188         const char *pszSalt;
    189         if (g_aTests[i].pszSalt)
    190             pszSalt = g_aTests[i].pszSalt;
    191         else
    192         {
    193             rc = RTCrShaCryptGenerateSalt(szSalt, RT_SHACRYPT_MAX_SALT_LEN);
    194             RTTEST_CHECK_RC_OK(hTest, rc);
    195             pszSalt = szSalt;
    196         }
    197 
    198         uint32_t cRounds;
    199         if (g_aTests[i].cRounds == UINT32_MAX)
    200             cRounds = RTRandU32Ex(1, _512K /* Save a bit of time on the testboxes */);
    201         else
    202             cRounds = g_aTests[i].cRounds;
    203 
    204         TST_DIGESTTYPE enmType;
    205         if (g_aTests[i].enmType == TST_DIGESTTYPE_RANDOM)
    206             enmType = (TST_DIGESTTYPE)RTRandU32Ex(1, TST_DIGESTTYPE_LAST - 1);
    207         else
    208             enmType = g_aTests[i].enmType;
    209 
    210         switch (enmType)
    211         {
    212             case TST_DIGESTTYPE_SHA256:
    213                 rc = RTCrShaCrypt256(g_aTests[i].pszPassword, pszSalt, cRounds, abDigest);
    214                 break;
    215 
    216             case TST_DIGESTTYPE_SHA512:
    217                 rc = RTCrShaCrypt512(g_aTests[i].pszPassword, pszSalt, cRounds, abDigest);
    218                 break;
    219 
    220             default:
    221                 AssertFailed();
    222                 break;
    223         }
    224 
    225         if (   RT_SUCCESS(rc)
    226             && g_aTests[i].pszResultStr)
    227         {
    228             char szResult[RTSHA512_DIGEST_LEN + 1];
    229 
    230             switch (enmType)
    231             {
    232                 case TST_DIGESTTYPE_SHA256:
    233                     rc = RTCrShaCrypt256ToString(abDigest, pszSalt, cRounds, szResult, sizeof(szResult));
    234                     break;
    235 
    236                 case TST_DIGESTTYPE_SHA512:
    237                     rc = RTCrShaCrypt512ToString(abDigest, pszSalt, cRounds, szResult, sizeof(szResult));
    238                     break;
    239 
    240                 default:
    241                     AssertFailed();
    242                     break;
    243             }
    244 
    245             if (RT_SUCCESS(rc))
    246             {
    247                 if (RTStrCmp(szResult, g_aTests[i].pszResultStr))
    248                     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 salt): Returns '%s', expected '%s'",
    281                                   i, szResult, g_aTests[i].pszResultStr);
    282             }
    283         }
    284 
    285         if (rc != g_aTests[i].rc)
    286             RTTestIFailed("#%u: Returned %Rrc, expected %Rrc", i, rc, g_aTests[i].rc);
    287     }
    288 
    289     RTAssertSetMayPanic(fAssertMayPanic);
    290     RTAssertSetQuiet(fAssertQuiet);
     334
     335    test1(hTest);
    291336
    292337    /*
  • trunk/src/VBox/Runtime/tools/RTMkPasswd.cpp

    r102344 r102488  
    3535 */
    3636
     37
     38/*********************************************************************************************************************************
     39*   Header Files                                                                                                                 *
     40*********************************************************************************************************************************/
    3741#include <iprt/buildconfig.h>
    3842#include <iprt/crypto/shacrypt.h>
    39 #include <iprt/errcore.h>
     43#include <iprt/err.h>
    4044#include <iprt/initterm.h>
    4145#include <iprt/getopt.h>
     
    4852
    4953
     54/*********************************************************************************************************************************
     55*   Structures and Typedefs                                                                                                      *
     56*********************************************************************************************************************************/
    5057/** Method type. */
    51 typedef enum RTMKPASSWORD_METHODTYPE
     58typedef enum RTMKPASSWDMETHOD
    5259{
    53     RTMKPASSWORD_METHODTYPE_SHA256,
    54     RTMKPASSWORD_METHODTYPE_SHA512
    55 } RTMKPASSWORD_METHODTYPE;
     60    RTMKPASSWDMETHOD_SHA256,
     61    RTMKPASSWDMETHOD_SHA512
     62} RTMKPASSWDMETHOD;
     63
    5664
    5765
     
    7684    AssertRCReturn(rc, RTEXITCODE_INIT);
    7785
    78     const char *pszKey                = NULL;
    79           char   szSalt[RT_SHACRYPT_MAX_SALT_LEN + 1];
    80     const char *pszSalt               = NULL;
    81     uint32_t    cRounds               = RT_SHACRYPT_DEFAULT_ROUNDS;
    82     RTMKPASSWORD_METHODTYPE enmMethod = RTMKPASSWORD_METHODTYPE_SHA512; /* Go with strongest by default. */
     86    const char         *pszKey      = NULL;
     87    const char         *pszSalt     = NULL;
     88    uint32_t            cRounds     = RT_SHACRYPT_ROUNDS_DEFAULT;
     89    RTMKPASSWDMETHOD    enmMethod   = RTMKPASSWDMETHOD_SHA512; /* Go with strongest by default. */
    8390
    8491    int           ch;
     
    9198            {
    9299                if (!pszSalt)
    93                 {
    94100                    pszSalt = ValueUnion.psz;
    95                 }
    96101                else
    97102                    return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Salt already specified!\n");
     
    102107            {
    103108                cRounds = ValueUnion.u32;
    104                 if (cRounds < RT_SHACRYPT_DEFAULT_ROUNDS)
    105                     RTMsgWarning("Using less rounds than the default (%zu) isn't a good idea!!\n",
    106                                  RT_SHACRYPT_DEFAULT_ROUNDS);
     109                if (cRounds < RT_SHACRYPT_ROUNDS_DEFAULT)
     110                    RTMsgWarning("Using less rounds than the default (%u) isn't a good idea!!\n",
     111                                 RT_SHACRYPT_ROUNDS_DEFAULT);
    107112                break;
    108113            }
     
    112117                const char *pszMethod = ValueUnion.psz;
    113118                if (!RTStrICmp(pszMethod, "sha256"))
    114                     enmMethod = RTMKPASSWORD_METHODTYPE_SHA256;
     119                    enmMethod = RTMKPASSWDMETHOD_SHA256;
    115120                else if (!RTStrICmp(pszMethod, "sha512"))
    116                     enmMethod = RTMKPASSWORD_METHODTYPE_SHA512;
     121                    enmMethod = RTMKPASSWDMETHOD_SHA512;
    117122                else if (!RTStrICmp(pszMethod, "help"))
    118123                {
     
    162167    if (!pszKey)
    163168         return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No password specified!\n");
     169
     170    char  szSalt[RT_SHACRYPT_SALT_MAX_LEN + 1];
    164171    if (!pszSalt)
    165172    {
    166         int vrc2 = RTCrShaCryptGenerateSalt(szSalt, RT_SHACRYPT_MAX_SALT_LEN);
     173        int vrc2 = RTCrShaCryptGenerateSalt(szSalt, RT_SHACRYPT_SALT_MAX_LEN);
    167174        AssertRCReturn(vrc2, RTEXITCODE_FAILURE);
    168175        pszSalt = szSalt;
    169176    }
    170     else if (strlen(pszSalt) < RT_SHACRYPT_MIN_SALT_LEN)
    171         return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Salt is too short (must be at least %zu characters)!\n",
    172                               RT_SHACRYPT_MIN_SALT_LEN);
    173     else if (strlen(pszSalt) > RT_SHACRYPT_MAX_SALT_LEN)
    174         return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Salt is too long (must be less or equal than %zu characters)!\n",
    175                               RT_SHACRYPT_MAX_SALT_LEN);
    176 
    177     uint8_t abDigest[RTSHA512_HASH_SIZE];
    178     char    szResult[RTSHA512_DIGEST_LEN + 1];
    179 
     177    else if (strlen(pszSalt) < RT_SHACRYPT_SALT_MIN_LEN)
     178        return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Salt is too short (must be at least %u characters)!\n",
     179                              RT_SHACRYPT_SALT_MIN_LEN);
     180    else if (strlen(pszSalt) > RT_SHACRYPT_SALT_MAX_LEN)
     181        return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Salt is too long (must be less or equal than %u characters)!\n",
     182                              RT_SHACRYPT_SALT_MAX_LEN);
     183
     184    /*
     185     * Do the work.
     186     */
     187    char szResult[RT_SHACRYPT_512_MAX_SIZE];
    180188    switch (enmMethod)
    181189    {
    182         case RTMKPASSWORD_METHODTYPE_SHA256:
    183         {
    184             rc = RTCrShaCrypt256(pszKey, pszSalt, cRounds, abDigest);
    185             if (RT_SUCCESS(rc))
    186                 rc = RTCrShaCrypt256ToString(abDigest, pszSalt, cRounds, szResult, sizeof(szResult));
     190        case RTMKPASSWDMETHOD_SHA256:
     191            rc = RTCrShaCrypt256(pszKey, pszSalt, cRounds, szResult, sizeof(szResult));
    187192            break;
    188         }
    189 
    190         case RTMKPASSWORD_METHODTYPE_SHA512:
    191         {
    192             rc = RTCrShaCrypt512(pszKey, pszSalt, cRounds, abDigest);
    193             if (RT_SUCCESS(rc))
    194                 rc = RTCrShaCrypt512ToString(abDigest, pszSalt, cRounds, szResult, sizeof(szResult));
     193
     194        case RTMKPASSWDMETHOD_SHA512:
     195            rc = RTCrShaCrypt512(pszKey, pszSalt, cRounds, szResult, sizeof(szResult));
    195196            break;
    196         }
    197197
    198198        default:
    199             AssertFailed();
     199            AssertFailedStmt(rc = VERR_INTERNAL_ERROR_3);
    200200            break;
    201201    }
    202202
    203203   if (RT_SUCCESS(rc))
    204    {
    205204        RTPrintf("%s\n", szResult);
    206    }
    207205   else
    208206        RTMsgError("Failed with %Rrc\n", rc);
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