c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen/*
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen * NTLM and NTLMv2 hash generation.
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen *
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen * Copyright (c) 2004 Andrey Panin <pazke@donpac.ru>
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen *
e074ffeaee1ce283bd42f167c6810e3d013f8218Timo Sirainen * This software is released under the MIT license.
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen */
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen#include "lib.h"
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen#include "buffer.h"
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen#include "compat.h"
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen#include "safe-memset.h"
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen#include "md4.h"
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz#include "md5.h"
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz#include "hmac.h"
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen#include "ntlm.h"
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen#include "ntlm-des.h"
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen
0729d22d8f7be5b40f34748279183820a81aa851Timo Sirainen#include <ctype.h>
0729d22d8f7be5b40f34748279183820a81aa851Timo Sirainen
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainenstatic unsigned char *
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainent_unicode_str(const char *src, bool ucase, size_t *size)
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen{
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen buffer_t *wstr;
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen wstr = buffer_create_dynamic(unsafe_data_stack_pool, 32);
23bdbb7b1831785c6ba6df190f6369da882d2b9dTimo Sirainen for ( ; *src != '\0'; src++) {
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen buffer_append_c(wstr, ucase ? i_toupper(*src) : *src);
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen buffer_append_c(wstr, '\0');
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen }
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen
2d5d7890bd9b282eb1092fc788a2432a6c79a7adTimo Sirainen *size = wstr->used;
0f66f12eb4cdbf47670975044c88d8f388bf92dfTimo Sirainen return buffer_free_without_data(&wstr);
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen}
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainenvoid lm_hash(const char *passwd, unsigned char hash[LM_HASH_SIZE])
d43c646d4b84635aa795946555be04a553d5413aTimo Sirainen{
d43c646d4b84635aa795946555be04a553d5413aTimo Sirainen static const unsigned char lm_magic[8] = "KGS!@#$%";
d43c646d4b84635aa795946555be04a553d5413aTimo Sirainen unsigned char buffer[14];
d43c646d4b84635aa795946555be04a553d5413aTimo Sirainen unsigned int i;
d43c646d4b84635aa795946555be04a553d5413aTimo Sirainen
971deedd546f4cb3abb2e3a67d273cc8e214a3c3Timo Sirainen strncpy((char *)buffer, passwd, sizeof(buffer));
d43c646d4b84635aa795946555be04a553d5413aTimo Sirainen
d43c646d4b84635aa795946555be04a553d5413aTimo Sirainen for (i = 0; i < sizeof(buffer); i++)
d43c646d4b84635aa795946555be04a553d5413aTimo Sirainen buffer[i] = i_toupper(buffer[i]);
d43c646d4b84635aa795946555be04a553d5413aTimo Sirainen
d43c646d4b84635aa795946555be04a553d5413aTimo Sirainen deshash(hash, buffer, lm_magic);
d43c646d4b84635aa795946555be04a553d5413aTimo Sirainen deshash(hash + 8, buffer + 7, lm_magic);
d43c646d4b84635aa795946555be04a553d5413aTimo Sirainen
d43c646d4b84635aa795946555be04a553d5413aTimo Sirainen safe_memset(buffer, 0, sizeof(buffer));
d43c646d4b84635aa795946555be04a553d5413aTimo Sirainen}
d43c646d4b84635aa795946555be04a553d5413aTimo Sirainen
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainenvoid ntlm_v1_hash(const char *passwd, unsigned char hash[NTLMSSP_HASH_SIZE])
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen{
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen size_t len;
4cc046655697b1b387fd10ccc7aa821e43495a1eTimo Sirainen void *wpwd = t_unicode_str(passwd, FALSE, &len);
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen md4_get_digest(wpwd, len, hash);
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen safe_memset(wpwd, 0, len);
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen}
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainenstatic void
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitzhmac_md5_ucs2le_string_ucase(struct hmac_context *ctx, const char *str)
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen{
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen size_t len;
4cc046655697b1b387fd10ccc7aa821e43495a1eTimo Sirainen unsigned char *wstr = t_unicode_str(str, TRUE, &len);
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz hmac_update(ctx, wstr, len);
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen}
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainenstatic void ATTR_NULL(2)
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainenntlm_v2_hash(const char *user, const char *target,
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen const unsigned char *hash_v1,
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen unsigned char hash[NTLMSSP_V2_HASH_SIZE])
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen{
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz struct hmac_context ctx;
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz hmac_init(&ctx, hash_v1, NTLMSSP_HASH_SIZE, &hash_method_md5);
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen hmac_md5_ucs2le_string_ucase(&ctx, user);
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen if (target != NULL)
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen hmac_md5_ucs2le_string_ucase(&ctx, target);
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz hmac_final(&ctx, hash);
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen}
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainenvoid
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainenntlmssp_v1_response(const unsigned char *hash,
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen const unsigned char *challenge,
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen unsigned char response[NTLMSSP_RESPONSE_SIZE])
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen{
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen unsigned char des_hash[NTLMSSP_DES_KEY_LENGTH * 3];
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen memcpy(des_hash, hash, NTLMSSP_HASH_SIZE);
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen memset(des_hash + NTLMSSP_HASH_SIZE, 0,
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen sizeof(des_hash) - NTLMSSP_HASH_SIZE);
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen
7d85c4e4e727a48ba7f6d6e6522de8338240ad74Timo Sirainen deshash(response, des_hash, challenge);
7d85c4e4e727a48ba7f6d6e6522de8338240ad74Timo Sirainen deshash(response + 8, des_hash + 7, challenge);
7d85c4e4e727a48ba7f6d6e6522de8338240ad74Timo Sirainen deshash(response + 16, des_hash + 14, challenge);
7d85c4e4e727a48ba7f6d6e6522de8338240ad74Timo Sirainen
7d85c4e4e727a48ba7f6d6e6522de8338240ad74Timo Sirainen safe_memset(des_hash, 0, sizeof(des_hash));
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen}
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen
88c2db95c4a0f8f7986a63cd57cf4b6850d76543Timo Sirainenvoid
88c2db95c4a0f8f7986a63cd57cf4b6850d76543Timo Sirainenntlmssp2_response(const unsigned char *hash,
88c2db95c4a0f8f7986a63cd57cf4b6850d76543Timo Sirainen const unsigned char *server_challenge,
88c2db95c4a0f8f7986a63cd57cf4b6850d76543Timo Sirainen const unsigned char *client_challenge,
88c2db95c4a0f8f7986a63cd57cf4b6850d76543Timo Sirainen unsigned char response[NTLMSSP_RESPONSE_SIZE])
88c2db95c4a0f8f7986a63cd57cf4b6850d76543Timo Sirainen{
88c2db95c4a0f8f7986a63cd57cf4b6850d76543Timo Sirainen struct md5_context ctx;
a27109c960092f913f8f9ecd2a6e87cf40f4d0f1Timo Sirainen unsigned char session_hash[MD5_RESULTLEN];
88c2db95c4a0f8f7986a63cd57cf4b6850d76543Timo Sirainen
88c2db95c4a0f8f7986a63cd57cf4b6850d76543Timo Sirainen md5_init(&ctx);
88c2db95c4a0f8f7986a63cd57cf4b6850d76543Timo Sirainen md5_update(&ctx, server_challenge, NTLMSSP_CHALLENGE_SIZE);
88c2db95c4a0f8f7986a63cd57cf4b6850d76543Timo Sirainen md5_update(&ctx, client_challenge, NTLMSSP_CHALLENGE_SIZE);
88c2db95c4a0f8f7986a63cd57cf4b6850d76543Timo Sirainen md5_final(&ctx, session_hash);
88c2db95c4a0f8f7986a63cd57cf4b6850d76543Timo Sirainen
88c2db95c4a0f8f7986a63cd57cf4b6850d76543Timo Sirainen ntlmssp_v1_response(hash, session_hash, response);
88c2db95c4a0f8f7986a63cd57cf4b6850d76543Timo Sirainen}
88c2db95c4a0f8f7986a63cd57cf4b6850d76543Timo Sirainen
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainenvoid
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainenntlmssp_v2_response(const char *user, const char *target,
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen const unsigned char *hash_v1,
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen const unsigned char *challenge,
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen const unsigned char *blob, size_t blob_size,
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen unsigned char response[NTLMSSP_V2_RESPONSE_SIZE])
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen{
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz struct hmac_context ctx;
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen unsigned char hash[NTLMSSP_V2_HASH_SIZE];
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen ntlm_v2_hash(user, target, hash_v1, hash);
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz hmac_init(&ctx, hash, NTLMSSP_V2_HASH_SIZE, &hash_method_md5);
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz hmac_update(&ctx, challenge, NTLMSSP_CHALLENGE_SIZE);
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz hmac_update(&ctx, blob, blob_size);
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz hmac_final(&ctx, response);
7d85c4e4e727a48ba7f6d6e6522de8338240ad74Timo Sirainen
7d85c4e4e727a48ba7f6d6e6522de8338240ad74Timo Sirainen safe_memset(hash, 0, sizeof(hash));
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen}