void derive_key_sha512 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *dk, int dklen) { char u[SHA512_DIGESTSIZE]; int b, l, r; if (dklen % SHA512_DIGESTSIZE) { l = 1 + dklen / SHA512_DIGESTSIZE; } else { l = dklen / SHA512_DIGESTSIZE; } r = dklen - (l - 1) * SHA512_DIGESTSIZE; /* first l - 1 blocks */ for (b = 1; b < l; b++) { derive_u_sha512 (pwd, pwd_len, salt, salt_len, iterations, u, b); memcpy (dk, u, SHA512_DIGESTSIZE); dk += SHA512_DIGESTSIZE; } /* last block */ derive_u_sha512 (pwd, pwd_len, salt, salt_len, iterations, u, b); memcpy (dk, u, r); /* Prevent possible leaks. */ burn (u, sizeof(u)); }
void derive_key_sha512 (char *pwd, int pwd_len, char *salt, int salt_len, uint32 iterations, char *dk, int dklen) { hmac_sha512_ctx hmac; int b, l, r; char key[SHA512_DIGESTSIZE]; /* If the password is longer than the hash algorithm block size, let pwd = sha512(pwd), as per HMAC specifications. */ if (pwd_len > SHA512_BLOCKSIZE) { sha512_ctx tctx; sha512_begin (&tctx); sha512_hash ((unsigned char *) pwd, pwd_len, &tctx); sha512_end ((unsigned char *) key, &tctx); pwd = key; pwd_len = SHA512_DIGESTSIZE; burn (&tctx, sizeof(tctx)); // Prevent leaks } if (dklen % SHA512_DIGESTSIZE) { l = 1 + dklen / SHA512_DIGESTSIZE; } else { l = dklen / SHA512_DIGESTSIZE; } r = dklen - (l - 1) * SHA512_DIGESTSIZE; /* first l - 1 blocks */ for (b = 1; b < l; b++) { derive_u_sha512 (pwd, pwd_len, salt, salt_len, iterations, b, &hmac); memcpy (dk, hmac.u, SHA512_DIGESTSIZE); dk += SHA512_DIGESTSIZE; } /* last block */ derive_u_sha512 (pwd, pwd_len, salt, salt_len, iterations, b, &hmac); memcpy (dk, hmac.u, r); /* Prevent possible leaks. */ burn (&hmac, sizeof(hmac)); burn (key, sizeof(key)); }