Skip to content

Instantly share code, notes, and snippets.

@adamz01h
Created June 20, 2024 17:10
Show Gist options
  • Select an option

  • Save adamz01h/d12b721b105a902cf886a75855bdbf6e to your computer and use it in GitHub Desktop.

Select an option

Save adamz01h/d12b721b105a902cf886a75855bdbf6e to your computer and use it in GitHub Desktop.
NTLMv1 Implementation in C GPT
#include <stdio.h>
#include <stdint.h>
#include <string.h>
// Simplified MD4 implementation
typedef struct {
uint32_t state[4];
uint32_t count[2];
unsigned char buffer[64];
} MD4_CTX;
void MD4Transform(uint32_t state[4], const unsigned char block[64]);
void Encode(unsigned char *output, uint32_t *input, unsigned int len);
void Decode(uint32_t *output, const unsigned char *input, unsigned int len);
void MD4Init(MD4_CTX *context);
void MD4Update(MD4_CTX *context, const unsigned char *input, unsigned int inputLen);
void MD4Final(unsigned char digest[16], MD4_CTX *context);
void MD4Init(MD4_CTX *context) {
context->count[0] = context->count[1] = 0;
context->state[0] = 0x67452301;
context->state[1] = 0xefcdab89;
context->state[2] = 0x98badcfe;
context->state[3] = 0x10325476;
}
void MD4Update(MD4_CTX *context, const unsigned char *input, unsigned int inputLen) {
unsigned int i, index, partLen;
index = (unsigned int)((context->count[0] >> 3) & 0x3F);
if ((context->count[0] += ((uint32_t)inputLen << 3)) < ((uint32_t)inputLen << 3))
context->count[1]++;
context->count[1] += ((uint32_t)inputLen >> 29);
partLen = 64 - index;
if (inputLen >= partLen) {
memcpy(&context->buffer[index], input, partLen);
MD4Transform(context->state, context->buffer);
for (i = partLen; i + 63 < inputLen; i += 64)
MD4Transform(context->state, &input[i]);
index = 0;
} else {
i = 0;
}
memcpy(&context->buffer[index], &input[i], inputLen - i);
}
void MD4Final(unsigned char digest[16], MD4_CTX *context) {
unsigned char bits[8];
unsigned int index, padLen;
static unsigned char PADDING[64] = {
0x80
};
Encode(bits, context->count, 8);
index = (unsigned int)((context->count[0] >> 3) & 0x3f);
padLen = (index < 56) ? (56 - index) : (120 - index);
MD4Update(context, PADDING, padLen);
MD4Update(context, bits, 8);
Encode(digest, context->state, 16);
memset((unsigned char*)context, 0, sizeof(*context));
}
void MD4Transform(uint32_t state[4], const unsigned char block[64]) {
uint32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16];
Decode(x, block, 64);
#define S11 3
#define S12 7
#define S13 11
#define S14 19
#define S21 3
#define S22 5
#define S23 9
#define S24 13
#define S31 3
#define S32 9
#define S33 11
#define S34 15
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
#define FF(a, b, c, d, x, s) { (a) += F ((b), (c), (d)) + (x); (a) = ROTATE_LEFT ((a), (s)); }
#define GG(a, b, c, d, x, s) { (a) += G ((b), (c), (d)) + (x) + (uint32_t)0x5a827999; (a) = ROTATE_LEFT ((a), (s)); }
#define HH(a, b, c, d, x, s) { (a) += H ((b), (c), (d)) + (x) + (uint32_t)0x6ed9eba1; (a) = ROTATE_LEFT ((a), (s)); }
FF(a, b, c, d, x[ 0], S11);
FF(d, a, b, c, x[ 1], S12);
FF(c, d, a, b, x[ 2], S13);
FF(b, c, d, a, x[ 3], S14);
FF(a, b, c, d, x[ 4], S11);
FF(d, a, b, c, x[ 5], S12);
FF(c, d, a, b, x[ 6], S13);
FF(b, c, d, a, x[ 7], S14);
FF(a, b, c, d, x[ 8], S11);
FF(d, a, b, c, x[ 9], S12);
FF(c, d, a, b, x[10], S13);
FF(b, c, d, a, x[11], S14);
FF(a, b, c, d, x[12], S11);
FF(d, a, b, c, x[13], S12);
FF(c, d, a, b, x[14], S13);
FF(b, c, d, a, x[15], S14);
GG(a, b, c, d, x[ 0], S21);
GG(d, a, b, c, x[ 4], S22);
GG(c, d, a, b, x[ 8], S23);
GG(b, c, d, a, x[12], S24);
GG(a, b, c, d, x[ 1], S21);
GG(d, a, b, c, x[ 5], S22);
GG(c, d, a, b, x[ 9], S23);
GG(b, c, d, a, x[13], S24);
GG(a, b, c, d, x[ 2], S21);
GG(d, a, b, c, x[ 6], S22);
GG(c, d, a, b, x[10], S23);
GG(b, c, d, a, x[14], S24);
GG(a, b, c, d, x[ 3], S21);
GG(d, a, b, c, x[ 7], S22);
GG(c, d, a, b, x[11], S23);
GG(b, c, d, a, x[15], S24);
HH(a, b, c, d, x[ 0], S31);
HH(d, a, b, c, x[ 8], S32);
HH(c, d, a, b, x[ 4], S33);
HH(b, c, d, a, x[12], S34);
HH(a, b, c, d, x[ 2], S31);
HH(d, a, b, c, x[10], S32);
HH(c, d, a, b, x[ 6], S33);
HH(b, c, d, a, x[14], S34);
HH(a, b, c, d, x[ 1], S31);
HH(d, a, b, c, x[ 9], S32);
HH(c, d, a, b, x[ 5], S33);
HH(b, c, d, a, x[13], S34);
HH(a, b, c, d, x[ 3], S31);
HH(d, a, b, c, x[11], S32);
HH(c, d, a, b, x[ 7], S33);
HH(b, c, d, a, x[15], S34);
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
memset((unsigned char*)x, 0, sizeof(x));
}
void Encode(unsigned char *output, uint32_t *input, unsigned int len) {
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4) {
output[j] = (unsigned char)(input[i] & 0xff);
output[j + 1] = (unsigned char)((input[i] >> 8) & 0xff);
output[j + 2] = (unsigned char)((input[i] >> 16) & 0xff);
output[j + 3] = (unsigned char)((input[i] >> 24) & 0xff);
}
}
void Decode(uint32_t *output, const unsigned char *input, unsigned int len) {
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4)
output[i] = ((uint32_t)input[j]) | (((uint32_t)input[j + 1]) << 8) |
(((uint32_t)input[j + 2]) << 16) | (((uint32_t)input[j + 3]) << 24);
}
// Simplified DES implementation
void DESKeySetup(const unsigned char key[7], uint32_t ks[16][2]);
void DESRound(uint32_t *l, uint32_t *r, const uint32_t ks[2]);
void DESEncryptBlock(const unsigned char key[7], const unsigned char plaintext[8], unsigned char ciphertext[8]) {
uint32_t ks[16][2];
uint32_t l, r;
DESKeySetup(key, ks);
l = ((uint32_t)plaintext[0] << 24) | ((uint32_t)plaintext[1] << 16) | ((uint32_t)plaintext[2] << 8) | ((uint32_t)plaintext[3]);
r = ((uint32_t)plaintext[4] << 24) | ((uint32_t)plaintext[5] << 16) | ((uint32_t)plaintext[6] << 8) | ((uint32_t)plaintext[7]);
for (int i = 0; i < 16; i++) {
DESRound(&l, &r, ks[i]);
}
ciphertext[0] = (r >> 24) & 0xff;
ciphertext[1] = (r >> 16) & 0xff;
ciphertext[2] = (r >> 8) & 0xff;
ciphertext[3] = r & 0xff;
ciphertext[4] = (l >> 24) & 0xff;
ciphertext[5] = (l >> 16) & 0xff;
ciphertext[6] = (l >> 8) & 0xff;
ciphertext[7] = l & 0xff;
}
// Helper functions for DES
#define IP(l, r) \
{ \
uint32_t tt; \
PERM_OP(r, l, tt, 4, 0x0f0f0f0f); \
PERM_OP(l, r, tt, 16, 0x0000ffff); \
PERM_OP(r, l, tt, 2, 0x33333333); \
PERM_OP(l, r, tt, 8, 0x00ff00ff); \
PERM_OP(r, l, tt, 1, 0x55555555); \
}
#define FP(l, r) \
{ \
uint32_t tt; \
PERM_OP(l, r, tt, 1, 0x55555555); \
PERM_OP(r, l, tt, 8, 0x00ff00ff); \
PERM_OP(l, r, tt, 2, 0x33333333); \
PERM_OP(r, l, tt, 16, 0x0000ffff); \
PERM_OP(l, r, tt, 4, 0x0f0f0f0f); \
}
#define PERM_OP(a, b, t, n, m) \
{ \
t = ((a >> n) ^ b) & m; \
b ^= t; \
a ^= t << n; \
}
#define ROTATE(a, n) (((a) >> (n)) | ((a) << (32 - (n))))
#define DES_F(l, r, s, t) \
{ \
uint32_t u, v; \
u = r ^ s[0]; \
v = ROTATE(r, 28) ^ s[1]; \
l ^= SP1[(u >> 24) & 0x3f] | SP2[(u >> 16) & 0x3f] | SP3[(u >> 8) & 0x3f] | SP4[u & 0x3f] | \
SP5[(v >> 24) & 0x3f] | SP6[(v >> 16) & 0x3f] | SP7[(v >> 8) & 0x3f] | SP8[v & 0x3f]; \
}
#define LOAD_DATA_tmp(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) \
{ \
a = (t[0] >> 4) | (t[1] << 28); \
b = (t[0] & 0x0f) | (t[1] >> 4); \
c = (t[2] >> 4) | (t[3] << 28); \
d = (t[2] & 0x0f) | (t[3] >> 4); \
e = (t[4] >> 4) | (t[5] << 28); \
f = (t[4] & 0x0f) | (t[5] >> 4); \
g = (t[6] >> 4) | (t[7] << 28); \
h = (t[6] & 0x0f) | (t[7] >> 4); \
i = (t[8] >> 4) | (t[9] << 28); \
j = (t[8] & 0x0f) | (t[9] >> 4); \
k = (t[10] >> 4) | (t[11] << 28); \
l = (t[10] & 0x0f) | (t[11] >> 4); \
m = (t[12] >> 4) | (t[13] << 28); \
n = (t[12] & 0x0f) | (t[13] >> 4); \
o = (t[14] >> 4) | (t[15] << 28); \
p = (t[14] & 0x0f) | (t[15] >> 4); \
}
static const uint32_t SP1[64] = { /* TO BE FILLED */ };
static const uint32_t SP2[64] = { /* TO BE FILLED */ };
static const uint32_t SP3[64] = { /* TO BE FILLED */ };
static const uint32_t SP4[64] = { /* TO BE FILLED */ };
static const uint32_t SP5[64] = { /* TO BE FILLED */ };
static const uint32_t SP6[64] = { /* TO BE FILLED */ };
static const uint32_t SP7[64] = { /* TO BE FILLED */ };
static const uint32_t SP8[64] = { /* TO BE FILLED */ };
void DESKeySetup(const unsigned char key[7], uint32_t ks[16][2]) {
unsigned char pc1m[56], pcr[56];
uint32_t kn[32];
int i, j, l, m, n;
for (j = 0; j < 56; j++) {
l = pc1[j];
m = l & 7;
pc1m[j] = (key[l >> 3] & bytebit[m]) ? 1 : 0;
}
for (i = 0; i < 16; i++) {
if (shifts2[i]) {
for (j = 0; j < 56; j++) {
pcr[j] = pc1m[j] ? 1 : 0;
if ((j + 1) % 28) pc1m[j] = pc1m[j + 1];
else pc1m[j] = pcr[j - 27];
}
} else {
for (j = 0; j < 56; j++) {
pcr[j] = pc1m[j] ? 1 : 0;
if ((j + 2) % 28) pc1m[j] = pc1m[j + 2];
else pc1m[j] = pcr[j - 26];
}
}
for (j = 0; j < 48; j++) {
kn[j] = pc1m[pc2[j]] ? 1 : 0;
}
for (j = 0; j < 24; j++) {
ks[i][0] = (ks[i][0] << 1) + kn[j];
ks[i][1] = (ks[i][1] << 1) + kn[j + 24];
}
}
}
void DESRound(uint32_t *l, uint32_t *r, const uint32_t ks[2]) {
uint32_t u, v;
u = *r ^ ks[0];
v = ROTATE(*r, 28) ^ ks[1];
*l ^= SP1[(u >> 24) & 0x3f] | SP2[(u >> 16) & 0x3f] | SP3[(u >> 8) & 0x3f] | SP4[u & 0x3f] |
SP5[(v >> 24) & 0x3f] | SP6[(v >> 16) & 0x3f] | SP7[(v >> 8) & 0x3f] | SP8[v & 0x3f];
}
void string_to_unicode(const char *src, unsigned char *dest) {
while (*src) {
*dest++ = *src++;
*dest++ = 0x00;
}
}
void lm_hash(const char *password, unsigned char *hash) {
unsigned char key[14] = {0};
unsigned char magic[] = "KGS!@#$%";
unsigned char part1[8], part2[8];
strncpy((char *)key, password, 14);
DESEncryptBlock(key, magic, part1);
DESEncryptBlock(key + 7, magic, part2);
memcpy(hash, part1, 8);
memcpy(hash + 8, part2, 8);
}
void nt_hash(const char *password, unsigned char *hash) {
unsigned char unicode_pass[256] = {0};
MD4_CTX md4_ctx;
string_to_unicode(password, unicode_pass);
MD4Init(&md4_ctx);
MD4Update(&md4_ctx, unicode_pass, strlen(password) * 2);
MD4Final(hash, &md4_ctx);
}
void ntlmv1_response(const unsigned char *hash, const unsigned char *challenge, unsigned char *response) {
unsigned char key1[7], key2[7], key3[7];
unsigned char part1[8], part2[8], part3[8];
memset(key1, 0, 7);
memset(key2, 0, 7);
memset(key3, 0, 7);
memcpy(key1, hash, 7);
memcpy(key2, hash + 7, 7);
memcpy(key3, hash + 14, 2);
DESEncryptBlock(key1, (unsigned char *)challenge, part1);
DESEncryptBlock(key2, (unsigned char *)challenge, part2);
DESEncryptBlock(key3, (unsigned char *)challenge, part3);
memcpy(response, part1, 8);
memcpy(response + 8, part2, 8);
memcpy(response + 16, part3, 8);
}
int main() {
const char *password = "password";
unsigned char lmhash[16] = {0};
unsigned char nthash[16] = {0};
unsigned char challenge[8] = {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0};
unsigned char lm_response[24] = {0};
unsigned char nt_response[24] = {0};
// Generate LM and NT hashes
lm_hash(password, lmhash);
nt_hash(password, nthash);
// Generate NTLMv1 responses
ntlmv1_response(lmhash, challenge, lm_response);
ntlmv1_response(nthash, challenge, nt_response);
// Print LM response
printf("LM Response: ");
for (int i = 0; i < 24; i++) {
printf("%02x", lm_response[i]);
}
printf("\n");
// Print NT response
printf("NT Response: ");
for (int i = 0; i < 24; i++) {
printf("%02x", nt_response[i]);
}
printf("\n");
return 0;
}
@adamz01h
Copy link
Author

This came from CHATGPT and might not work at all.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment