Created
June 20, 2024 17:10
-
-
Save adamz01h/d12b721b105a902cf886a75855bdbf6e to your computer and use it in GitHub Desktop.
NTLMv1 Implementation in C GPT
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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; | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This came from CHATGPT and might not work at all.