ProtoCore v0.0.2
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
ntlm.h
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file ntlm.h
6 * @brief NTLMv2 response computation (MS-NLMP §3.3.2) for the SMB2 client (PC_ENABLE_SMB).
7 *
8 * The auth core: from the user's password and the server's CHALLENGE (the 8-byte server challenge
9 * + the target-info AV_PAIR blob), compute the NtChallengeResponse and the session base key that
10 * seed SESSION_SETUP. Built on the KAT-verified MD4 / MD5 / HMAC-MD5 (crypto/hash/md.h). Pure, zero heap.
11 *
12 * NThash = MD4(UTF-16LE(password))
13 * NTOWFv2 = HMAC-MD5(NThash, UTF-16LE(Uppercase(user) + domain))
14 * temp = 0x01 0x01 Z(6) Time(8) ClientChallenge(8) Z(4) TargetInfo Z(4)
15 * NTProofStr = HMAC-MD5(NTOWFv2, ServerChallenge(8) + temp)
16 * NtChallengeResponse = NTProofStr(16) + temp
17 * SessionBaseKey = HMAC-MD5(NTOWFv2, NTProofStr)
18 *
19 * Verified against the MS-NLMP §4.2 worked example (test_ntlm).
20 *
21 * @author Douglas Quigg (dstroy0)
22 * @date 2026
23 */
24
25#ifndef PROTOCORE_NTLM_H
26#define PROTOCORE_NTLM_H
27
28#include "protocore_config.h"
29
30#if PC_ENABLE_SMB
31
32#include <stddef.h>
33#include <stdint.h>
34
35/** @brief The NT hash: MD4 of the UTF-16LE password (@p password is ASCII/UTF-8, NUL-terminated). */
36void pc_ntlm_nt_hash(const char *password, uint8_t nt_hash[16]);
37
38/**
39 * @brief NTOWFv2 = HMAC-MD5(NThash, UTF-16LE(Uppercase(user) + domain)).
40 *
41 * Only the @p user is uppercased (ASCII), not the @p domain (MS-NLMP). Both are NUL-terminated.
42 * @return true; false if user + domain exceed the internal 256-char scratch.
43 */
44bool pc_ntlm_ntowfv2(const uint8_t nt_hash[16], const char *user, const char *domain, uint8_t owf[16]);
45
46/**
47 * @brief Compute the NTLMv2 NtChallengeResponse (NTProofStr + temp) and the session base key.
48 *
49 * @param owf NTOWFv2 (from pc_ntlm_ntowfv2).
50 * @param server_challenge the 8-byte challenge from the server's CHALLENGE_MESSAGE.
51 * @param client_challenge the 8-byte client-generated challenge.
52 * @param timestamp the 8-byte little-endian FILETIME (may be zero).
53 * @param target_info the AV_PAIR blob from the CHALLENGE_MESSAGE.
54 * @param session_key receives the 16-byte SessionBaseKey (may be null).
55 * @return the NtChallengeResponse length written to @p out (48 + @p ti_len), or 0 on overflow.
56 */
57size_t pc_ntlm_v2_response(const uint8_t owf[16], const uint8_t server_challenge[8], const uint8_t client_challenge[8],
58 const uint8_t timestamp[8], const uint8_t *target_info, size_t ti_len, uint8_t *out,
59 size_t out_cap, uint8_t session_key[16]);
60
61/**
62 * @brief Copy the CHALLENGE target-info AV_PAIR list into @p out, setting the MsvAvFlags (AvId 6)
63 * bit 0x00000002 ("the client provides a MIC in the AUTHENTICATE", MS-NLMP §2.2.2.10 / §3.1.5.1.2).
64 *
65 * If an MsvAvFlags pair is already present its value is OR'd with 0x2; otherwise a new
66 * `AvId=6, AvLen=4, value=0x00000002` pair is inserted immediately before the MsvAvEOL (AvId 0)
67 * terminator. The resulting blob is what the NTLMv2 response is computed over, so the server sees the
68 * flag and verifies the MIC. Call before ::pc_ntlm_v2_response and feed it the returned blob.
69 *
70 * @return the new target-info length in @p out (@p ti_len, or @p ti_len + 8 when a pair was inserted),
71 * or 0 on a null pointer / overflow / a malformed (unterminated) list.
72 */
73size_t pc_ntlm_set_mic_flag(const uint8_t *target_info, size_t ti_len, uint8_t *out, size_t out_cap);
74
75/**
76 * @brief The NTLMSSP AUTHENTICATE MIC (MS-NLMP §3.1.5.1.2): HMAC-MD5 over the concatenation of the
77 * three NTLM messages, keyed by the ExportedSessionKey (= the NTLMv2 SessionBaseKey when no key
78 * exchange is negotiated).
79 *
80 * MIC = HMAC-MD5(session_key, NEGOTIATE_MESSAGE || CHALLENGE_MESSAGE || AUTHENTICATE_MESSAGE)
81 *
82 * The three are the raw NTLMSSP token bytes (not SPNEGO-wrapped); @p auth must already have its 16-byte
83 * MIC field zeroed (as ::pc_ntlmssp_build_authenticate leaves it). Streams the parts, so no scratch
84 * concatenation buffer is needed.
85 */
86void pc_ntlm_mic(const uint8_t session_key[16], const uint8_t *neg, size_t neg_len, const uint8_t *chal,
87 size_t chal_len, const uint8_t *auth, size_t auth_len, uint8_t out[16]);
88
89#endif // PC_ENABLE_SMB
90
91#endif // PROTOCORE_NTLM_H
User-facing configuration for ProtoCore.