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 + -
显示快捷键?