17static const uint8_t NTLMSSP_SIG[8] = {
'N',
'T',
'L',
'M',
'S',
'S',
'P', 0};
20static void wr_field(uint8_t *f, uint16_t len, uint32_t off)
27size_t pc_ntlmssp_build_negotiate(uint8_t *buf,
size_t cap, uint32_t flags)
34 memcpy(buf + 0, NTLMSSP_SIG, 8);
37 wr_field(buf + 16, 0, 32);
38 wr_field(buf + 24, 0, 32);
42bool pc_ntlmssp_parse_challenge(
const uint8_t *msg,
size_t len, NtlmChallenge *out)
44 if (!msg || !out || len < 48)
48 if (memcmp(msg, NTLMSSP_SIG, 8) != 0 ||
pc_rd32le(msg + 8) != 2)
53 memcpy(out->server_challenge, msg + 24, 8);
58 out->target_info =
nullptr;
59 out->target_info_len = 0;
62 if ((
size_t)ti_off + ti_len > len)
66 out->target_info = msg + ti_off;
67 out->target_info_len = ti_len;
72static size_t put_utf16le(uint8_t *buf,
const char *s)
77 for (
const char *p = s; *p; p++)
79 buf[n++] = (uint8_t)*p;
85static size_t utf16_len(
const char *s)
98size_t pc_ntlmssp_build_authenticate(uint8_t *buf,
size_t cap,
const uint8_t *lm_resp,
size_t lm_len,
99 const uint8_t *nt_resp,
size_t nt_len,
const char *domain,
const char *user,
100 const char *workstation, uint32_t flags,
bool with_mic)
104 const size_t HDR = with_mic ? 88 : 64;
107 flags |= NtlmsspFlags::NTLMSSP_NEGOTIATE_VERSION;
109 size_t dlen = utf16_len(domain);
110 size_t ulen = utf16_len(user);
111 size_t wlen = utf16_len(workstation);
112 size_t total = HDR + lm_len + nt_len + dlen + ulen + wlen;
113 if (!buf || total > cap)
119 memcpy(buf + 0, NTLMSSP_SIG, 8);
134 if (lm_resp && lm_len)
136 memcpy(buf + off, lm_resp, lm_len);
140 if (nt_resp && nt_len)
142 memcpy(buf + off, nt_resp, nt_len);
145 size_t dom_off = off;
146 off += put_utf16le(buf + off, domain);
147 size_t usr_off = off;
148 off += put_utf16le(buf + off, user);
149 size_t wks_off = off;
150 off += put_utf16le(buf + off, workstation);
151 size_t key_off = off;
153 wr_field(buf + 12, (uint16_t)lm_len, (uint32_t)lm_off);
154 wr_field(buf + 20, (uint16_t)nt_len, (uint32_t)nt_off);
155 wr_field(buf + 28, (uint16_t)dlen, (uint32_t)dom_off);
156 wr_field(buf + 36, (uint16_t)ulen, (uint32_t)usr_off);
157 wr_field(buf + 44, (uint16_t)wlen, (uint32_t)wks_off);
158 wr_field(buf + 52, 0, (uint32_t)key_off);
Fixed-width integer serializers into a raw uint8_t* buffer - one source of truth.
uint32_t pc_rd32le(const uint8_t *p)
Read a little-endian u32 at p.
size_t pc_wr32le(uint8_t *p, uint32_t v)
Write v little-endian at p.
uint16_t pc_rd16le(const uint8_t *p)
Read a little-endian u16 at p.
size_t pc_wr16le(uint8_t *p, uint16_t v)
Write v little-endian at p.
NTLMSSP message codec (MS-NLMP §2.2.1) for the SMB2 client (PC_ENABLE_SMB).