*/
#include "includes.h"
-#include "byteorder.h"
+#include "system/time.h"
+#include "auth/auth.h"
+#include "lib/crypto/crypto.h"
/*
This implements the X/Open SMB password encryption
Returns False if password must have been truncated to create LM hash
*/
-BOOL SMBencrypt(const char *passwd, const uchar *c8, uchar p24[24])
+BOOL SMBencrypt(const char *passwd, const uint8_t *c8, uint8_t p24[24])
{
BOOL ret;
- uchar p21[21];
+ uint8_t p21[21];
memset(p21,'\0',21);
ret = E_deshash(passwd, p21);
#ifdef DEBUG_PASSWORD
DEBUG(100,("SMBencrypt: lm#, challenge, response\n"));
- dump_data(100, (char *)p21, 16);
- dump_data(100, (const char *)c8, 8);
- dump_data(100, (char *)p24, 24);
+ dump_data(100, p21, 16);
+ dump_data(100, c8, 8);
+ dump_data(100, p24, 24);
#endif
return ret;
* @param p16 return password hashed with md4, caller allocated 16 byte buffer
*/
-void E_md4hash(const char *passwd, uchar p16[16])
+void E_md4hash(const char *passwd, uint8_t p16[16])
{
int len;
- smb_ucs2_t wpwd[129];
+ void *wpwd;
+
+ len = push_ucs2_talloc(NULL, &wpwd, passwd);
+ SMB_ASSERT(len >= 2);
- /* Password must be converted to NT unicode - null terminated. */
- push_ucs2(NULL, wpwd, (const char *)passwd, 256, STR_UNICODE|STR_NOALIGN|STR_TERMINATE);
- /* Calculate length in bytes */
- len = strlen_w(wpwd) * sizeof(int16_t);
+ len -= 2;
+ mdfour(p16, wpwd, len);
- mdfour(p16, (unsigned char *)wpwd, len);
- ZERO_STRUCT(wpwd);
+ talloc_free(wpwd);
}
/**
* @note p16 is filled in regardless
*/
-BOOL E_deshash(const char *passwd, uchar p16[16])
+BOOL E_deshash(const char *passwd, uint8_t p16[16])
{
BOOL ret = True;
fstring dospwd;
push_ascii(dospwd, passwd, sizeof(dospwd), STR_UPPER|STR_TERMINATE);
/* Only the fisrt 14 chars are considered, password need not be null terminated. */
- E_P16((const unsigned char *)dospwd, p16);
+ E_P16((const uint8_t *)dospwd, p16);
if (strlen(dospwd) > 14) {
ret = False;
return ret;
}
-/**
- * Creates the MD4 and DES (LM) Hash of the users password.
- * MD4 is of the NT Unicode, DES is of the DOS UPPERCASE password.
- * @param passwd password in 'unix' charset.
- * @param nt_p16 return password hashed with md4, caller allocated 16 byte buffer
- * @param p16 return password hashed with des, caller allocated 16 byte buffer
- */
-
-/* Does both the NT and LM owfs of a user's password */
-void nt_lm_owf_gen(const char *pwd, uchar nt_p16[16], uchar p16[16])
-{
- /* Calculate the MD4 hash (NT compatible) of the password */
- memset(nt_p16, '\0', 16);
- E_md4hash(pwd, nt_p16);
-
-#ifdef DEBUG_PASSWORD
- DEBUG(100,("nt_lm_owf_gen: pwd, nt#\n"));
- dump_data(120, pwd, strlen(pwd));
- dump_data(100, (char *)nt_p16, 16);
-#endif
-
- E_deshash(pwd, (uchar *)p16);
-
-#ifdef DEBUG_PASSWORD
- DEBUG(100,("nt_lm_owf_gen: pwd, lm#\n"));
- dump_data(120, pwd, strlen(pwd));
- dump_data(100, (char *)p16, 16);
-#endif
-}
-
/* Does both the NTLMv2 owfs of a user's password */
-BOOL ntv2_owf_gen(const uchar owf[16],
+BOOL ntv2_owf_gen(const uint8_t owf[16],
const char *user_in, const char *domain_in,
BOOL upper_case_domain, /* Transform the domain into UPPER case */
- uchar kr_buf[16])
+ uint8_t kr_buf[16])
{
- smb_ucs2_t *user;
- smb_ucs2_t *domain;
-
+ void *user;
+ void *domain;
size_t user_byte_len;
size_t domain_byte_len;
HMACMD5Context ctx;
-
- user_byte_len = push_ucs2_allocate(&user, user_in);
- if (user_byte_len == (size_t)-1) {
- DEBUG(0, ("push_uss2_allocate() for user returned -1 (probably malloc() failure)\n"));
+ TALLOC_CTX *mem_ctx = talloc_init("ntv2_owf_gen for %s\\%s", domain_in, user_in);
+ if (!mem_ctx) {
return False;
}
- domain_byte_len = push_ucs2_allocate(&domain, domain_in);
- if (domain_byte_len == (size_t)-1) {
- DEBUG(0, ("push_uss2_allocate() for domain returned -1 (probably malloc() failure)\n"));
+ user_in = strupper_talloc(mem_ctx, user_in);
+ if (user_in == NULL) {
+ talloc_free(mem_ctx);
return False;
}
- strupper_w(user);
+ if (upper_case_domain) {
+ domain_in = strupper_talloc(mem_ctx, domain_in);
+ if (domain_in == NULL) {
+ talloc_free(mem_ctx);
+ return False;
+ }
+ }
+
+ user_byte_len = push_ucs2_talloc(mem_ctx, &user, user_in);
+ if (user_byte_len == (ssize_t)-1) {
+ DEBUG(0, ("push_uss2_talloc() for user returned -1 (probably talloc() failure)\n"));
+ talloc_free(mem_ctx);
+ return False;
+ }
- if (upper_case_domain)
- strupper_w(domain);
+ domain_byte_len = push_ucs2_talloc(mem_ctx, &domain, domain_in);
+ if (domain_byte_len == (ssize_t)-1) {
+ DEBUG(0, ("push_ucs2_talloc() for domain returned -1 (probably talloc() failure)\n"));
+ talloc_free(mem_ctx);
+ return False;
+ }
SMB_ASSERT(user_byte_len >= 2);
SMB_ASSERT(domain_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_update(user, user_byte_len, &ctx);
+ hmac_md5_update(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, (const char *)user, user_byte_len);
- dump_data(100, (const char *)domain, domain_byte_len);
+ dump_data(100, user, user_byte_len);
+ dump_data(100, domain, domain_byte_len);
dump_data(100, owf, 16);
dump_data(100, kr_buf, 16);
#endif
- SAFE_FREE(user);
- SAFE_FREE(domain);
+ talloc_free(mem_ctx);
return True;
}
/* Does the des encryption from the NT or LM MD4 hash. */
-void SMBOWFencrypt(const uchar passwd[16], const uchar *c8, uchar p24[24])
+void SMBOWFencrypt(const uint8_t passwd[16], const uint8_t *c8, uint8_t p24[24])
{
- uchar p21[21];
+ uint8_t p21[21];
ZERO_STRUCT(p21);
/* Does the NT MD4 hash then des encryption. */
-void SMBNTencrypt(const char *passwd, uchar *c8, uchar *p24)
+void SMBNTencrypt(const char *passwd, uint8_t *c8, uint8_t *p24)
{
- uchar p21[21];
+ uint8_t p21[21];
memset(p21,'\0',21);
#ifdef DEBUG_PASSWORD
DEBUG(100,("SMBNTencrypt: nt#, challenge, response\n"));
- dump_data(100, (char *)p21, 16);
- dump_data(100, (char *)c8, 8);
- dump_data(100, (char *)p24, 24);
+ dump_data(100, p21, 16);
+ dump_data(100, c8, 8);
+ dump_data(100, p24, 24);
#endif
}
/* Does the md5 encryption from the Key Response for NTLMv2. */
-void SMBOWFencrypt_ntv2(const uchar kr[16],
+void SMBOWFencrypt_ntv2(const uint8_t kr[16],
const DATA_BLOB *srv_chal,
- const DATA_BLOB *cli_chal,
- uchar resp_buf[16])
+ 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(cli_chal->data, cli_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, cli_chal, resp_buf\n"));
+ DEBUG(100, ("SMBOWFencrypt_ntv2: srv_chal, smbcli_chal, resp_buf\n"));
dump_data(100, srv_chal->data, srv_chal->length);
- dump_data(100, cli_chal->data, cli_chal->length);
+ dump_data(100, smbcli_chal->data, smbcli_chal->length);
dump_data(100, resp_buf, 16);
#endif
}
-void SMBsesskeygen_ntv2(const uchar kr[16],
- const uchar * nt_resp, uint8 sess_key[16])
+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 */
hmac_md5_init_limK_to_64(kr, 16, &ctx);
hmac_md5_update(nt_resp, 16, &ctx);
- hmac_md5_final((unsigned char *)sess_key, &ctx);
+ hmac_md5_final((uint8_t *)sess_key, &ctx);
#ifdef DEBUG_PASSWORD
DEBUG(100, ("SMBsesskeygen_ntv2:\n"));
#endif
}
-void SMBsesskeygen_ntv1(const uchar kr[16], uint8 sess_key[16])
+void SMBsesskeygen_ntv1(const uint8_t kr[16], uint8_t sess_key[16])
{
/* yes, this session key does not change - yes, this
is a problem - but it is 128 bits */
- mdfour((unsigned char *)sess_key, kr, 16);
+ mdfour((uint8_t *)sess_key, kr, 16);
#ifdef DEBUG_PASSWORD
DEBUG(100, ("SMBsesskeygen_ntv1:\n"));
#endif
}
-void SMBsesskeygen_lm_sess_key(const uchar lm_hash[16],
- const uchar lm_resp[24], /* only uses 8 */
- uint8 sess_key[16])
+void SMBsesskeygen_lm_sess_key(const uint8_t lm_hash[16],
+ const uint8_t lm_resp[24], /* only uses 8 */
+ uint8_t sess_key[16])
{
/* Calculate the LM session key (effective length 40 bits,
but changes with each session) */
- uchar p24[24];
- uchar p21[21];
+ uint8_t p24[24];
+ uint8_t p21[21];
memset(p21,'\0',21);
memcpy(p21, lm_hash, 8);
static DATA_BLOB NTLMv2_generate_client_data(TALLOC_CTX *mem_ctx, const DATA_BLOB *names_blob)
{
- uchar client_chal[8];
+ uint8_t client_chal[8];
DATA_BLOB response = data_blob(NULL, 0);
char long_date[8];
NTTIME nttime;
unix_to_nt_time(&nttime, time(NULL));
- generate_random_buffer(client_chal, sizeof(client_chal), False);
+ generate_random_buffer(client_chal, sizeof(client_chal));
push_nttime(long_date, 0, nttime);
return response;
}
-static DATA_BLOB NTLMv2_generate_response(const uchar ntlm_v2_hash[16],
+static DATA_BLOB NTLMv2_generate_response(const uint8_t ntlm_v2_hash[16],
const DATA_BLOB *server_chal,
const DATA_BLOB *names_blob)
{
- uchar ntlmv2_response[16];
+ uint8_t ntlmv2_response[16];
DATA_BLOB ntlmv2_client_data;
DATA_BLOB final_response;
return final_response;
}
-static DATA_BLOB LMv2_generate_response(const uchar ntlm_v2_hash[16],
+static DATA_BLOB LMv2_generate_response(const uint8_t ntlm_v2_hash[16],
const DATA_BLOB *server_chal)
{
- uchar lmv2_response[16];
+ uint8_t lmv2_response[16];
DATA_BLOB lmv2_client_data = data_blob(NULL, 8);
DATA_BLOB final_response = data_blob(NULL, 24);
/* LMv2 */
/* client-supplied random data */
- generate_random_buffer(lmv2_client_data.data, lmv2_client_data.length, False);
+ generate_random_buffer(lmv2_client_data.data, lmv2_client_data.length);
/* Given that data, and the challenge from the server, generate a response */
SMBOWFencrypt_ntv2(ntlm_v2_hash, server_chal, &lmv2_client_data, lmv2_response);
return final_response;
}
-BOOL SMBNTLMv2encrypt(const char *user, const char *domain, const char *password,
- const DATA_BLOB *server_chal,
- const DATA_BLOB *names_blob,
- DATA_BLOB *lm_response, DATA_BLOB *nt_response,
- DATA_BLOB *user_session_key)
+BOOL SMBNTLMv2encrypt_hash(const char *user, const char *domain, const uint8_t nt_hash[16],
+ const DATA_BLOB *server_chal,
+ const DATA_BLOB *names_blob,
+ DATA_BLOB *lm_response, DATA_BLOB *nt_response,
+ DATA_BLOB *lm_session_key, DATA_BLOB *user_session_key)
{
- uchar nt_hash[16];
- uchar ntlm_v2_hash[16];
- E_md4hash(password, nt_hash);
+ uint8_t ntlm_v2_hash[16];
/* We don't use the NT# directly. Instead we use it mashed up with
the username and domain.
if (lm_response) {
*lm_response = LMv2_generate_response(ntlm_v2_hash, server_chal);
+ if (lm_session_key) {
+ *lm_session_key = data_blob(NULL, 16);
+
+ /* The NTLMv2 calculations also provide a session key, for signing etc later */
+ /* use only the first 16 bytes of lm_response for session key */
+ SMBsesskeygen_ntv2(ntlm_v2_hash, lm_response->data, lm_session_key->data);
+ }
}
return True;
}
+BOOL SMBNTLMv2encrypt(const char *user, const char *domain, const char *password,
+ const DATA_BLOB *server_chal,
+ const DATA_BLOB *names_blob,
+ DATA_BLOB *lm_response, DATA_BLOB *nt_response,
+ DATA_BLOB *lm_session_key, DATA_BLOB *user_session_key)
+{
+ uint8_t nt_hash[16];
+ E_md4hash(password, nt_hash);
+
+ return SMBNTLMv2encrypt_hash(user, domain, nt_hash, server_chal, names_blob,
+ lm_response, nt_response, lm_session_key, user_session_key);
+}
+
/***********************************************************
encode a password buffer with a unicode password. The buffer
is filled with random data to make it harder to attack.
************************************************************/
-BOOL encode_pw_buffer(char buffer[516], const char *password, int string_flags)
+BOOL encode_pw_buffer(uint8_t buffer[516], const char *password, int string_flags)
{
- uchar new_pw[512];
+ uint8_t new_pw[512];
size_t new_pw_len;
- new_pw_len = push_string(NULL, new_pw,
+ new_pw_len = push_string(new_pw,
password,
sizeof(new_pw), string_flags);
memcpy(&buffer[512 - new_pw_len], new_pw, new_pw_len);
- generate_random_buffer((unsigned char *)buffer, 512 - new_pw_len, False);
+ generate_random_buffer(buffer, 512 - new_pw_len);
/*
* The length of the new password is in the last 4 bytes of
}
/* decode into the return buffer. Buffer length supplied */
- *new_pw_len = pull_string(NULL, new_pwrd, &in_buffer[512 - byte_len], new_pwrd_size,
+ *new_pw_len = pull_string(new_pwrd, &in_buffer[512 - byte_len], new_pwrd_size,
byte_len, string_flags);
#ifdef DEBUG_PASSWORD