/*********************************************************** single function to calculate an HMAC MD5 digest from data using optimised hmacmd5 init method because the key is 16 bytes. ************************************************************/ void hmac_md5(const unsigned char *key, const unsigned char *data, int data_len, unsigned char *digest) { HMACMD5Context ctx; hmac_md5_init_K16(key, &ctx); if (data_len != 0) hmac_md5_update(data, data_len, &ctx); hmac_md5_final(digest, &ctx); }
/* Calculate the LMv2 response for the given challenge, using the specified authentication identity (username and domain), password and client nonce. */ static int crypt_all(int *pcount, struct db_salt *salt) { int count = *pcount; int i = 0; #ifdef _OPENMP #pragma omp parallel for for(i = 0; i < count; i++) #endif { unsigned char ntlm_v2_hash[16]; HMACMD5Context ctx; // can't be moved above the OMP pragma if (!keys_prepared) { int len; unsigned char ntlm[16]; /* Generate 16-byte NTLM hash */ len = E_md4hash(saved_plain[i], saved_len[i], ntlm); // We do key setup of the next HMAC_MD5 here (once per salt) hmac_md5_init_K16(ntlm, &saved_ctx[i]); if (len <= 0) saved_plain[i][-len] = 0; // match truncation } /* HMAC-MD5(Username + Domain, NTLM Hash) */ memcpy(&ctx, &saved_ctx[i], sizeof(ctx)); hmac_md5_update(&challenge[17], (int)challenge[16], &ctx); hmac_md5_final(ntlm_v2_hash, &ctx); /* Generate 16-byte non-client nonce portion of LMv2 Response */ /* HMAC-MD5(Challenge + Nonce, NTLMv2 Hash) + Nonce */ hmac_md5(ntlm_v2_hash, challenge, 16, (unsigned char*)output[i]); } keys_prepared = 1; return count; }
/* Calculate the NTLMv2 response for the given challenge, using the specified authentication identity (username and domain), password and client nonce. challenge: Identity length, Identity\0, Challenge Size, Server Challenge + Client Challenge */ static int crypt_all(int *pcount, struct db_salt *salt) { int count = *pcount; int identity_length, challenge_size; int i = 0; /* --- HMAC #1 Calculations --- */ identity_length = challenge[0]; challenge_size = (*(challenge + 1 + identity_length + 1) << 8) | *(challenge + 1 + identity_length + 2); #ifdef _OPENMP #pragma omp parallel for for(i=0; i<count; i++) #endif { unsigned char ntlm_v2_hash[16]; HMACMD5Context ctx; if (!keys_prepared) { unsigned char ntlm[16]; int len; /* Generate 16-byte NTLM hash */ len = E_md4hash(saved_plain[i], saved_len[i], ntlm); // We do key setup of the next HMAC_MD5 here (once per salt) hmac_md5_init_K16(ntlm, &saved_ctx[i]); if (len <= 0) saved_plain[i][-len] = 0; // match truncation } /* HMAC-MD5(Username + Domain, NTLM Hash) */ memcpy(&ctx, &saved_ctx[i], sizeof(ctx)); hmac_md5_update((unsigned char *)&challenge[1], identity_length, &ctx); hmac_md5_final(ntlm_v2_hash, &ctx); /* --- Blob Construction --- */ /* The blob consists of the target (from Type 2 message), client nonce and timestamp. This data was provided by the client during authentication and we can use it as is. */ /* --- HMAC #2 Caculations --- */ /* The (server) challenge from the Type 2 message is concatenated with the blob. The HMAC-MD5 message authentication code algorithm is applied to this value using the 16-byte NTLMv2 hash (calculated above) as the key. This results in a 16-byte output value. */ /* Generate 16-byte non-client nonce portion of NTLMv2 Response HMAC-MD5(Challenge + Nonce, NTLMv2 Hash) The length of the challenge was set in get_salt(). We find the server challenge and blob following the identity and challenge size value. challenge -> Identity length, Identity\0, Size (2 bytes), Server Challenge + Client Challenge (Blob) */ hmac_md5(ntlm_v2_hash, challenge + 1 + identity_length + 1 + 2, challenge_size, (unsigned char*)output[i]); } keys_prepared = 1; return count; }