Changeset 102488 in vbox for trunk/src/VBox/Runtime/common/crypto
- Timestamp:
- Dec 5, 2023 11:53:09 PM (17 months ago)
- svn:sync-xref-src-repo-rev:
- 160631
- 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 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
Note:
See TracChangeset
for help on using the changeset viewer.