summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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
5 files changed, 324 insertions, 4 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)
{