summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimo Sorce <simo@redhat.com>2013-07-17 03:20:16 -0400
committerSimo Sorce <simo@redhat.com>2013-07-18 22:37:25 -0400
commita121c1b405c43b6fcc48fb87ebbe78b9e9dbb74c (patch)
tree48f99d240ad207aaae8d4080401e8f0f0e577f00
parentf3873d6853b7101a8cb82e80586541996a748990 (diff)
downloadgss-ntlmssp-a121c1b405c43b6fcc48fb87ebbe78b9e9dbb74c.tar.gz
gss-ntlmssp-a121c1b405c43b6fcc48fb87ebbe78b9e9dbb74c.tar.xz
gss-ntlmssp-a121c1b405c43b6fcc48fb87ebbe78b9e9dbb74c.zip
Add NTLM Crypto support functions for NTLMv1
-rw-r--r--src/crypto.c68
-rw-r--r--src/crypto.h28
-rw-r--r--src/gss_creds.c2
-rw-r--r--src/ntlm.h78
-rw-r--r--src/ntlm_crypto.c152
-rw-r--r--tests/ntlmssptest.c392
6 files changed, 713 insertions, 7 deletions
diff --git a/src/crypto.c b/src/crypto.c
index 14e6c8d..ab1efbf 100644
--- a/src/crypto.c
+++ b/src/crypto.c
@@ -16,7 +16,9 @@
*/
#include <errno.h>
+#include <string.h>
+#include <openssl/des.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/rand.h>
@@ -219,3 +221,69 @@ int RC4K(struct ntlm_buffer *key,
return ret;
}
+int WEAK_DES(struct ntlm_buffer *key,
+ struct ntlm_buffer *payload,
+ struct ntlm_buffer *result)
+{
+ DES_key_schedule schedule;
+ DES_cblock key8;
+
+ if ((key->length != 7) ||
+ (payload->length != 8) ||
+ (result->length != 8)) {
+ return EINVAL;
+ }
+
+ /* Undocumented shuffle needed before calling DES_set_key_unchecked */
+ key8[0] = key->data[0];
+ key8[1] = (key->data[0] << 7) | (key->data[1] >> 1);
+ key8[2] = (key->data[1] << 6) | (key->data[2] >> 2);
+ key8[3] = (key->data[2] << 5) | (key->data[3] >> 3);
+ key8[4] = (key->data[3] << 4) | (key->data[4] >> 4);
+ key8[5] = (key->data[4] << 3) | (key->data[5] >> 5);
+ key8[6] = (key->data[5] << 2) | (key->data[6] >> 6);
+ key8[7] = (key->data[6] << 1);
+
+ DES_set_key_unchecked(&key8, &schedule);
+ DES_ecb_encrypt((DES_cblock *)payload->data,
+ (DES_cblock *)result->data, &schedule, 1);
+ return 0;
+}
+
+int DESL(struct ntlm_buffer *key,
+ struct ntlm_buffer *payload,
+ struct ntlm_buffer *result)
+{
+ uint8_t buf7[7];
+ struct ntlm_buffer key7;
+ struct ntlm_buffer res8;
+
+ if ((key->length != 16) ||
+ (payload->length != 8) ||
+ (result->length != 24)) {
+ return EINVAL;
+ }
+
+ /* part 1 */
+ key7.data = key->data;
+ key7.length = 7;
+ res8.data = result->data;
+ res8.length = 8;
+ WEAK_DES(&key7, payload, &res8);
+ /* part 2 */
+ key7.data = &key->data[7];
+ key7.length = 7;
+ res8.data = &result->data[8];
+ res8.length = 8;
+ WEAK_DES(&key7, payload, &res8);
+ /* part 3 */
+ memcpy(buf7, &key->data[14], 2);
+ memset(&buf7[2], 0, 5);
+ key7.data = buf7;
+ key7.length = 7;
+ res8.data = &result->data[16];
+ res8.length = 8;
+ WEAK_DES(&key7, payload, &res8);
+
+ return 0;
+}
diff --git a/src/crypto.h b/src/crypto.h
index 3a2f6f9..efce1fc 100644
--- a/src/crypto.h
+++ b/src/crypto.h
@@ -112,6 +112,32 @@ void RC4_FREE(struct ntlm_rc4_handle **handle);
int RC4K(struct ntlm_buffer *key,
enum ntlm_cipher_mode mode,
struct ntlm_buffer *payload,
-struct ntlm_buffer *result);
+ struct ntlm_buffer *result);
+
+/**
+ * @brief Extreely weak DES encryption
+ *
+ * @param key The encryption/decryption key (must be 8 bytes)
+ * @param payload Input buffer (must be 8 bytes)
+ * @param result Output buffer (must be 8 bytes)
+ *
+ * @return 0 on success or EINVAL if any buffer is not 8 in length
+ */
+int WEAK_DES(struct ntlm_buffer *key,
+ struct ntlm_buffer *payload,
+ struct ntlm_buffer *result);
+
+/**
+ * @brief A sad weak encryption/expansion scheme needed by NTLMv1
+ *
+ * @param key The encryption/decryption key (must be 16 bytes)
+ * @param payload Input buffer (must be 8 bytes)
+ * @param result Output buffer (must be 24 bytes)
+ *
+ * @return 0 on success or EINVAL if any buffer is not of proper length
+ */
+int DESL(struct ntlm_buffer *key,
+ struct ntlm_buffer *payload,
+ struct ntlm_buffer *result);
#endif /* _SRC_CRYPTO_H_ */
diff --git a/src/gss_creds.c b/src/gss_creds.c
index b16f9ca..2f062bd 100644
--- a/src/gss_creds.c
+++ b/src/gss_creds.c
@@ -98,7 +98,7 @@ static int get_initial_creds(struct gssntlm_name *name,
goto done;
}
cred->cred.user.nt_hash.length = 16;
- ret = ntlm_pwd_to_nt_hash(pwd, &cred->cred.user.nt_hash);
+ ret = NTOWFv1(pwd, &cred->cred.user.nt_hash);
goto done;
}
diff --git a/src/ntlm.h b/src/ntlm.h
index 0acdbfc..18cb79a 100644
--- a/src/ntlm.h
+++ b/src/ntlm.h
@@ -112,7 +112,83 @@ struct ntlm_key {
*
* @return 0 on success or an error;
*/
-int ntlm_pwd_to_nt_hash(const char *password, struct ntlm_key *result);
+int NTOWFv1(const char *password, struct ntlm_key *result);
+
+/**
+ * @brief Turns a utf8 password into an LM Hash
+ *
+ * @param password The password
+ * @param result The returned hash
+ *
+ * @return 0 on success or an error;
+ */
+int LMOWFv1(const char *password, struct ntlm_key *result);
+
+/**
+ * @brief Generates a v1 NT Response
+ *
+ * @param nt_key The NTLMv1 key computed by NTOWFv1()
+ * @param ext_sec Whether Extended Security has been negotiated
+ * @param server_chal[8] The server challenge
+ * @param client_chal[8] The client challenge (only with Extended Security)
+ * @param nt_response The output buffer (must be 24 bytes preallocated)
+ *
+ * @return 0 on success or ERR_CRYPTO
+ */
+int ntlm_compute_nt_response(struct ntlm_key *nt_key, bool ext_sec,
+ uint8_t server_chal[8], uint8_t client_chal[8],
+ struct ntlm_buffer *nt_response);
+
+/**
+ * @brief Generates a v1 LM Response
+ *
+ * @param lm_key The LMv1 key computed by LMOWFv1()
+ * @param ext_sec Whether Extended Security has been negotiated
+ * @param server_chal[8] The server challenge
+ * @param client_chal[8] The client challenge (only with Extended Security)
+ * @param lm_response The output buffer (must be 24 bytes preallocated)
+ *
+ * @return 0 on success or ERR_CRYPTO
+ */
+int ntlm_compute_lm_response(struct ntlm_key *lm_key, bool ext_sec,
+ uint8_t server_chal[8], uint8_t client_chal[8],
+ struct ntlm_buffer *lm_response);
+
+/**
+ * @brief Returns the v1 session key
+ *
+ * @param nt_key The NTLMv1 key computed by NTOWFv1()
+ * @param session_base_key The output buffer (must be 16 bytes preallocated)
+ *
+ * @return 0 on success or ERR_CRYPTO
+ */
+int ntlm_session_base_key(struct ntlm_key *nt_key,
+ struct ntlm_key *session_base_key);
+
+/**
+ * @brief V1 Key Exchange Key calculation
+ *
+ * @param ctx An ntlm context
+ * @param ext_sec Whether Extended Security has been negotiated
+ * @param neg_lm_key Whether LM KEY has been negotiated
+ * @param non_nt_sess_key Whether non NT Session Key has been negotiated
+ * @param server_chal The server challenge (only with Extended Security)
+ * @param lm_key The LMv1 key computed by LMOWFv1()
+ * @param session_base_key The Session Base Key
+ * @param lm_response The LM v1 Response
+ * @param key_exchange_key The output buffer (must be 16 bytes preallocated)
+ *
+ * @return 0 on success or ERR_CRYPTO
+ */
+int KXKEY(struct ntlm_ctx *ctx,
+ bool ext_sec,
+ bool neg_lm_key,
+ bool non_nt_sess_key,
+ uint8_t server_chal[8],
+ struct ntlm_key *lm_key,
+ struct ntlm_key *session_base_key,
+ struct ntlm_buffer *lm_response,
+ struct ntlm_key *key_exchange_key);
/**
* @brief Generates a NTLMv2 Response Key
diff --git a/src/ntlm_crypto.c b/src/ntlm_crypto.c
index c94ea79..d999d0f 100644
--- a/src/ntlm_crypto.c
+++ b/src/ntlm_crypto.c
@@ -81,7 +81,7 @@ struct wire_ntlmv2_cli_chal {
#define MAX_USER_DOM_LEN 512
-int ntlm_pwd_to_nt_hash(const char *password, struct ntlm_key *result)
+int NTOWFv1(const char *password, struct ntlm_key *result)
{
struct ntlm_buffer payload;
struct ntlm_buffer hash;
@@ -106,6 +106,156 @@ int ntlm_pwd_to_nt_hash(const char *password, struct ntlm_key *result)
return ret;
}
+#define DES_CONST "KGS!@#$%"
+int LMOWFv1(const char *password, struct ntlm_key *result)
+{
+ struct ntlm_buffer key;
+ struct ntlm_buffer plain;
+ struct ntlm_buffer cipher;
+ char upcased[15];
+ char *retstr;
+ size_t out;
+ size_t len;
+ int ret;
+
+ if (result->length != 16) return EINVAL;
+
+ len = strlen(password);
+ if (len > 14) return ERANGE;
+
+ out = 15;
+ retstr = (char *)u8_toupper((const uint8_t *)password, len,
+ NULL, NULL, (uint8_t *)upcased, &out);
+ if (!retstr) return ERR_CRYPTO;
+ if (retstr != upcased) {
+ free(retstr);
+ ret = EINVAL;
+ }
+ memset(&upcased[len], 0, 15 - len);
+
+ /* part1 */
+ key.data = (uint8_t *)upcased;
+ key.length = 7;
+ plain.data = discard_const(DES_CONST);
+ plain.length = 8;
+ cipher.data = result->data;
+ cipher.length = 8;
+ ret = WEAK_DES(&key, &plain, &cipher);
+ if (ret) return ret;
+
+ /* part2 */
+ key.data = (uint8_t *)&upcased[7];
+ key.length = 7;
+ plain.data = discard_const(DES_CONST);
+ plain.length = 8;
+ cipher.data = &result->data[8];
+ cipher.length = 8;
+ return WEAK_DES(&key, &plain, &cipher);
+}
+
+int ntlm_compute_nt_response(struct ntlm_key *nt_key, bool ext_sec,
+ uint8_t server_chal[8], uint8_t client_chal[8],
+ struct ntlm_buffer *nt_response)
+{
+ struct ntlm_buffer key = { nt_key->data, nt_key->length };
+ struct ntlm_buffer payload;
+ struct ntlm_buffer result;
+ uint8_t buf1[16];
+ uint8_t buf2[16];
+ int ret;
+
+ memcpy(buf1, server_chal, 8);
+ if (ext_sec) {
+ memcpy(&buf1[8], client_chal, 8);
+ payload.data = buf1;
+ payload.length = 16;
+ result.data = buf2;
+ result.length = 16;
+ ret = MD5_HASH(&payload, &result);
+ if (ret) return ret;
+ memcpy(buf1, result.data, 8);
+ }
+ payload.data = buf1;
+ payload.length = 8;
+
+ return DESL(&key, &payload, nt_response);
+}
+
+int ntlm_compute_lm_response(struct ntlm_key *lm_key, bool ext_sec,
+ uint8_t server_chal[8], uint8_t client_chal[8],
+ struct ntlm_buffer *lm_response)
+{
+ struct ntlm_buffer key = { lm_key->data, lm_key->length };
+ struct ntlm_buffer payload = { server_chal, 8 };
+
+ if (ext_sec) {
+ memcpy(lm_response->data, client_chal, 8);
+ memset(&lm_response->data[8], 0, 16);
+ return 0;
+ }
+ return DESL(&key, &payload, lm_response);
+}
+
+int ntlm_session_base_key(struct ntlm_key *nt_key,
+ struct ntlm_key *session_base_key)
+{
+ struct ntlm_buffer payload = { nt_key->data, nt_key->length };
+ struct ntlm_buffer hash = { session_base_key->data,
+ session_base_key->length };
+
+ return MD4_HASH(&payload, &hash);
+}
+
+int KXKEY(struct ntlm_ctx *ctx,
+ bool ext_sec,
+ bool neg_lm_key,
+ bool non_nt_sess_key,
+ uint8_t server_chal[8],
+ struct ntlm_key *lm_key,
+ struct ntlm_key *session_base_key,
+ struct ntlm_buffer *lm_response,
+ struct ntlm_key *key_exchange_key)
+{
+ struct ntlm_buffer payload;
+ struct ntlm_buffer result;
+ struct ntlm_buffer key;
+ uint8_t buf[16];
+ int ret = 0;
+
+ if (ext_sec) {
+ key.data = session_base_key->data;
+ key.length = session_base_key->length;
+ memcpy(buf, server_chal, 8);
+ memcpy(&buf[8], lm_response->data, 8);
+ payload.data = buf;
+ payload.length = 16;
+ result.data = key_exchange_key->data;
+ result.length = key_exchange_key->length;
+ ret = HMAC_MD5(&key, &payload, &result);
+ } else if (neg_lm_key) {
+ payload.data = lm_response->data;
+ payload.length = 8;
+ key.data = lm_key->data;
+ key.length = 7;
+ result.data = key_exchange_key->data;
+ result.length = 8;
+ ret = WEAK_DES(&key, &payload, &result);
+ if (ret) return ret;
+ buf[0] = lm_key->data[7];
+ memset(&buf[1], 0xbd, 6);
+ key.data = buf;
+ result.data = &key_exchange_key->data[8];
+ result.length = 8;
+ ret = WEAK_DES(&key, &payload, &result);
+ } else if (non_nt_sess_key) {
+ memcpy(key_exchange_key->data, lm_key, 8);
+ memset(&key_exchange_key->data[8], 0, 8);
+ } else {
+ memcpy(key_exchange_key->data, session_base_key->data, 16);
+ }
+ return ret;
+}
+
int NTOWFv2(struct ntlm_ctx *ctx, struct ntlm_key *nt_hash,
const char *user, const char *domain, struct ntlm_key *result)
{
diff --git a/tests/ntlmssptest.c b/tests/ntlmssptest.c
index 4f653c4..176eee4 100644
--- a/tests/ntlmssptest.c
+++ b/tests/ntlmssptest.c
@@ -97,6 +97,138 @@ uint8_t T_ServerChallenge[] = {
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef
};
+/* NTLMv1 Auth Test Data */
+struct {
+ struct ntlm_key ResponseKeyLM;
+ struct ntlm_key ResponseKeyNT;
+ struct ntlm_key SessionBaseKey;
+ uint8_t LMv1Response[24];
+ uint8_t NTLMv1Response[24];
+ struct ntlm_key KeyExchangeKey;
+ struct ntlm_key EncryptedSessionKey1;
+ struct ntlm_key EncryptedSessionKey2;
+ struct ntlm_key EncryptedSessionKey3;
+ uint32_t ChallengeFlags;
+ uint8_t ChallengeMessage[0x44];
+ /* Version field differs from the one MS DOCS generated */
+ uint8_t EncChallengeMessage[0x44];
+ uint8_t AuthenticateMessage[0xAC];
+} T_NTLMv1 = {
+ {
+ .data = {
+ 0xe5, 0x2c, 0xac, 0x67, 0x41, 0x9a, 0x9a, 0x22,
+ 0x4a, 0x3b, 0x10, 0x8f, 0x3f, 0xa6, 0xcb, 0x6d
+ },
+ .length = 16
+ },
+ {
+ .data = {
+ 0xa4, 0xf4, 0x9c, 0x40, 0x65, 0x10, 0xbd, 0xca,
+ 0xb6, 0x82, 0x4e, 0xe7, 0xc3, 0x0f, 0xd8, 0x52
+ },
+ .length = 16
+ },
+ {
+ .data = {
+ 0xd8, 0x72, 0x62, 0xb0, 0xcd, 0xe4, 0xb1, 0xcb,
+ 0x74, 0x99, 0xbe, 0xcc, 0xcd, 0xf1, 0x07, 0x84
+ },
+ .length = 16
+ },
+ {
+ 0x98, 0xde, 0xf7, 0xb8, 0x7f, 0x88, 0xaa, 0x5d,
+ 0xaf, 0xe2, 0xdf, 0x77, 0x96, 0x88, 0xa1, 0x72,
+ 0xde, 0xf1, 0x1c, 0x7d, 0x5c, 0xcd, 0xef, 0x13
+ },
+ {
+ 0x67, 0xc4, 0x30, 0x11, 0xf3, 0x02, 0x98, 0xa2,
+ 0xad, 0x35, 0xec, 0xe6, 0x4f, 0x16, 0x33, 0x1c,
+ 0x44, 0xbd, 0xbe, 0xd9, 0x27, 0x84, 0x1f, 0x94
+ },
+ {
+ .data = {
+ 0xb0, 0x9e, 0x37, 0x9f, 0x7f, 0xbe, 0xcb, 0x1e,
+ 0xaf, 0x0a, 0xfd, 0xcb, 0x03, 0x83, 0xc8, 0xa0
+ },
+ .length = 16
+ },
+ {
+ .data = {
+ 0x51, 0x88, 0x22, 0xb1, 0xb3, 0xf3, 0x50, 0xc8,
+ 0x95, 0x86, 0x82, 0xec, 0xbb, 0x3e, 0x3c, 0xb7
+ },
+ .length = 16
+ },
+ {
+ .data = {
+ 0x74, 0x52, 0xca, 0x55, 0xc2, 0x25, 0xa1, 0xca,
+ 0x04, 0xb4, 0x8f, 0xae, 0x32, 0xcf, 0x56, 0xfc
+ },
+ .length = 16
+ },
+ {
+ .data = {
+ 0x4c, 0xd7, 0xbb, 0x57, 0xd6, 0x97, 0xef, 0x9b,
+ 0x54, 0x9f, 0x02, 0xb8, 0xf9, 0xb3, 0x78, 0x64
+ },
+ .length = 16
+ },
+ (
+ NTLMSSP_NEGOTIATE_56 | NTLMSSP_NEGOTIATE_KEY_EXCH |
+ NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_VERSION |
+ NTLMSSP_TARGET_TYPE_SERVER |
+ NTLMSSP_NEGOTIATE_ALWAYS_SIGN | NTLMSSP_NEGOTIATE_NTLM |
+ NTLMSSP_NEGOTIATE_SEAL | NTLMSSP_NEGOTIATE_SIGN |
+ NTLMSSP_NEGOTIATE_OEM | NTLMSSP_NEGOTIATE_UNICODE
+ ),
+ {
+ 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00,
+ 0x38, 0x00, 0x00, 0x00, 0x33, 0x82, 0x02, 0xe2,
+ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x06, 0x00, 0x70, 0x17, 0x00, 0x00, 0x00, 0x0f,
+ 0x53, 0x00, 0x65, 0x00, 0x72, 0x00, 0x76, 0x00,
+ 0x65, 0x00, 0x72, 0x00
+ },
+ {
+ 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00,
+ 0x38, 0x00, 0x00, 0x00, 0x33, 0x82, 0x02, 0xe2,
+ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f,
+ 0x53, 0x00, 0x65, 0x00, 0x72, 0x00, 0x76, 0x00,
+ 0x65, 0x00, 0x72, 0x00
+ },
+ {
+ 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00,
+ 0x6c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00,
+ 0x84, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00,
+ 0x48, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00,
+ 0x54, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00,
+ 0x5c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00,
+ 0x9c, 0x00, 0x00, 0x00, 0x35, 0x82, 0x80, 0xe2,
+ 0x05, 0x01, 0x28, 0x0a, 0x00, 0x00, 0x00, 0x0f,
+ 0x44, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x61, 0x00,
+ 0x69, 0x00, 0x6e, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x43, 0x00, 0x4f, 0x00,
+ 0x4d, 0x00, 0x50, 0x00, 0x55, 0x00, 0x54, 0x00,
+ 0x45, 0x00, 0x52, 0x00, 0x98, 0xde, 0xf7, 0xb8,
+ 0x7f, 0x88, 0xaa, 0x5d, 0xaf, 0xe2, 0xdf, 0x77,
+ 0x96, 0x88, 0xa1, 0x72, 0xde, 0xf1, 0x1c, 0x7d,
+ 0x5c, 0xcd, 0xef, 0x13, 0x67, 0xc4, 0x30, 0x11,
+ 0xf3, 0x02, 0x98, 0xa2, 0xad, 0x35, 0xec, 0xe6,
+ 0x4f, 0x16, 0x33, 0x1c, 0x44, 0xbd, 0xbe, 0xd9,
+ 0x27, 0x84, 0x1f, 0x94, 0x51, 0x88, 0x22, 0xb1,
+ 0xb3, 0xf3, 0x50, 0xc8, 0x95, 0x86, 0x82, 0xec,
+ 0xbb, 0x3e, 0x3c, 0xb7
+ }
+};
+
/* NTLMv2 Auth Test Data */
struct {
uint32_t ChallengeFlags;
@@ -223,13 +355,119 @@ struct {
}
};
+int test_LMOWFv1(struct ntlm_ctx *ctx)
+{
+ struct ntlm_key result = { .length = 16 };
+ int ret;
+
+ ret = LMOWFv1(T_Passwd, &result);
+ if (ret) return ret;
+
+ if (memcmp(result.data, T_NTLMv1.ResponseKeyLM.data, 16) != 0) {
+ fprintf(stderr, "results differ!\n");
+ fprintf(stderr, "expected %s\n",
+ hex_to_str_16(T_NTLMv1.ResponseKeyLM.data));
+ fprintf(stderr, "obtained %s\n",
+ hex_to_str_16(result.data));
+ ret = EINVAL;
+ }
+
+ return ret;
+}
+
+int test_NTOWFv1(struct ntlm_ctx *ctx)
+{
+ struct ntlm_key result = { .length = 16 };
+ int ret;
+
+ ret = NTOWFv1(T_Passwd, &result);
+ if (ret) return ret;
+
+ if (memcmp(result.data, T_NTLMv1.ResponseKeyNT.data, 16) != 0) {
+ fprintf(stderr, "results differ!\n");
+ fprintf(stderr, "expected %s\n",
+ hex_to_str_16(T_NTLMv1.ResponseKeyNT.data));
+ fprintf(stderr, "obtained %s\n",
+ hex_to_str_16(result.data));
+ ret = EINVAL;
+ }
+
+ return ret;
+}
+
+int test_SessionBaseKeyV1(struct ntlm_ctx *ctx)
+{
+ struct ntlm_key session_base_key = { .length = 16 };
+ int ret;
+
+ ret = ntlm_session_base_key(&T_NTLMv1.ResponseKeyNT, &session_base_key);
+ if (ret) return ret;
+
+ if (memcmp(session_base_key.data, T_NTLMv1.SessionBaseKey.data, 16) != 0) {
+ fprintf(stderr, "results differ!\n");
+ fprintf(stderr, "expected %s\n",
+ hex_to_str_16(T_NTLMv1.SessionBaseKey.data));
+ fprintf(stderr, "obtained %s\n",
+ hex_to_str_16(session_base_key.data));
+ ret = EINVAL;
+ }
+
+ return ret;
+}
+
+int test_LMResponseV1(struct ntlm_ctx *ctx)
+{
+ uint8_t buf[24];
+ struct ntlm_buffer result = { buf, 24 };
+ int ret;
+
+ ret = ntlm_compute_lm_response(&T_NTLMv1.ResponseKeyLM, false,
+ T_ServerChallenge, T_ClientChallenge,
+ &result);
+ if (ret) return ret;
+
+ if (memcmp(result.data, T_NTLMv1.LMv1Response, 16) != 0) {
+ fprintf(stderr, "results differ!\n");
+ fprintf(stderr, "expected %s\n",
+ hex_to_str_16(T_NTLMv1.LMv1Response));
+ fprintf(stderr, "obtained %s\n",
+ hex_to_str_16(result.data));
+ ret = EINVAL;
+ }
+
+ return ret;
+}
+
+int test_NTResponseV1(struct ntlm_ctx *ctx)
+{
+ uint8_t buf[24];
+ struct ntlm_buffer result = { buf, 24 };
+ int ret;
+
+ ret = ntlm_compute_nt_response(&T_NTLMv1.ResponseKeyNT, false,
+ T_ServerChallenge, T_ClientChallenge,
+ &result);
+ if (ret) return ret;
+
+ if (memcmp(result.data, T_NTLMv1.NTLMv1Response, 16) != 0) {
+ fprintf(stderr, "results differ!\n");
+ fprintf(stderr, "expected %s\n",
+ hex_to_str_16(T_NTLMv1.NTLMv1Response));
+ fprintf(stderr, "obtained %s\n",
+ hex_to_str_16(result.data));
+ ret = EINVAL;
+ }
+
+ return ret;
+}
+
int test_NTOWFv2(struct ntlm_ctx *ctx)
{
struct ntlm_key nt_hash = { .length = 16 };
struct ntlm_key result = { .length = 16 };
int ret;
- ret = ntlm_pwd_to_nt_hash(T_Passwd, &nt_hash);
+ ret = NTOWFv1(T_Passwd, &nt_hash);
if (ret) return ret;
ret = NTOWFv2(ctx, &nt_hash, T_User, T_UserDom, &result);
@@ -344,6 +582,118 @@ int test_EncryptedSessionKey(struct ntlm_ctx *ctx,
return ret;
}
+int test_EncryptedSessionKey1(struct ntlm_ctx *ctx)
+{
+ struct ntlm_buffer lm_response = { T_NTLMv1.LMv1Response, 24 };
+ struct ntlm_key key_exchnage_key = { .length = 16 };
+ int ret;
+
+ ret = KXKEY(ctx, false, false, false, T_ServerChallenge,
+ &T_NTLMv1.ResponseKeyLM, &T_NTLMv1.SessionBaseKey,
+ &lm_response, &key_exchnage_key);
+ if (ret) return ret;
+
+ return test_EncryptedSessionKey(ctx, &key_exchnage_key,
+ &T_NTLMv1.EncryptedSessionKey1);
+}
+
+int test_EncryptedSessionKey2(struct ntlm_ctx *ctx)
+{
+ struct ntlm_buffer lm_response = { T_NTLMv1.LMv1Response, 24 };
+ struct ntlm_key key_exchnage_key = { .length = 16 };
+ int ret;
+
+ ret = KXKEY(ctx, false, false, true, T_ServerChallenge,
+ &T_NTLMv1.ResponseKeyLM, &T_NTLMv1.SessionBaseKey,
+ &lm_response, &key_exchnage_key);
+ if (ret) return ret;
+
+ return test_EncryptedSessionKey(ctx, &key_exchnage_key,
+ &T_NTLMv1.EncryptedSessionKey2);
+}
+
+int test_EncryptedSessionKey3(struct ntlm_ctx *ctx)
+{
+ struct ntlm_buffer lm_response = { T_NTLMv1.LMv1Response, 24 };
+ struct ntlm_key key_exchnage_key = { .length = 16 };
+ int ret;
+
+ ret = KXKEY(ctx, false, true, false, T_ServerChallenge,
+ &T_NTLMv1.ResponseKeyLM, &T_NTLMv1.SessionBaseKey,
+ &lm_response, &key_exchnage_key);
+ if (ret) return ret;
+
+ return test_EncryptedSessionKey(ctx, &key_exchnage_key,
+ &T_NTLMv1.EncryptedSessionKey3);
+}
+
+int test_DecodeChallengeMessageV1(struct ntlm_ctx *ctx)
+{
+ struct ntlm_buffer chal_msg = { T_NTLMv1.ChallengeMessage, 0x68 };
+ uint32_t type;
+ uint32_t flags;
+ char *target_name = NULL;
+ uint8_t chal[8];
+ struct ntlm_buffer challenge = { chal, 8 };
+ int ret;
+
+ ret = ntlm_decode_msg_type(ctx, &chal_msg, &type);
+ if (ret) return ret;
+ if (type != 2) return EINVAL;
+
+ ret = ntlm_decode_chal_msg(ctx, &chal_msg, &flags, &target_name,
+ &challenge, NULL);
+ if (ret) return ret;
+
+ if (flags != T_NTLMv1.ChallengeFlags) {
+ fprintf(stderr, "flags differ!\n");
+ fprintf(stderr, "expected %d\n", T_NTLMv1.ChallengeFlags);
+ fprintf(stderr, "obtained %d\n", flags);
+ ret = EINVAL;
+ }
+
+ if (strcmp(target_name, T_Server_Name) != 0) {
+ fprintf(stderr, "Target Names differ!\n");
+ fprintf(stderr, "expected %s\n", T_Server_Name);
+ fprintf(stderr, "obtained %s\n", target_name);
+ ret = EINVAL;
+ }
+
+ if (memcmp(chal, T_ServerChallenge, 8) != 0) {
+ fprintf(stderr, "Challenges differ!\n");
+ fprintf(stderr, "expected %s\n", hex_to_str_8(T_ServerChallenge));
+ fprintf(stderr, "obtained %s\n", hex_to_str_8(chal));
+ ret = EINVAL;
+ }
+
+ free(target_name);
+ return ret;
+}
+
+int test_EncodeChallengeMessageV1(struct ntlm_ctx *ctx)
+{
+ struct ntlm_buffer challenge = { T_ServerChallenge, 8 };
+ struct ntlm_buffer message = { 0 };
+ int ret;
+
+ ret = ntlm_encode_chal_msg(ctx, T_NTLMv1.ChallengeFlags, T_Server_Name,
+ &challenge, NULL, &message);
+ if (ret) return ret;
+
+ if ((message.length != 0x44) ||
+ (memcmp(message.data, T_NTLMv1.EncChallengeMessage, 0x44) != 0)) {
+ fprintf(stderr, "Challenge Messages differ!\n");
+ fprintf(stderr, "expected:\n%s",
+ hex_to_dump(T_NTLMv1.EncChallengeMessage, 0x44));
+ fprintf(stderr, "obtained:\n%s",
+ hex_to_dump(message.data, message.length));
+ ret = EINVAL;
+ }
+
+ free(message.data);
+ return ret;
+}
+
int test_DecodeChallengeMessageV2(struct ntlm_ctx *ctx)
{
struct ntlm_buffer chal_msg = { T_NTLMv2.ChallengeMessage, 0x68 };
@@ -530,8 +880,44 @@ int main(int argc, const char *argv[])
ret = ntlm_init_ctx(&ctx);
if (ret) goto done;
- fprintf(stdout, "Test NTOWFv2\n");
- ret = test_NTOWFv2(ctx);
+ fprintf(stdout, "Test LMOWFv1\n");
+ ret = test_LMOWFv1(ctx);
+ fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
+
+ fprintf(stdout, "Test NTOWFv1\n");
+ ret = test_NTOWFv1(ctx);
+ fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
+
+ fprintf(stdout, "Test LMResponse v1\n");
+ ret = test_LMResponseV1(ctx);
+ fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
+
+ fprintf(stdout, "Test NTResponse v1\n");
+ ret = test_NTResponseV1(ctx);
+ fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
+
+ fprintf(stdout, "Test SessionBaseKey v1\n");
+ ret = test_SessionBaseKeyV1(ctx);
+ fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
+
+ fprintf(stdout, "Test EncryptedSessionKey v1 (1)\n");
+ ret = test_EncryptedSessionKey1(ctx);
+ fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
+
+ fprintf(stdout, "Test EncryptedSessionKey v1 (2)\n");
+ ret = test_EncryptedSessionKey2(ctx);
+ fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
+
+ fprintf(stdout, "Test EncryptedSessionKey v1 (3)\n");
+ ret = test_EncryptedSessionKey3(ctx);
+ fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
+
+ fprintf(stdout, "Test decoding ChallengeMessage v1\n");
+ ret = test_DecodeChallengeMessageV1(ctx);
+ fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
+
+ fprintf(stdout, "Test encoding ChallengeMessage v1\n");
+ ret = test_EncodeChallengeMessageV1(ctx);
fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
fprintf(stdout, "Test LMResponse v2\n");