VirtualBox

Ignore:
Timestamp:
Dec 5, 2023 11:53:09 PM (17 months ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
160631
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/Runtime/common/crypto
Files:
1 edited
2 copied

Legend:

Unmodified
Added
Removed
  • 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 
Note: See TracChangeset for help on using the changeset viewer.

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