//solution for KeygenMe V7 by MaxX0r
//more: http://hasherezade.net/crackmes/
#include <stdio.h>
#include <string.h>
#include <map>
#include <iostream>
#ifdef _MSC_VER
typedef __int32 int32_t;
#else
# include <inttypes.h>
#endif
char charset[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
void initTranslation(std::map<int, int> &translate)
{
int tabOut[] = { 5, 7, 4, 1, 0, 9, 8, 3, 2, 6 };
translate.clear();
for (size_t i = 0; i < 10; i++) {
int out = tabOut[i];
translate[out] = i;
}
}
int32_t charSum(char str[])
{
int32_t sum = 0;
size_t len = strlen(str);
for (size_t i = 0; i < len; i++) {
char c = str[i];
sum += c;
}
return sum;
}
int32_t calcUserHash0(char username[])
{
int32_t sum = charSum(username);
int32_t len = strlen(username);
int32_t hash = (sum ^ len) * 0xF + 1;
hash >>= 4;
while (hash >= 0x24) hash -= 7;
return hash;
}
int32_t calcUserHash1(char username[])
{
int hash = 0;
int32_t len = strlen(username);
for (size_t i = 0; i < len; i++) {
int32_t d = i + 8;
int32_t c = username[i] * i;
c += (hash / d);
c *= i;
hash += c;
}
if (hash < 0x3E8) {
hash *= hash;
}
return hash;
}
char mixChar(char c, std::map<int, int> &translate)
{
if (c < '0' || c > '9') {
if (c >= 'a' && c <='z') return (c - 'a') + 'A';
return c;
}
int val = c - '0';
val = translate[val];
val = translate[val];
return val +'0';
}
std::string makeKey(char username[], int32_t hash0, int32_t hash1, std::map<int,int> translate)
{
char key[33];
memset(key, 0, 33);
size_t unLen = strlen(username);
int32_t bigLoopIndx = 0;
int32_t prevKeyIndx = -1;
for ( bigLoopIndx = 0; bigLoopIndx < 32; bigLoopIndx++ ) {
if ( bigLoopIndx != 0 && bigLoopIndx % 7 == 0 ) {
key[bigLoopIndx] = '-';
continue;
}
if (bigLoopIndx == 0 || (33 % (bigLoopIndx + 2)) == 0 || ((bigLoopIndx & 3) == 0)) {
int32_t keyIndx = (hash1 / (hash0 + bigLoopIndx)) + 1337;
keyIndx = hash1 / keyIndx;
keyIndx = (bigLoopIndx + 1) ^ keyIndx;
int32_t ecx = keyIndx * 0xF + 1;
int32_t sign = (hash0 < 0) ? -1 : 0;
int32_t esi = ((hash0 - sign) >> 1) + 1;
keyIndx = ecx / esi;
if (prevKeyIndx != -1) {
if (prevKeyIndx == keyIndx) keyIndx <<= 1;
}
while (keyIndx >= 34) keyIndx -= 2;
while (keyIndx < 0) keyIndx += 2;
prevKeyIndx = keyIndx;
char keyChar = mixChar(charset[keyIndx], translate);
key[bigLoopIndx] = keyChar;
continue;
}
//path 2:
int32_t keyIndx = (hash1 / (0x23 - bigLoopIndx)) + 1337;
keyIndx = hash1 / keyIndx;
keyIndx = keyIndx % (bigLoopIndx + 1);
int32_t ecx = keyIndx * 0xF + 1;
int32_t sign = (hash0 < 0) ? -1 : 0;
int32_t esi = ((hash0 - sign) >> 1) + 1;
keyIndx = ecx / esi;
if (prevKeyIndx != -1) {
if (prevKeyIndx == keyIndx) keyIndx <<= 1;
}
while (keyIndx > 36) keyIndx -= 2;
while (keyIndx < 0) keyIndx += 2;
prevKeyIndx = keyIndx;
char keyChar = mixChar(charset[keyIndx], translate);
key[bigLoopIndx] = keyChar;
}
return key;
}
int main(int argc, char *argv[])
{
if (argc < 2) {
printf("No username given!\n");
return -1;
}
char *username = argv[1];
size_t uLen = strlen(username);
if (uLen < 3) {
printf("Username too short\n");
return -1;
}
if (uLen > 16) {
printf("Username too long\n");
return -1;
}
printf ("Username: %s\n", username);
std::map<int,int> translationMap;
initTranslation(translationMap);
int32_t hash0 = calcUserHash0(username);
int32_t hash1 = calcUserHash1(username);
std::string key = makeKey(username, hash0, hash1, translationMap);
printf("%s\n", key.c_str());
return 0;
}