- Timestamp:
- Dec 5, 2023 11:53:09 PM (14 months ago)
- 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 635 635 int UnattendedScriptTemplate::shaCryptGenerateSalt(char *pszSalt, size_t cchSalt) 636 636 { 637 AssertPtrReturn(pszSalt, VERR_INVALID_POINTER);638 637 #ifdef IN_TST_UNATTENDED_SCRIPT 639 638 /* Use a fixed salt to predict the hashing result with the testcases. */ 640 return RTStr Printf2(pszSalt, cchSalt, "testcase123") > 0 ? VINF_SUCCESS : VERR_BUFFER_OVERFLOW;639 return RTStrCopy(pszSalt, cchSalt + 1, "testcase123"); 641 640 #else 642 641 return RTCrShaCryptGenerateSalt(pszSalt, cchSalt); … … 648 647 #define IS_MATCH(a_szMatch) \ 649 648 (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) \ 652 655 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) \ 657 657 { \ 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(); \ 666 667 } \ 667 668 } while (0) … … 677 678 pszValue = mpUnattended->i_getPassword().c_str(); 678 679 else if (IS_MATCH("USER_PASSWORD_SHACRYPT512")) 679 SHACRYPT_AND_ASSIGN(mpUnattended->i_getPassword().c_str(), RTCrShaCrypt512, RT SHA512_HASH_SIZE);680 SHACRYPT_AND_ASSIGN(mpUnattended->i_getPassword().c_str(), RTCrShaCrypt512, RT_SHACRYPT_512_MAX_SIZE); 680 681 else if (IS_MATCH("ROOT_PASSWORD")) 681 682 pszValue = mpUnattended->i_getPassword().c_str(); 682 683 else if (IS_MATCH("ROOT_PASSWORD_SHACRYPT512")) 683 SHACRYPT_AND_ASSIGN(mpUnattended->i_getPassword().c_str(), RTCrShaCrypt512, RT SHA512_HASH_SIZE);684 SHACRYPT_AND_ASSIGN(mpUnattended->i_getPassword().c_str(), RTCrShaCrypt512, RT_SHACRYPT_512_MAX_SIZE); 684 685 else if (IS_MATCH("USER_FULL_NAME")) 685 686 pszValue = mpUnattended->i_getFullUserName().c_str(); -
trunk/src/VBox/Runtime/common/crypto/shacrypt-256.cpp.h
r102476 r102488 1 1 /* $Id$ */ 2 2 /** @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! 4 7 */ 5 8 … … 36 39 37 40 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) 41 RTDECL(int) RTCrShaCrypt256(const char *pszPhrase, const char *pszSalt, uint32_t cRounds, char *pszString, size_t cbString) 57 42 { 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; 67 48 } 68 49 69 50 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 RTR3DECL(int) RTCrShaCrypt256Ex(const char *pszPhrase, const char *pszSalt, uint32_t cRounds, uint8_t pabHash[RTSHA256_HASH_SIZE]) 78 52 { 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); 118 61 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. */ 122 81 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 123 105 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. */ 158 107 159 108 /* 160 109 * Byte sequence P (= password). 161 110 */ 162 size_t const cbSeqP = cch Key;163 uint8_t *pabSeqP = (uint8_t *)RTMemDup(psz Key, 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; 165 114 AssertPtrReturn(pabSeqP, VERR_NO_MEMORY); 166 115 167 116 for (i = cbSeqP; i > RTSHA256_HASH_SIZE; i -= RTSHA256_HASH_SIZE) /* Step 16. */ 168 117 { 169 memcpy(p , (void *)abDigestTemp, sizeof(abDigestTemp));/* a) */170 p += RTSHA256_HASH_SIZE;171 } 172 memcpy(p , abDigestTemp, i);/* b) */173 174 RTSha256Init(&Ctx Alt);/* 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. */ 175 124 176 125 for (i = 0; i < 16 + (unsigned)abDigest[0]; i++) /* Step 18. */ 177 RTSha256Update(&Ctx Alt, pszSalt, cchSalt);178 179 RTSha256Final(&Ctx Alt, abDigestTemp);/* Step 19. */126 RTSha256Update(&CtxB, pszSalt, cchSalt); 127 128 RTSha256Final(&CtxB, abDigestTemp); /* Step 19. */ 180 129 181 130 /* 182 131 * Byte sequence S (= salt). 183 132 */ 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); 187 141 AssertPtrReturn(pabSeqS, VERR_NO_MEMORY); 188 142 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 195 156 196 157 /* Step 21. */ 197 for (uint32_t r = 0; r < cRounds; r++)158 for (uint32_t iRound = 0; iRound < cRounds; iRound++) 198 159 { 199 160 RTSHA256CONTEXT CtxC; 200 161 RTSha256Init(&CtxC); /* a) */ 201 162 202 if (( r& 1) != 0)163 if ((iRound & 1) != 0) 203 164 RTSha256Update(&CtxC, pabSeqP, cbSeqP); /* b) */ 204 165 else 205 166 RTSha256Update(&CtxC, abDigest, sizeof(abDigest)); /* c) */ 206 167 207 if ( r % 3 != 0)/* d) */168 if (iRound % 3 != 0) /* d) */ 208 169 RTSha256Update(&CtxC, pabSeqS, cbSeqS); 209 170 210 if ( r% 7 != 0)171 if (iRound % 7 != 0) 211 172 RTSha256Update(&CtxC, pabSeqP, cbSeqP); /* e) */ 212 173 213 if (( r& 1) != 0)174 if ((iRound & 1) != 0) 214 175 RTSha256Update(&CtxC, abDigest, sizeof(abDigest)); /* f) */ 215 176 else … … 219 180 } 220 181 221 memcpy(abHash, abDigest, RTSHA256_HASH_SIZE); 222 182 /* 183 * Done. 184 */ 185 memcpy(pabHash, abDigest, RTSHA256_HASH_SIZE); 186 187 /* 188 * Cleanup. 189 */ 223 190 RTMemWipeThoroughly(abDigestTemp, RTSHA256_HASH_SIZE, 3); 224 191 RTMemWipeThoroughly(pabSeqP, cbSeqP, 3); 225 RTMemWipeThoroughly(pabSeqP, cbSeqP, 3);226 192 RTMemFree(pabSeqP); 193 #if 0 227 194 RTMemWipeThoroughly(pabSeqS, cbSeqS, 3); 228 195 RTMemFree(pabSeqS); 196 #else 197 RTMemWipeThoroughly(abSeqS, sizeof(abSeqS), 3); 198 #endif 229 199 230 200 return VINF_SUCCESS; … … 232 202 233 203 234 RTR3DECL(int) RTCrShaCrypt256ToString(uint8_t abHash[RTSHA256_HASH_SIZE], const char *pszSalt, uint32_t cRounds,235 char *pszString, size_t c chString)204 RTR3DECL(int) RTCrShaCrypt256ToString(uint8_t const pabHash[RTSHA256_HASH_SIZE], const char *pszSalt, uint32_t cRounds, 205 char *pszString, size_t cbString) 236 206 { 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 240 218 AssertPtrReturn(pszString, VERR_INVALID_POINTER); 241 219 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); 291 272 292 273 return VINF_SUCCESS; 293 274 } 294 275 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 else335 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 else392 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 else403 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 else436 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_ENCODE484 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 1 1 /* $Id$ */ 2 2 /** @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! 4 7 */ 5 8 … … 36 39 37 40 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) 41 RTDECL(int) RTCrShaCrypt512(const char *pszPhrase, const char *pszSalt, uint32_t cRounds, char *pszString, size_t cbString) 57 42 { 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; 67 48 } 68 49 69 50 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 52 RTR3DECL(int) RTCrShaCrypt512Ex(const char *pszPhrase, const char *pszSalt, uint32_t cRounds, uint8_t pabHash[RTSHA512_HASH_SIZE]) 78 53 { 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); 118 62 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) */ 147 95 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. */ 158 108 159 109 /* 160 110 * Byte sequence P (= password). 161 111 */ 162 size_t const cbSeqP = cch Key;163 uint8_t *pabSeqP = (uint8_t *)RTMemDup(psz Key, 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; 165 115 AssertPtrReturn(pabSeqP, VERR_NO_MEMORY); 166 116 167 for (i = cbSeqP; i > RTSHA 256_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 RTSha 256Init(&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. */ 175 125 176 126 for (i = 0; i < 16 + (unsigned)abDigest[0]; i++) /* Step 18. */ 177 RTSha 256Update(&CtxAlt, pszSalt, cchSalt);178 179 RTSha 256Final(&CtxAlt, abDigestTemp);/* Step 19. */127 RTSha512Update(&CtxB, pszSalt, cchSalt); 128 129 RTSha512Final(&CtxB, abDigestTemp); /* Step 19. */ 180 130 181 131 /* 182 132 * Byte sequence S (= salt). 183 133 */ 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); 187 142 AssertPtrReturn(pabSeqS, VERR_NO_MEMORY); 188 143 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 195 157 196 158 /* 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++) 385 160 { 386 161 RTSHA512CONTEXT CtxC; 387 162 RTSha512Init(&CtxC); /* a) */ 388 163 389 if (( r& 1) != 0)164 if ((iRound & 1) != 0) 390 165 RTSha512Update(&CtxC, pabSeqP, cbSeqP); /* b) */ 391 166 else 392 167 RTSha512Update(&CtxC, abDigest, sizeof(abDigest)); /* c) */ 393 168 394 if ( r % 3 != 0)/* d) */169 if (iRound % 3 != 0) /* d) */ 395 170 RTSha512Update(&CtxC, pabSeqS, cbSeqS); 396 171 397 if ( r% 7 != 0)172 if (iRound % 7 != 0) 398 173 RTSha512Update(&CtxC, pabSeqP, cbSeqP); /* e) */ 399 174 400 if (( r& 1) != 0)175 if ((iRound & 1) != 0) 401 176 RTSha512Update(&CtxC, abDigest, sizeof(abDigest)); /* f) */ 402 177 else … … 406 181 } 407 182 408 memcpy(abHash, abDigest, RTSHA512_HASH_SIZE); 409 183 /* 184 * Done. 185 */ 186 memcpy(pabHash, abDigest, RTSHA512_HASH_SIZE); 187 188 /* 189 * Cleanup. 190 */ 410 191 RTMemWipeThoroughly(abDigestTemp, RTSHA512_HASH_SIZE, 3); 411 192 RTMemWipeThoroughly(pabSeqP, cbSeqP, 3); 412 RTMemWipeThoroughly(pabSeqP, cbSeqP, 3);413 193 RTMemFree(pabSeqP); 194 #if 0 414 195 RTMemWipeThoroughly(pabSeqS, cbSeqS, 3); 415 196 RTMemFree(pabSeqS); 197 #else 198 RTMemWipeThoroughly(abSeqS, sizeof(abSeqS), 3); 199 #endif 416 200 417 201 return VINF_SUCCESS; … … 419 203 420 204 421 RTR3DECL(int) RTCrShaCrypt512ToString(uint8_t abHash[RTSHA512_HASH_SIZE], const char *pszSalt, uint32_t cRounds,422 char *pszString, size_t c chString)205 RTR3DECL(int) RTCrShaCrypt512ToString(uint8_t const pabHash[RTSHA512_HASH_SIZE], const char *pszSalt, uint32_t cRounds, 206 char *pszString, size_t cbString) 423 207 { 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 427 219 AssertPtrReturn(pszString, VERR_INVALID_POINTER); 428 220 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); 487 284 488 285 return VINF_SUCCESS; -
trunk/src/VBox/Runtime/common/crypto/shacrypt.cpp
r102375 r102488 39 39 * Header Files * 40 40 *********************************************************************************************************************************/ 41 #include "internal/iprt.h" 42 #include <iprt/crypto/shacrypt.h> 41 43 42 #include <iprt/crypto/shacrypt.h>43 #include <iprt/types.h>44 44 #include <iprt/mem.h> 45 45 #include <iprt/rand.h> … … 48 48 49 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$" 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) 54 73 55 74 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. */ 79 static const char g_achCryptBase64[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 80 AssertCompile(sizeof(g_achCryptBase64) == 64 + 1); 68 81 69 82 … … 72 85 * 73 86 * @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 76 91 */ 77 static const char *rtCrShaCryptExtractSalt (const char *pszStr, size_t *pcchSalt)92 static const char *rtCrShaCryptExtractSaltAndRounds(const char *pszSalt, size_t *pcchSalt, uint32_t *pcRounds) 78 93 { 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; 80 101 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) 85 104 { 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 } 88 119 } 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_WITH95 120 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; 106 128 } 107 129 130 #include "shacrypt-256.cpp.h" 131 #include "shacrypt-512.cpp.h" 108 132 109 RTR3DECL(int) RTCrShaCrypt256(const char *pszKey, const char *pszSalt, uint32_t cRounds, uint8_t abHash[RTSHA256_HASH_SIZE]) 133 134 RTDECL(int) RTCrShaCryptGenerateSalt(char *pszSalt, size_t cchSalt) 110 135 { 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); 114 138 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)]; 117 141 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'; 230 143 return VINF_SUCCESS; 231 144 } 232 145 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 else251 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_ENCODE288 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 else335 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 else392 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 else403 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 else436 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_ENCODE484 485 if (cch)486 *psz = '\0';487 488 return VINF_SUCCESS;489 }490 -
trunk/src/VBox/Runtime/testcase/Makefile.kmk
r102289 r102488 77 77 tstRTCritSectRw \ 78 78 tstRTCrPkix-1 \ 79 tstRTCrShaCrypt \ 79 80 tstRTCrX509-1 \ 80 81 tstRTCType \ … … 144 145 tstRTSemXRoads \ 145 146 tstRTSg \ 146 tstRTShaCrypt \147 147 tstRTSort \ 148 148 tstRTStrAlloc \ … … 838 838 tstRTSg_SOURCES = tstRTSg.cpp 839 839 840 tstRT ShaCrypt_TEMPLATE = VBoxR3TstExe841 tstRT ShaCrypt_SOURCES = tstRTShaCrypt.cpp840 tstRTCrShaCrypt_TEMPLATE = VBoxR3TstExe 841 tstRTCrShaCrypt_SOURCES = tstRTCrShaCrypt.cpp 842 842 843 843 tstRTSort_TEMPLATE = VBoxR3TstExe -
trunk/src/VBox/Runtime/testcase/tstRTCrShaCrypt.cpp
r102476 r102488 40 40 *********************************************************************************************************************************/ 41 41 #include <iprt/crypto/shacrypt.h> 42 42 43 #include <iprt/errcore.h> 43 44 #include <iprt/initterm.h> 44 45 #include <iprt/rand.h> 45 #include <iprt/sha.h>46 46 #include <iprt/string.h> 47 47 #include <iprt/test.h> 48 49 50 /*********************************************************************************************************************************51 * Global Variables *52 *********************************************************************************************************************************/53 static RTTEST g_hTest;54 48 55 49 … … 59 53 60 54 /** Digest type. */ 61 typedef enum TST _DIGESTTYPE62 { 63 TST _DIGESTTYPE_RANDOM = 0,64 TST _DIGESTTYPE_SHA256,65 TST _DIGESTTYPE_SHA512,66 TST _DIGESTTYPE_LAST67 } TST _DIGESTTYPE;55 typedef enum TSTDIGESTTYPE 56 { 57 TSTDIGESTTYPE_RANDOM = 0, 58 TSTDIGESTTYPE_SHA256, 59 TSTDIGESTTYPE_SHA512, 60 TSTDIGESTTYPE_END 61 } TSTDIGESTTYPE; 68 62 69 63 static struct … … 76 70 uint32_t cRounds; 77 71 /** Digest type to use. If set to 0, a random digest type will be used. */ 78 TST _DIGESTTYPEenmType;72 TSTDIGESTTYPE enmType; 79 73 /** Overall test outcome. */ 80 int rc;74 int rc; 81 75 /** Expected result as a string. Can be NULL to skip testing this. */ 82 const char *pszResultStr;76 const char *pszResult; 83 77 } g_aTests[] = 84 78 { … … 87 81 */ 88 82 { /* 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 = */ "" 95 89 }, 96 90 { /* 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 = */ "" 103 97 }, 104 98 { /* 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 = */ "" 111 105 }, 112 106 { /* 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 = */ "" 119 113 }, 120 114 /* 121 115 * Valid stuff. 122 116 */ 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 162 188 } 163 189 }; 190 191 192 static 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 } 164 322 165 323 … … 170 328 */ 171 329 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; 175 333 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); 291 336 292 337 /* -
trunk/src/VBox/Runtime/tools/RTMkPasswd.cpp
r102344 r102488 35 35 */ 36 36 37 38 /********************************************************************************************************************************* 39 * Header Files * 40 *********************************************************************************************************************************/ 37 41 #include <iprt/buildconfig.h> 38 42 #include <iprt/crypto/shacrypt.h> 39 #include <iprt/err core.h>43 #include <iprt/err.h> 40 44 #include <iprt/initterm.h> 41 45 #include <iprt/getopt.h> … … 48 52 49 53 54 /********************************************************************************************************************************* 55 * Structures and Typedefs * 56 *********************************************************************************************************************************/ 50 57 /** Method type. */ 51 typedef enum RTMKPASSW ORD_METHODTYPE58 typedef enum RTMKPASSWDMETHOD 52 59 { 53 RTMKPASSWORD_METHODTYPE_SHA256, 54 RTMKPASSWORD_METHODTYPE_SHA512 55 } RTMKPASSWORD_METHODTYPE; 60 RTMKPASSWDMETHOD_SHA256, 61 RTMKPASSWDMETHOD_SHA512 62 } RTMKPASSWDMETHOD; 63 56 64 57 65 … … 76 84 AssertRCReturn(rc, RTEXITCODE_INIT); 77 85 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. */ 83 90 84 91 int ch; … … 91 98 { 92 99 if (!pszSalt) 93 {94 100 pszSalt = ValueUnion.psz; 95 }96 101 else 97 102 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Salt already specified!\n"); … … 102 107 { 103 108 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); 107 112 break; 108 113 } … … 112 117 const char *pszMethod = ValueUnion.psz; 113 118 if (!RTStrICmp(pszMethod, "sha256")) 114 enmMethod = RTMKPASSW ORD_METHODTYPE_SHA256;119 enmMethod = RTMKPASSWDMETHOD_SHA256; 115 120 else if (!RTStrICmp(pszMethod, "sha512")) 116 enmMethod = RTMKPASSW ORD_METHODTYPE_SHA512;121 enmMethod = RTMKPASSWDMETHOD_SHA512; 117 122 else if (!RTStrICmp(pszMethod, "help")) 118 123 { … … 162 167 if (!pszKey) 163 168 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No password specified!\n"); 169 170 char szSalt[RT_SHACRYPT_SALT_MAX_LEN + 1]; 164 171 if (!pszSalt) 165 172 { 166 int vrc2 = RTCrShaCryptGenerateSalt(szSalt, RT_SHACRYPT_ MAX_SALT_LEN);173 int vrc2 = RTCrShaCryptGenerateSalt(szSalt, RT_SHACRYPT_SALT_MAX_LEN); 167 174 AssertRCReturn(vrc2, RTEXITCODE_FAILURE); 168 175 pszSalt = szSalt; 169 176 } 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]; 180 188 switch (enmMethod) 181 189 { 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)); 187 192 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)); 195 196 break; 196 }197 197 198 198 default: 199 AssertFailed ();199 AssertFailedStmt(rc = VERR_INTERNAL_ERROR_3); 200 200 break; 201 201 } 202 202 203 203 if (RT_SUCCESS(rc)) 204 {205 204 RTPrintf("%s\n", szResult); 206 }207 205 else 208 206 RTMsgError("Failed with %Rrc\n", rc);
Note:
See TracChangeset
for help on using the changeset viewer.