ntlm.c
来自「samba最新软件」· C语言 代码 · 共 1,365 行 · 第 1/3 页
C
1,365 行
heim_ntlm_free_buf(key); return ret; } MD4_Init(&ctx); MD4_Update(&ctx, buf.data, buf.length); MD4_Final(key->data, &ctx); heim_ntlm_free_buf(&buf); return 0;}/** * Calculate NTLMv1 response hash * * @param key the ntlm v1 key * @param len length of key * @param challange sent by the server * @param answer calculated answer, should be freed with heim_ntlm_free_buf(). * * @return In case of success 0 is return, an errors, a errno in what * went wrong. * * @ingroup ntlm_core */intheim_ntlm_calculate_ntlm1(void *key, size_t len, unsigned char challange[8], struct ntlm_buf *answer){ unsigned char res[21]; if (len != MD4_DIGEST_LENGTH) return EINVAL; memcpy(res, key, len); memset(&res[MD4_DIGEST_LENGTH], 0, sizeof(res) - MD4_DIGEST_LENGTH); answer->data = malloc(24); if (answer->data == NULL) return ENOMEM; answer->length = 24; splitandenc(&res[0], challange, ((unsigned char *)answer->data) + 0); splitandenc(&res[7], challange, ((unsigned char *)answer->data) + 8); splitandenc(&res[14], challange, ((unsigned char *)answer->data) + 16); return 0;}/** * Generates an NTLMv1 session random with assosited session master key. * * @param key the ntlm v1 key * @param len length of key * @param session generated session nonce, should be freed with heim_ntlm_free_buf(). * @param master calculated session master key, should be freed with heim_ntlm_free_buf(). * * @return In case of success 0 is return, an errors, a errno in what * went wrong. * * @ingroup ntlm_core */intheim_ntlm_build_ntlm1_master(void *key, size_t len, struct ntlm_buf *session, struct ntlm_buf *master){ RC4_KEY rc4; memset(master, 0, sizeof(*master)); memset(session, 0, sizeof(*session)); if (len != MD4_DIGEST_LENGTH) return EINVAL; session->length = MD4_DIGEST_LENGTH; session->data = malloc(session->length); if (session->data == NULL) { session->length = 0; return EINVAL; } master->length = MD4_DIGEST_LENGTH; master->data = malloc(master->length); if (master->data == NULL) { heim_ntlm_free_buf(master); heim_ntlm_free_buf(session); return EINVAL; } { unsigned char sessionkey[MD4_DIGEST_LENGTH]; MD4_CTX ctx; MD4_Init(&ctx); MD4_Update(&ctx, key, len); MD4_Final(sessionkey, &ctx); RC4_set_key(&rc4, sizeof(sessionkey), sessionkey); } if (RAND_bytes(session->data, session->length) != 1) { heim_ntlm_free_buf(master); heim_ntlm_free_buf(session); return EINVAL; } RC4(&rc4, master->length, session->data, master->data); memset(&rc4, 0, sizeof(rc4)); return 0;}/** * Generates an NTLMv2 session key. * * @param key the ntlm key * @param len length of key * @param username name of the user, as sent in the message, assumed to be in UTF8. * @param target the name of the target, assumed to be in UTF8. * @param ntlmv2 the ntlmv2 session key * * @ingroup ntlm_core */voidheim_ntlm_ntlmv2_key(const void *key, size_t len, const char *username, const char *target, unsigned char ntlmv2[16]){ unsigned int hmaclen; HMAC_CTX c; HMAC_CTX_init(&c); HMAC_Init_ex(&c, key, len, EVP_md5(), NULL); { struct ntlm_buf buf; /* uppercase username and turn it inte ucs2-le */ ascii2ucs2le(username, 1, &buf); HMAC_Update(&c, buf.data, buf.length); free(buf.data); /* uppercase target and turn into ucs2-le */ ascii2ucs2le(target, 1, &buf); HMAC_Update(&c, buf.data, buf.length); free(buf.data); } HMAC_Final(&c, ntlmv2, &hmaclen); HMAC_CTX_cleanup(&c);}/* * */#define NTTIME_EPOCH 0x019DB1DED53E8000LLstatic uint64_tunix2nttime(time_t unix_time){ long long wt; wt = unix_time * (uint64_t)10000000 + (uint64_t)NTTIME_EPOCH; return wt;}static time_tnt2unixtime(uint64_t t){ t = ((t - (uint64_t)NTTIME_EPOCH) / (uint64_t)10000000); if (t > (((time_t)(~(uint64_t)0)) >> 1)) return 0; return (time_t)t;}/** * Calculate NTLMv2 response * * @param key the ntlm key * @param len length of key * @param username name of the user, as sent in the message, assumed to be in UTF8. * @param target the name of the target, assumed to be in UTF8. * @param serverchallange challange as sent by the server in the type2 message. * @param infotarget infotarget as sent by the server in the type2 message. * @param ntlmv2 calculated session key * @param answer ntlm response answer, should be freed with heim_ntlm_free_buf(). * * @return In case of success 0 is return, an errors, a errno in what * went wrong. * * @ingroup ntlm_core */intheim_ntlm_calculate_ntlm2(const void *key, size_t len, const char *username, const char *target, const unsigned char serverchallange[8], const struct ntlm_buf *infotarget, unsigned char ntlmv2[16], struct ntlm_buf *answer){ krb5_error_code ret; krb5_data data; unsigned int hmaclen; unsigned char ntlmv2answer[16]; krb5_storage *sp; unsigned char clientchallange[8]; HMAC_CTX c; uint64_t t; t = unix2nttime(time(NULL)); if (RAND_bytes(clientchallange, sizeof(clientchallange)) != 1) return EINVAL; /* calculate ntlmv2 key */ heim_ntlm_ntlmv2_key(key, len, username, target, ntlmv2); /* calculate and build ntlmv2 answer */ sp = krb5_storage_emem(); if (sp == NULL) return ENOMEM; krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); CHECK(krb5_store_uint32(sp, 0x00000101), 0); CHECK(krb5_store_uint32(sp, 0), 0); /* timestamp le 64 bit ts */ CHECK(krb5_store_uint32(sp, t & 0xffffffff), 0); CHECK(krb5_store_uint32(sp, t >> 32), 0); CHECK(krb5_storage_write(sp, clientchallange, 8), 8); CHECK(krb5_store_uint32(sp, 0), 0); /* unknown but zero will work */ CHECK(krb5_storage_write(sp, infotarget->data, infotarget->length), infotarget->length); CHECK(krb5_store_uint32(sp, 0), 0); /* unknown but zero will work */ CHECK(krb5_storage_to_data(sp, &data), 0); krb5_storage_free(sp); sp = NULL; HMAC_CTX_init(&c); HMAC_Init_ex(&c, ntlmv2, 16, EVP_md5(), NULL); HMAC_Update(&c, serverchallange, 8); HMAC_Update(&c, data.data, data.length); HMAC_Final(&c, ntlmv2answer, &hmaclen); HMAC_CTX_cleanup(&c); sp = krb5_storage_emem(); if (sp == NULL) { krb5_data_free(&data); return ENOMEM; } CHECK(krb5_storage_write(sp, ntlmv2answer, 16), 16); CHECK(krb5_storage_write(sp, data.data, data.length), data.length); krb5_data_free(&data); CHECK(krb5_storage_to_data(sp, &data), 0); krb5_storage_free(sp); sp = NULL; answer->data = data.data; answer->length = data.length; return 0;out: if (sp) krb5_storage_free(sp); return ret;}static const int authtimediff = 3600 * 2; /* 2 hours *//** * Verify NTLMv2 response. * * @param key the ntlm key * @param len length of key * @param username name of the user, as sent in the message, assumed to be in UTF8. * @param target the name of the target, assumed to be in UTF8. * @param now the time now (0 if the library should pick it up itself) * @param serverchallange challange as sent by the server in the type2 message. * @param answer ntlm response answer, should be freed with heim_ntlm_free_buf(). * @param infotarget infotarget as sent by the server in the type2 message. * @param ntlmv2 calculated session key * * @return In case of success 0 is return, an errors, a errno in what * went wrong. * * @ingroup ntlm_core */intheim_ntlm_verify_ntlm2(const void *key, size_t len, const char *username, const char *target, time_t now, const unsigned char serverchallange[8], const struct ntlm_buf *answer, struct ntlm_buf *infotarget, unsigned char ntlmv2[16]){ krb5_error_code ret; unsigned int hmaclen; unsigned char clientanswer[16]; unsigned char clientnonce[8]; unsigned char serveranswer[16]; krb5_storage *sp; HMAC_CTX c; uint64_t t; time_t authtime; uint32_t temp; infotarget->length = 0; infotarget->data = NULL; if (answer->length < 16) return EINVAL; if (now == 0) now = time(NULL); /* calculate ntlmv2 key */ heim_ntlm_ntlmv2_key(key, len, username, target, ntlmv2); /* calculate and build ntlmv2 answer */ sp = krb5_storage_from_readonly_mem(answer->data, answer->length); if (sp == NULL) return ENOMEM; krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); CHECK(krb5_storage_read(sp, clientanswer, 16), 16); CHECK(krb5_ret_uint32(sp, &temp), 0); CHECK(temp, 0x00000101); CHECK(krb5_ret_uint32(sp, &temp), 0); CHECK(temp, 0); /* timestamp le 64 bit ts */ CHECK(krb5_ret_uint32(sp, &temp), 0); t = temp; CHECK(krb5_ret_uint32(sp, &temp), 0); t |= ((uint64_t)temp)<< 32; authtime = nt2unixtime(t); if (abs((int)(authtime - now)) > authtimediff) { ret = EINVAL; goto out; } /* client challange */ CHECK(krb5_storage_read(sp, clientnonce, 8), 8); CHECK(krb5_ret_uint32(sp, &temp), 0); /* unknown */ /* should really unparse the infotarget, but lets pick up everything */ infotarget->length = answer->length - krb5_storage_seek(sp, 0, SEEK_CUR); infotarget->data = malloc(infotarget->length); if (infotarget->data == NULL) { ret = ENOMEM; goto out; } CHECK(krb5_storage_read(sp, infotarget->data, infotarget->length), infotarget->length); /* XXX remove the unknown ?? */ krb5_storage_free(sp); sp = NULL; HMAC_CTX_init(&c); HMAC_Init_ex(&c, ntlmv2, 16, EVP_md5(), NULL); HMAC_Update(&c, serverchallange, 8); HMAC_Update(&c, ((unsigned char *)answer->data) + 16, answer->length - 16); HMAC_Final(&c, serveranswer, &hmaclen); HMAC_CTX_cleanup(&c); if (memcmp(serveranswer, clientanswer, 16) != 0) { heim_ntlm_free_buf(infotarget); return EINVAL; } return 0;out: heim_ntlm_free_buf(infotarget); if (sp) krb5_storage_free(sp); return ret;}/* * Calculate the NTLM2 Session Response * * @param clnt_nonce client nonce * @param svr_chal server challage * @param ntlm2_hash ntlm hash * @param lm The LM response, should be freed with heim_ntlm_free_buf(). * @param ntlm The NTLM response, should be freed with heim_ntlm_free_buf(). * * @return In case of success 0 is return, an errors, a errno in what * went wrong. * * @ingroup ntlm_core */intheim_ntlm_calculate_ntlm2_sess(const unsigned char clnt_nonce[8], const unsigned char svr_chal[8], const unsigned char ntlm_hash[16], struct ntlm_buf *lm, struct ntlm_buf *ntlm){ unsigned char ntlm2_sess_hash[MD5_DIGEST_LENGTH]; unsigned char res[21], *resp; MD5_CTX md5; lm->data = malloc(24); if (lm->data == NULL) return ENOMEM; lm->length = 24; ntlm->data = malloc(24); if (ntlm->data == NULL) { free(lm->data); lm->data = NULL; return ENOMEM; } ntlm->length = 24; /* first setup the lm resp */ memset(lm->data, 0, 24); memcpy(lm->data, clnt_nonce, 8); MD5_Init(&md5); MD5_Update(&md5, svr_chal, 8); /* session nonce part 1 */ MD5_Update(&md5, clnt_nonce, 8); /* session nonce part 2 */ MD5_Final(ntlm2_sess_hash, &md5); /* will only use first 8 bytes */ memset(res, 0, sizeof(res)); memcpy(res, ntlm_hash, 16); resp = ntlm->data; splitandenc(&res[0], ntlm2_sess_hash, resp + 0); splitandenc(&res[7], ntlm2_sess_hash, resp + 8); splitandenc(&res[14], ntlm2_sess_hash, resp + 16); return 0;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?