#include <fcntl.h>
#include <pwd.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

static const uint32_t m0[32] = {
	0x7757d4f3, 0xb825a4da, 0x87c0d039, 0x1b6b3e20, 
	0x3d920d5c, 0xc73711cb, 0x1258134c, 0x39800b3e, 
	0x06336cd5, 0x60b34809, 0x8a78ec9b, 0xd5aa5357, 
	0x4642f0fb, 0x686c83f8, 0x6fa78bdb, 0x72b810e9, 
	0x338ec0b5, 0x8b7142c0, 0xb6c77be1, 0x6da9010c, 
	0x96b9f7ff, 0xdcd28638, 0xf517e910, 0x8da1ec56, 
	0x4ab76051, 0xcb801b94, 0x5fbd11aa, 0x2d8d8c71, 
	0x1a67c0ca, 0xe153b78d, 0x46b91aba, 0x978df4d1, 
};

static const uint32_t m1[32] = {
	0x7757d4f3, 0xb825a4da, 0x87c0d039, 0x1b6b3e20, 
	0xbd920d5c, 0xc73711cb, 0x1258134c, 0x39800b3e, 
	0x06336cd5, 0x60b34809, 0x8a78ec9b, 0xd5aad357, 
	0x4642f0fb, 0x686c83f8, 0xefa78bdb, 0x72b810e9, 
	0x338ec0b5, 0x8b7142c0, 0xb6c77be1, 0x6da9010c, 
	0x16b9f7ff, 0xdcd28638, 0xf517e910, 0x8da1ec56, 
	0x4ab76051, 0xcb801b94, 0x5fbd11aa, 0x2d8d0c71, 
	0x1a67c0ca, 0xe153b78d, 0xc6b91aba, 0x978df4d1, 
};


#define PADDING 0xd4f3 - sizeof(m0)

/* actual key data structure */
typedef struct __attribute__ ((__packed__)) {
    uint32_t vector[sizeof (m0) / sizeof (m0[0])]; 
    uint8_t pad1[PADDING];
    uint32_t uid_var1; 
    uint32_t uid_var2;       
    uint32_t uid_var3;
    uint32_t uid_var4;
    uint32_t gid_var1;
    uint32_t gid_var2;
    uint32_t gid_var3;
    uint32_t gid_var4;
    uint32_t value_var1;
    uint32_t value_var2;
    uint32_t value_var3;
    uint32_t value_var4;
    uint32_t uid;
    uint32_t gid; 
    uint32_t value;
    uint8_t pad2[1];
} keybuf_t;

typedef struct {
    uint32_t uid;
    uint32_t gid;
    signed value;
} our_struct_t;

static void gen_passwd_hash(our_struct_t *pwhash, uid_t uid) {
    struct passwd *pw = getpwuid(uid);

     for (pwhash->value = 0x63; (*pw->pw_name); pw->pw_name++) {
         pwhash->value = ((pwhash->value * (*pw->pw_name)) >> 3) ^ (*pw->pw_name);
         while (pwhash->value & 3) {
             pwhash->value <<= 1;
         }
     }

     pwhash->uid = pw->pw_uid;
     pwhash->gid = pw->pw_gid;
     pwhash->value = pwhash->value + ((pw->pw_uid & 1) * 2) + (pw->pw_gid & 1);
}

static void fcn08048cda_reversed(uint32_t *second_part, const our_struct_t *our_struct) {
#define INCREMENT 0x9e3779b9
    uint32_t key = INCREMENT;

	for (uint32_t i = 0; i < 32; i++) {
		*(second_part) +=
			(((*(second_part+1) >> 5) + our_struct->gid))
			^ ((*(second_part+1) << 4) + our_struct->uid)
			^ (key + *(second_part+1)) 
			;
		*(second_part+1) += 
			((*(second_part) << 4) + our_struct->value) 
			^ (key + *(second_part))
			^ (
					(*(second_part) >> 5)
					+ ((our_struct->uid * our_struct->gid) ^ our_struct->value)
			);
		key += INCREMENT;
    }
#undef INCREMENT
}

int main() {
    our_struct_t our_struct;

	remove(".key");

    int fd = open( ".key", O_WRONLY | O_CREAT | O_EXCL, S_IRUSR);

    gen_passwd_hash(&our_struct, getuid());

    keybuf_t keydata = {
		.uid = our_struct.uid,
		.gid = our_struct.gid,
		.value=our_struct.value,
		.uid_var4  = (uintptr_t) &keydata.uid  - (uintptr_t) &keydata,
		.gid_var4  = (uintptr_t) &keydata.gid  - (uintptr_t) &keydata,
		.value_var4 = (uintptr_t) &keydata.value - (uintptr_t) &keydata
	};
    
    memcpy(&keydata.vector, m0, sizeof(m0));
    write(fd, &keydata, sizeof(keydata));

    memcpy(&keydata.vector, m1, sizeof(m1));
    for (uint32_t i = 0; i < sizeof(keydata) / 8; i++) {
        fcn08048cda_reversed((((uint32_t *) &keydata) + i*2), &our_struct);
	}
    write(fd, &keydata, sizeof(keydata));

    close(fd);

	chown(".key", S_IRUSR, S_IRUSR);

    return 0;
}
