void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, const struct nls_table *nls_cp) { int rc; struct ntlmv2_resp *buf = (struct ntlmv2_resp *)resp_buf; struct HMACMD5Context context; buf->blob_signature = cpu_to_le32(0x00000101); buf->reserved = 0; buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); get_random_bytes(&buf->client_chal, sizeof(buf->client_chal)); buf->reserved2 = 0; buf->names[0].type = cpu_to_le16(NTLMSSP_DOMAIN_TYPE); buf->names[0].length = 0; buf->names[1].type = 0; buf->names[1].length = 0; /* calculate buf->ntlmv2_hash */ rc = calc_ntlmv2_hash(ses, nls_cp); if (rc) cERROR(1, "could not get v2 hash rc %d", rc); CalcNTLMv2_response(ses, resp_buf); /* now calculate the MAC key for NTLMv2 */ hmac_md5_init_limK_to_64(ses->server->ntlmv2_hash, 16, &context); hmac_md5_update(resp_buf, 16, &context); hmac_md5_final(ses->server->mac_signing_key.data.ntlmv2.key, &context); memcpy(&ses->server->mac_signing_key.data.ntlmv2.resp, resp_buf, sizeof(struct ntlmv2_resp)); ses->server->mac_signing_key.len = 16 + sizeof(struct ntlmv2_resp); }
/* Does the NTLMv2 owfs of a user's password */ #if 0 /* function not needed yet - but will be soon */ static void ntv2_owf_gen(const unsigned char owf[16], const char *user_n, const char *domain_n, unsigned char kr_buf[16], const struct nls_table *nls_codepage) { wchar_t *user_u; wchar_t *dom_u; int user_l, domain_l; struct HMACMD5Context ctx; /* might as well do one alloc to hold both (user_u and dom_u) */ user_u = kmalloc(2048 * sizeof(wchar_t), GFP_KERNEL); if (user_u == NULL) return; dom_u = user_u + 1024; /* push_ucs2(NULL, user_u, user_n, (user_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER); push_ucs2(NULL, dom_u, domain_n, (domain_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER); */ /* BB user and domain may need to be uppercased */ user_l = cifs_strtoUCS(user_u, user_n, 511, nls_codepage); domain_l = cifs_strtoUCS(dom_u, domain_n, 511, nls_codepage); user_l++; /* trailing null */ domain_l++; hmac_md5_init_limK_to_64(owf, 16, &ctx); hmac_md5_update((const unsigned char *) user_u, user_l * 2, &ctx); hmac_md5_update((const unsigned char *) dom_u, domain_l * 2, &ctx); hmac_md5_final(kr_buf, &ctx); kfree(user_u); }
/* initialise the credentials state for ADS-style 128 bit session keys this call is made after the netr_ServerReqChallenge call */ static void creds_init_128bit(struct creds_CredentialState *creds, const struct netr_Credential *client_challenge, const struct netr_Credential *server_challenge, const struct samr_Password *machine_password) { unsigned char zero[4], tmp[16]; HMACMD5Context ctx; struct MD5Context md5; ZERO_STRUCT(creds->session_key); memset(zero, 0, sizeof(zero)); hmac_md5_init_rfc2104(machine_password->hash, sizeof(machine_password->hash), &ctx); MD5Init(&md5); MD5Update(&md5, zero, sizeof(zero)); MD5Update(&md5, client_challenge->data, 8); MD5Update(&md5, server_challenge->data, 8); MD5Final(tmp, &md5); hmac_md5_update(tmp, sizeof(tmp), &ctx); hmac_md5_final(creds->session_key, &ctx); creds->client = *client_challenge; creds->server = *server_challenge; des_crypt112(creds->client.data, client_challenge->data, creds->session_key, 1); des_crypt112(creds->server.data, server_challenge->data, creds->session_key, 1); creds->seed = creds->client; }
static int calc_ntlmv2_hash(struct cifsSesInfo *ses, const struct nls_table *nls_cp) { int rc = 0; int len; char nt_hash[16]; struct HMACMD5Context *pctxt; wchar_t *user; wchar_t *domain; pctxt = kmalloc(sizeof(struct HMACMD5Context), GFP_KERNEL); if (pctxt == NULL) return -ENOMEM; /* calculate md4 hash of password */ E_md4hash(ses->password, nt_hash); /* convert Domainname to unicode and uppercase */ hmac_md5_init_limK_to_64(nt_hash, 16, pctxt); /* convert ses->userName to unicode and uppercase */ len = strlen(ses->userName); user = kmalloc(2 + (len * 2), GFP_KERNEL); if (user == NULL) goto calc_exit_2; len = cifs_strtoUCS((__le16 *)user, ses->userName, len, nls_cp); UniStrupr(user); hmac_md5_update((char *)user, 2*len, pctxt); /* convert ses->domainName to unicode and uppercase */ if (ses->domainName) { len = strlen(ses->domainName); domain = kmalloc(2 + (len * 2), GFP_KERNEL); if (domain == NULL) goto calc_exit_1; len = cifs_strtoUCS((__le16 *)domain, ses->domainName, len, nls_cp); /* the following line was removed since it didn't work well with lower cased domain name that passed as an option. Maybe converting the domain name earlier makes sense */ /* UniStrupr(domain); */ hmac_md5_update((char *)domain, 2*len, pctxt); kfree(domain); } calc_exit_1: kfree(user); calc_exit_2: /* BB FIXME what about bytes 24 through 40 of the signing key? compare with the NTLM example */ hmac_md5_final(ses->server->ntlmv2_hash, pctxt); kfree(pctxt); return rc; }
void hmac_md5(unsigned char key[16], unsigned char *data, int data_len, unsigned char *digest) { HMACMD5Context ctx; hmac_md5_init_limK_to_64(key, 16, &ctx); if (data_len != 0) { hmac_md5_update(data, data_len, &ctx); } hmac_md5_final(digest, &ctx); }
int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *ses, const struct nls_table *nls_info) { char temp_hash[16]; struct HMACMD5Context ctx; char *ucase_buf; __le16 *unicode_buf; unsigned int i, user_name_len, dom_name_len; if (ses == NULL) return -EINVAL; E_md4hash(ses->password, temp_hash); hmac_md5_init_limK_to_64(temp_hash, 16, &ctx); user_name_len = strlen(ses->userName); if (user_name_len > MAX_USERNAME_SIZE) return -EINVAL; if (ses->domainName == NULL) return -EINVAL; /* BB should we use CIFS_LINUX_DOM */ dom_name_len = strlen(ses->domainName); if (dom_name_len > MAX_USERNAME_SIZE) return -EINVAL; ucase_buf = kmalloc((MAX_USERNAME_SIZE+1), GFP_KERNEL); if (ucase_buf == NULL) return -ENOMEM; unicode_buf = kmalloc((MAX_USERNAME_SIZE+1)*4, GFP_KERNEL); if (unicode_buf == NULL) { kfree(ucase_buf); return -ENOMEM; } for (i = 0; i < user_name_len; i++) ucase_buf[i] = nls_info->charset2upper[(int)ses->userName[i]]; ucase_buf[i] = 0; user_name_len = cifs_strtoUCS(unicode_buf, ucase_buf, MAX_USERNAME_SIZE*2, nls_info); unicode_buf[user_name_len] = 0; user_name_len++; for (i = 0; i < dom_name_len; i++) ucase_buf[i] = nls_info->charset2upper[(int)ses->domainName[i]]; ucase_buf[i] = 0; dom_name_len = cifs_strtoUCS(unicode_buf+user_name_len, ucase_buf, MAX_USERNAME_SIZE*2, nls_info); unicode_buf[user_name_len + dom_name_len] = 0; hmac_md5_update((const unsigned char *) unicode_buf, (user_name_len+dom_name_len)*2, &ctx); hmac_md5_final(ses->server->ntlmv2_hash, &ctx); kfree(ucase_buf); kfree(unicode_buf); return 0; }
static void SMBsesskeygen_ntv2(const unsigned char kr[16], const unsigned char *nt_resp, __u8 sess_key[16]) { struct HMACMD5Context ctx; hmac_md5_init_limK_to_64(kr, 16, &ctx); hmac_md5_update(nt_resp, 16, &ctx); hmac_md5_final((unsigned char *) sess_key, &ctx); }
/* One step hmac computation * * digest may be same as text or key */ void hmac_md5(const unsigned char *text, int text_len, const unsigned char *key, int key_len, unsigned char digest[HMAC_MD5_SIZE]) { HMAC_MD5_CTX hmac; hmac_md5_init(&hmac, key, key_len); hmac_md5_update(&hmac, text, text_len); hmac_md5_final(digest, &hmac); }
/*********************************************************** 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); }
/*********************************************************** single function to calculate an HMAC MD5 digest from data. use the microsoft hmacmd5 init method because the key is 16 bytes. ************************************************************/ _PUBLIC_ void hmac_md5(const uint8_t key[16], const uint8_t *data, int data_len, uint8_t *digest) { HMACMD5Context ctx; hmac_md5_init_limK_to_64(key, 16, &ctx); if (data_len != 0) { hmac_md5_update(data, data_len, &ctx); } hmac_md5_final(digest, &ctx); }
/* Does both the NTLMv2 owfs of a user's password */ bool ntv2_owf_gen(const uchar owf[16], const char *user_in, const char *domain_in, bool upper_case_domain, /* Transform the domain into UPPER case */ uchar kr_buf[16]) { smb_ucs2_t *user; smb_ucs2_t *domain; size_t user_byte_len; size_t domain_byte_len; HMACMD5Context ctx; if (!push_ucs2_allocate(&user, user_in, &user_byte_len)) { DEBUG(0, ("push_uss2_allocate() for user failed: %s\n", strerror(errno))); return False; } if (!push_ucs2_allocate(&domain, domain_in, &domain_byte_len)) { DEBUG(0, ("push_uss2_allocate() for domain failed: %s\n", strerror(errno))); SAFE_FREE(user); return False; } strupper_w(user); if (upper_case_domain) strupper_w(domain); SMB_ASSERT(user_byte_len >= 2); SMB_ASSERT(domain_byte_len >= 2); /* We don't want null termination */ user_byte_len = user_byte_len - 2; domain_byte_len = domain_byte_len - 2; hmac_md5_init_limK_to_64(owf, 16, &ctx); hmac_md5_update((const unsigned char *)user, user_byte_len, &ctx); hmac_md5_update((const unsigned char *)domain, domain_byte_len, &ctx); hmac_md5_final(kr_buf, &ctx); #ifdef DEBUG_PASSWORD DEBUG(100, ("ntv2_owf_gen: user, domain, owfkey, kr\n")); dump_data(100, (uint8 *)user, user_byte_len); dump_data(100, (uint8 *)domain, domain_byte_len); dump_data(100, (uint8 *)owf, 16); dump_data(100, (uint8 *)kr_buf, 16); #endif SAFE_FREE(user); SAFE_FREE(domain); return True; }
void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_response) { struct HMACMD5Context context; memcpy(v2_session_response + 8, ses->server->cryptKey,8); /* gen_blob(v2_session_response + 16); */ hmac_md5_init_limK_to_64(ses->server->mac_signing_key, 16, &context); hmac_md5_update(ses->server->cryptKey,8,&context); /* hmac_md5_update(v2_session_response+16)client thing,8,&context); */ /* BB fix */ hmac_md5_final(v2_session_response,&context); }
static void SMBOWFencrypt_ntv2(const unsigned char kr[16], const struct data_blob *srv_chal, const struct data_blob *cli_chal, unsigned char resp_buf[16]) { struct HMACMD5Context ctx; hmac_md5_init_limK_to_64(kr, 16, &ctx); hmac_md5_update(srv_chal->data, srv_chal->length, &ctx); hmac_md5_update(cli_chal->data, cli_chal->length, &ctx); hmac_md5_final(resp_buf, &ctx); }
static void ntlm_v2_hash(const char *user, const char *target, const unsigned char *hash_v1, unsigned char hash[NTLMSSP_V2_HASH_SIZE]) { struct hmac_md5_context ctx; hmac_md5_init(&ctx, hash_v1, NTLMSSP_HASH_SIZE); hmac_md5_ucs2le_string_ucase(&ctx, user); if (target) hmac_md5_ucs2le_string_ucase(&ctx, target); hmac_md5_final(&ctx, hash); }
void CalcNTLMv2_response(const struct cifsSesInfo * ses, char * v2_session_response) { struct HMACMD5Context context; /* rest of v2 struct already generated */ memcpy(v2_session_response + 8, ses->server->cryptKey,8); hmac_md5_init_limK_to_64(ses->server->mac_signing_key, 16, &context); hmac_md5_update(v2_session_response+8, sizeof(struct ntlmv2_resp) - 8, &context); hmac_md5_final(v2_session_response,&context); /* cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */ }
void hmac_md5(const char *msg, const unsigned int msg_len, unsigned char *hmac, const char *hmac_key, const int hmac_key_len) { hmac_md5_ctx ctx; memset(&ctx, 0, sizeof(ctx)); hmac_md5_init(&ctx, hmac_key, hmac_key_len); hmac_md5_update(&ctx, msg, msg_len); hmac_md5_final(&ctx, hmac); return; }
void SMBsesskeygen_ntv2(const uint8_t kr[16], const uint8_t * nt_resp, uint8_t sess_key[16]) { /* a very nice, 128 bit, variable session key */ HMACMD5Context ctx; hmac_md5_init_limK_to_64(kr, 16, &ctx); hmac_md5_update(nt_resp, 16, &ctx); hmac_md5_final((uint8_t *)sess_key, &ctx); #ifdef DEBUG_PASSWORD DEBUG(100, ("SMBsesskeygen_ntv2:\n")); dump_data(100, sess_key, 16); #endif }
static void creds_init_128(struct dcinfo *dc, const DOM_CHAL *clnt_chal_in, const DOM_CHAL *srv_chal_in, const unsigned char mach_pw[16]) { unsigned char zero[4], tmp[16]; HMACMD5Context ctx; struct MD5Context md5; /* Just in case this isn't already there */ memcpy(dc->mach_pw, mach_pw, 16); ZERO_STRUCT(dc->sess_key); memset(zero, 0, sizeof(zero)); hmac_md5_init_rfc2104(mach_pw, 16, &ctx); MD5Init(&md5); MD5Update(&md5, zero, sizeof(zero)); MD5Update(&md5, clnt_chal_in->data, 8); MD5Update(&md5, srv_chal_in->data, 8); MD5Final(tmp, &md5); hmac_md5_update(tmp, sizeof(tmp), &ctx); hmac_md5_final(dc->sess_key, &ctx); /* debug output */ DEBUG(5,("creds_init_128\n")); DEBUG(5,("\tclnt_chal_in: %s\n", credstr(clnt_chal_in->data))); DEBUG(5,("\tsrv_chal_in : %s\n", credstr(srv_chal_in->data))); dump_data_pw("\tsession_key ", (const unsigned char *)dc->sess_key, 16); /* Generate the next client and server creds. */ des_crypt112(dc->clnt_chal.data, /* output */ clnt_chal_in->data, /* input */ dc->sess_key, /* input */ 1); des_crypt112(dc->srv_chal.data, /* output */ srv_chal_in->data, /* input */ dc->sess_key, /* input */ 1); /* Seed is the client chal. */ memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8); }
void smb_key_derivation(const uint8_t *KI, size_t KI_len, uint8_t KO[16]) { static const uint8_t SSKeyHash[256] = { 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x79, 0x07, 0x6e, 0x28, 0x2e, 0x69, 0x88, 0x10, 0xb3, 0xdb, 0x01, 0x55, 0x72, 0xfb, 0x74, 0x14, 0xfb, 0xc4, 0xc5, 0xaf, 0x3b, 0x41, 0x65, 0x32, 0x17, 0xba, 0xa3, 0x29, 0x08, 0xc1, 0xde, 0x16, 0x61, 0x7e, 0x66, 0x98, 0xa4, 0x0b, 0xfe, 0x06, 0x83, 0x53, 0x4d, 0x05, 0xdf, 0x6d, 0xa7, 0x51, 0x10, 0x73, 0xc5, 0x50, 0xdc, 0x5e, 0xf8, 0x21, 0x46, 0xaa, 0x96, 0x14, 0x33, 0xd7, 0x52, 0xeb, 0xaf, 0x1f, 0xbf, 0x36, 0x6c, 0xfc, 0xb7, 0x1d, 0x21, 0x19, 0x81, 0xd0, 0x6b, 0xfa, 0x77, 0xad, 0xbe, 0x18, 0x78, 0xcf, 0x10, 0xbd, 0xd8, 0x78, 0xf7, 0xd3, 0xc6, 0xdf, 0x43, 0x32, 0x19, 0xd3, 0x9b, 0xa8, 0x4d, 0x9e, 0xaa, 0x41, 0xaf, 0xcb, 0xc6, 0xb9, 0x34, 0xe7, 0x48, 0x25, 0xd4, 0x88, 0xc4, 0x51, 0x60, 0x38, 0xd9, 0x62, 0xe8, 0x8d, 0x5b, 0x83, 0x92, 0x7f, 0xb5, 0x0e, 0x1c, 0x2d, 0x06, 0x91, 0xc3, 0x75, 0xb3, 0xcc, 0xf8, 0xf7, 0x92, 0x91, 0x0b, 0x3d, 0xa1, 0x10, 0x5b, 0xd5, 0x0f, 0xa8, 0x3f, 0x5d, 0x13, 0x83, 0x0a, 0x6b, 0x72, 0x93, 0x14, 0x59, 0xd5, 0xab, 0xde, 0x26, 0x15, 0x6d, 0x60, 0x67, 0x71, 0x06, 0x6e, 0x3d, 0x0d, 0xa7, 0xcb, 0x70, 0xe9, 0x08, 0x5c, 0x99, 0xfa, 0x0a, 0x5f, 0x3d, 0x44, 0xa3, 0x8b, 0xc0, 0x8d, 0xda, 0xe2, 0x68, 0xd0, 0x0d, 0xcd, 0x7f, 0x3d, 0xf8, 0x73, 0x7e, 0x35, 0x7f, 0x07, 0x02, 0x0a, 0xb5, 0xe9, 0xb7, 0x87, 0xfb, 0xa1, 0xbf, 0xcb, 0x32, 0x31, 0x66, 0x09, 0x48, 0x88, 0xcc, 0x18, 0xa3, 0xb2, 0x1f, 0x1f, 0x1b, 0x90, 0x4e, 0xd7, 0xe1 }; HMACMD5Context ctx; hmac_md5_init_limK_to_64(KI, KI_len, &ctx); hmac_md5_update(SSKeyHash, sizeof(SSKeyHash), &ctx); hmac_md5_final(KO, &ctx); ZERO_STRUCT(ctx); }
static NTSTATUS ntlmssp_make_packet_signature(NTLMSSP_STATE *ntlmssp_state, const uchar *data, size_t length, enum ntlmssp_direction direction, DATA_BLOB *sig) { if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) { HMACMD5Context ctx; uchar seq_num[4]; uchar digest[16]; SIVAL(seq_num, 0, ntlmssp_state->ntlmssp_seq_num); hmac_md5_init_limK_to_64((const unsigned char *)(ntlmssp_state->send_sign_const), 16, &ctx); hmac_md5_update(seq_num, 4, &ctx); hmac_md5_update(data, length, &ctx); hmac_md5_final(digest, &ctx); if (!msrpc_gen(sig, "dBd", NTLMSSP_SIGN_VERSION, digest, 8 /* only copy first 8 bytes */ , ntlmssp_state->ntlmssp_seq_num)) { return NT_STATUS_NO_MEMORY; } if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) { switch (direction) { case NTLMSSP_SEND: NTLMSSPcalc_ap(ntlmssp_state->send_sign_hash, sig->data+4, sig->length-4); break; case NTLMSSP_RECEIVE: NTLMSSPcalc_ap(ntlmssp_state->recv_sign_hash, sig->data+4, sig->length-4); break; } } } else { uint32 crc; crc = crc32_calc_buffer((const char *)data, length); if (!msrpc_gen(sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlmssp_seq_num)) { return NT_STATUS_NO_MEMORY; } dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash, sizeof(ntlmssp_state->ntlmssp_hash)); NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, sig->data+4, sig->length-4); } return NT_STATUS_OK; }
/* Does the md5 encryption from the Key Response for NTLMv2. */ void SMBOWFencrypt_ntv2(const uint8_t kr[16], const DATA_BLOB *srv_chal, const DATA_BLOB *smbcli_chal, uint8_t resp_buf[16]) { HMACMD5Context ctx; hmac_md5_init_limK_to_64(kr, 16, &ctx); hmac_md5_update(srv_chal->data, srv_chal->length, &ctx); hmac_md5_update(smbcli_chal->data, smbcli_chal->length, &ctx); hmac_md5_final(resp_buf, &ctx); #ifdef DEBUG_PASSWORD DEBUG(100, ("SMBOWFencrypt_ntv2: srv_chal, smbcli_chal, resp_buf\n")); dump_data(100, srv_chal->data, srv_chal->length); dump_data(100, smbcli_chal->data, smbcli_chal->length); dump_data(100, resp_buf, 16); #endif }
void ntlmssp_v2_response(const char *user, const char *target, const unsigned char *hash_v1, const unsigned char *challenge, const unsigned char *blob, size_t blob_size, unsigned char response[NTLMSSP_V2_RESPONSE_SIZE]) { struct hmac_md5_context ctx; unsigned char hash[NTLMSSP_V2_HASH_SIZE]; ntlm_v2_hash(user, target, hash_v1, hash); hmac_md5_init(&ctx, hash, NTLMSSP_V2_HASH_SIZE); hmac_md5_update(&ctx, challenge, NTLMSSP_CHALLENGE_SIZE); hmac_md5_update(&ctx, blob, blob_size); hmac_md5_final(&ctx, response); safe_memset(hash, 0, sizeof(hash)); }
/* 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; }
/* Calculate the NTLMv2 response for the given challenge, using the specified authentication identity (username and domain), password and client nonce. challenge: Identity \0 Challenge Size \0 Server Challenge + Client Challenge */ static void netntlmv2_crypt_all(int count) { HMACMD5Context ctx; unsigned char ntlm[16]; unsigned char ntlm_v2_hash[16]; uchar *identity = NULL; int identity_length = 0; int16 identity_usc[129]; int identity_usc_length = 0; int challenge_size = 0; memset(ntlm, 0, 16); memset(ntlm_v2_hash, 0, 16); memset(output, 0, 16); memset(identity_usc, 0, 129); identity_usc_length = 0; /* --- HMAC #1 Caculations --- */ /* Convert identity (username + domain) string to NT unicode */ identity_length = strlen((char *)challenge); identity = challenge; ntlmv2_mbstowcs(identity_usc, identity, identity_length); identity_usc_length = ntlmv2_wcslen(identity_usc) * sizeof(int16); /* Generate 16-byte NTLM hash */ E_md4hash(saved_plain, ntlm); /* Generate 16-byte NTLMv2 Hash */ /* HMAC-MD5(Username + Domain, NTLM Hash) */ hmac_md5_init_limK_to_64(ntlm, 16, &ctx); hmac_md5_update((const unsigned char *)identity_usc, identity_usc_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 netntlmv2_get_salt(). We find the server challenge and blob following the identity and challenge size value. challenge -> Identity \0 Size (2 bytes) \0 Server Challenge + Client Challenge (Blob) */ challenge_size = (*(challenge + identity_length + 1) << 8) | *(challenge + identity_length + 2); hmac_md5_init_limK_to_64(ntlm_v2_hash, 16, &ctx); hmac_md5_update(challenge + identity_length + 1 + 2 + 1, challenge_size, &ctx); hmac_md5_final(output, &ctx); }
/* Does both the NTLMv2 owfs of a user's password */ tree_cell * nasl_ntv2_owf_gen (lex_ctxt * lexic) { const uchar *owf_in = (uchar *) get_str_var_by_name (lexic, "owf"); int owf_in_len = get_var_size_by_name (lexic, "owf"); char *user_in = get_str_var_by_name (lexic, "login"); int user_in_len = get_var_size_by_name (lexic, "login"); char *domain_in = get_str_var_by_name (lexic, "domain"); int domain_len = get_var_size_by_name (lexic, "domain"); char *src_user, *src_domain; smb_ucs2_t *user, *dst_user, val_user; smb_ucs2_t *domain, *dst_domain, val_domain; int i; size_t user_byte_len; size_t domain_byte_len; tree_cell *retc; uchar *kr_buf; HMACMD5Context ctx; if (owf_in_len < 0 || owf_in == NULL || user_in_len < 0 || user_in == NULL || domain_len < 0 || domain_in == NULL) { nasl_perror (lexic, "Syntax : ntv2_owf_gen(owf:<o>, login:<l>, domain:<d>)\n"); return NULL; } assert (owf_in_len == 16); user_byte_len = sizeof (smb_ucs2_t) * (strlen (user_in) + 1); user = emalloc (user_byte_len); dst_user = user; src_user = user_in; for (i = 0; i < user_in_len; i++) { val_user = *src_user; *dst_user = val_user; dst_user++; src_user++; if (val_user == 0) break; } domain_byte_len = sizeof (smb_ucs2_t) * (strlen (domain_in) + 1); domain = emalloc (domain_byte_len); dst_domain = domain; src_domain = domain_in; for (i = 0; i < domain_len; i++) { val_domain = *src_domain; *dst_domain = val_domain; dst_domain++; src_domain++; if (val_domain == 0) break; } strupper_w (user); strupper_w (domain); assert (user_byte_len >= 2); assert (domain_byte_len >= 2); /* We don't want null termination */ user_byte_len = user_byte_len - 2; domain_byte_len = domain_byte_len - 2; kr_buf = emalloc (16); hmac_md5_init_limK_to_64 (owf_in, 16, &ctx); hmac_md5_update ((const unsigned char *) user, user_byte_len, &ctx); hmac_md5_update ((const unsigned char *) domain, domain_byte_len, &ctx); hmac_md5_final (kr_buf, &ctx); efree (&user); efree (&domain); retc = alloc_tree_cell (0, NULL); retc->type = CONST_DATA; retc->size = 16; retc->x.str_val = (char *) kr_buf; return retc; }
/* Does both the NTLMv2 owfs of a user's password */ bool ntv2_owf_gen(const uint8_t owf[16], const char *user_in, const char *domain_in, uint8_t kr_buf[16]) { smb_ucs2_t *user; smb_ucs2_t *domain; size_t user_byte_len; size_t domain_byte_len; bool ret; HMACMD5Context ctx; TALLOC_CTX *mem_ctx = talloc_init("ntv2_owf_gen for %s\\%s", domain_in, user_in); if (!mem_ctx) { return false; } if (!user_in) { user_in = ""; } if (!domain_in) { domain_in = ""; } user_in = strupper_talloc(mem_ctx, user_in); if (user_in == NULL) { talloc_free(mem_ctx); return false; } ret = push_ucs2_talloc(mem_ctx, &user, user_in, &user_byte_len ); if (!ret) { DEBUG(0, ("push_uss2_talloc() for user failed)\n")); talloc_free(mem_ctx); return false; } ret = push_ucs2_talloc(mem_ctx, &domain, domain_in, &domain_byte_len); if (!ret) { DEBUG(0, ("push_ucs2_talloc() for domain failed\n")); talloc_free(mem_ctx); return false; } SMB_ASSERT(user_byte_len >= 2); SMB_ASSERT(domain_byte_len >= 2); /* We don't want null termination */ user_byte_len = user_byte_len - 2; domain_byte_len = domain_byte_len - 2; hmac_md5_init_limK_to_64(owf, 16, &ctx); hmac_md5_update((uint8_t *)user, user_byte_len, &ctx); hmac_md5_update((uint8_t *)domain, domain_byte_len, &ctx); hmac_md5_final(kr_buf, &ctx); #ifdef DEBUG_PASSWORD DEBUG(100, ("ntv2_owf_gen: user, domain, owfkey, kr\n")); dump_data(100, (uint8_t *)user, user_byte_len); dump_data(100, (uint8_t *)domain, domain_byte_len); dump_data(100, owf, 16); dump_data(100, kr_buf, 16); #endif talloc_free(mem_ctx); return true; }
/* This uses the test values from rfc 2104, 2202 */ bool torture_local_crypto_hmacmd5(struct torture_context *torture) { bool ret = true; uint32_t i; struct { DATA_BLOB key; DATA_BLOB data; DATA_BLOB md5; } testarray[8]; TALLOC_CTX *tctx = talloc_new(torture); if (!tctx) { return false; }; testarray[0].key = data_blob_repeat_byte(0x0b, 16); testarray[0].data = data_blob_string_const("Hi There"); testarray[0].md5 = strhex_to_data_blob(tctx, "9294727a3638bb1c13f48ef8158bfc9d"); testarray[1].key = data_blob_string_const("Jefe"); testarray[1].data = data_blob_string_const("what do ya want for nothing?"); testarray[1].md5 = strhex_to_data_blob(tctx, "750c783e6ab0b503eaa86e310a5db738"); testarray[2].key = data_blob_repeat_byte(0xaa, 16); testarray[2].data = data_blob_repeat_byte(0xdd, 50); testarray[2].md5 = strhex_to_data_blob(tctx, "56be34521d144c88dbb8c733f0e8b3f6"); testarray[3].key = strhex_to_data_blob(tctx, "0102030405060708090a0b0c0d0e0f10111213141516171819"); testarray[3].data = data_blob_repeat_byte(0xcd, 50); testarray[3].md5 = strhex_to_data_blob(tctx, "697eaf0aca3a3aea3a75164746ffaa79"); testarray[4].key = data_blob_repeat_byte(0x0c, 16); testarray[4].data = data_blob_string_const("Test With Truncation"); testarray[4].md5 = strhex_to_data_blob(tctx, "56461ef2342edc00f9bab995690efd4c"); testarray[5].key = data_blob_repeat_byte(0xaa, 80); testarray[5].data = data_blob_string_const("Test Using Larger Than Block-Size Key - Hash Key First"); testarray[5].md5 = strhex_to_data_blob(tctx, "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd"); testarray[6].key = data_blob_repeat_byte(0xaa, 80); testarray[6].data = data_blob_string_const("Test Using Larger Than Block-Size Key " "and Larger Than One Block-Size Data"); testarray[6].md5 = strhex_to_data_blob(tctx, "6f630fad67cda0ee1fb1f562db3aa53e"); testarray[7].key = data_blob(NULL, 0); for (i=0; testarray[i].key.data; i++) { HMACMD5Context ctx; uint8_t md5[16]; int e; hmac_md5_init_rfc2104(testarray[i].key.data, testarray[i].key.length, &ctx); hmac_md5_update(testarray[i].data.data, testarray[i].data.length, &ctx); hmac_md5_final(md5, &ctx); e = memcmp(testarray[i].md5.data, md5, MIN(testarray[i].md5.length, sizeof(md5))); if (e != 0) { printf("hmacmd5 test[%u]: failed\n", i); dump_data(0, testarray[i].key.data, testarray[i].key.length); dump_data(0, testarray[i].data.data, testarray[i].data.length); dump_data(0, testarray[i].md5.data, testarray[i].md5.length); dump_data(0, md5, sizeof(md5)); ret = false; } } talloc_free(tctx); return ret; }
static NTSTATUS ntlmssp_make_packet_signature(NTLMSSP_STATE *ntlmssp_state, const uchar *data, size_t length, const uchar *whole_pdu, size_t pdu_length, enum ntlmssp_direction direction, DATA_BLOB *sig, bool encrypt_sig) { if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) { HMACMD5Context ctx; uchar seq_num[4]; uchar digest[16]; *sig = data_blob(NULL, NTLMSSP_SIG_SIZE); if (!sig->data) { return NT_STATUS_NO_MEMORY; } switch (direction) { case NTLMSSP_SEND: DEBUG(100,("ntlmssp_make_packet_signature: SEND seq = %u, len = %u, pdu_len = %u\n", ntlmssp_state->ntlm2_send_seq_num, (unsigned int)length, (unsigned int)pdu_length)); SIVAL(seq_num, 0, ntlmssp_state->ntlm2_send_seq_num); ntlmssp_state->ntlm2_send_seq_num++; hmac_md5_init_limK_to_64(ntlmssp_state->send_sign_key, 16, &ctx); break; case NTLMSSP_RECEIVE: DEBUG(100,("ntlmssp_make_packet_signature: RECV seq = %u, len = %u, pdu_len = %u\n", ntlmssp_state->ntlm2_recv_seq_num, (unsigned int)length, (unsigned int)pdu_length)); SIVAL(seq_num, 0, ntlmssp_state->ntlm2_recv_seq_num); ntlmssp_state->ntlm2_recv_seq_num++; hmac_md5_init_limK_to_64(ntlmssp_state->recv_sign_key, 16, &ctx); break; } dump_data_pw("pdu data ", whole_pdu, pdu_length); hmac_md5_update(seq_num, 4, &ctx); hmac_md5_update(whole_pdu, pdu_length, &ctx); hmac_md5_final(digest, &ctx); if (encrypt_sig && (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH)) { switch (direction) { case NTLMSSP_SEND: arcfour_crypt_sbox(&ntlmssp_state->send_seal_arc4_state, digest, 8); break; case NTLMSSP_RECEIVE: arcfour_crypt_sbox(&ntlmssp_state->recv_seal_arc4_state, digest, 8); break; } } SIVAL(sig->data, 0, NTLMSSP_SIGN_VERSION); memcpy(sig->data + 4, digest, 8); memcpy(sig->data + 12, seq_num, 4); dump_data_pw("ntlmssp v2 sig ", sig->data, sig->length); } else { uint32 crc; crc = crc32_calc_buffer(data, length); if (!msrpc_gen(sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlmv1_seq_num)) { return NT_STATUS_NO_MEMORY; } ntlmssp_state->ntlmv1_seq_num++; dump_arc4_state("ntlmssp hash: \n", &ntlmssp_state->ntlmv1_arc4_state); arcfour_crypt_sbox(&ntlmssp_state->ntlmv1_arc4_state, sig->data+4, sig->length-4); } return NT_STATUS_OK; }
NTSTATUS ntlmssp_seal_packet(NTLMSSP_STATE *ntlmssp_state, uchar *data, size_t length, DATA_BLOB *sig) { if (!ntlmssp_state->session_key.length) { DEBUG(3, ("NO session key, cannot seal packet\n")); return NT_STATUS_NO_USER_SESSION_KEY; } DEBUG(10,("ntlmssp_seal_data: seal\n")); dump_data_pw("ntlmssp clear data\n", data, length); if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) { HMACMD5Context ctx; char seq_num[4]; uchar digest[16]; SIVAL(seq_num, 0, ntlmssp_state->ntlmssp_seq_num); hmac_md5_init_limK_to_64((const unsigned char *)(ntlmssp_state->send_sign_const), 16, &ctx); hmac_md5_update((const unsigned char *)seq_num, 4, &ctx); hmac_md5_update(data, length, &ctx); hmac_md5_final(digest, &ctx); if (!msrpc_gen(sig, "dBd", NTLMSSP_SIGN_VERSION, digest, 8 /* only copy first 8 bytes */ , ntlmssp_state->ntlmssp_seq_num)) { return NT_STATUS_NO_MEMORY; } dump_data_pw("ntlmssp client sealing hash:\n", ntlmssp_state->send_seal_hash, sizeof(ntlmssp_state->send_seal_hash)); NTLMSSPcalc_ap(ntlmssp_state->send_seal_hash, data, length); dump_data_pw("ntlmssp client signing hash:\n", ntlmssp_state->send_sign_hash, sizeof(ntlmssp_state->send_sign_hash)); NTLMSSPcalc_ap(ntlmssp_state->send_sign_hash, sig->data+4, sig->length-4); } else { uint32 crc; crc = crc32_calc_buffer((const char *)data, length); if (!msrpc_gen(sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlmssp_seq_num)) { return NT_STATUS_NO_MEMORY; } /* The order of these two operations matters - we must first seal the packet, then seal the sequence number - this is becouse the ntlmssp_hash is not constant, but is is rather updated with each iteration */ dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash, sizeof(ntlmssp_state->ntlmssp_hash)); NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, data, length); dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash, sizeof(ntlmssp_state->ntlmssp_hash)); NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, sig->data+4, sig->length-4); } dump_data_pw("ntlmssp sealed data\n", data, length); /* increment counter on send */ ntlmssp_state->ntlmssp_seq_num++; return NT_STATUS_OK; }