#include char raw0[16] = {0x8A, 0xF8, 0xDA, 0xBA, 0x94, 0xC8, 0xA8, 0x80, 0x92, 0xD0, 0xB0, 0x8C, 0x9E, 0xDC, 0xBC}; char msk1[16] = {0x40, 0x40, 0x20, 0x40, 0x20, 0x10, 0x40, 0x20, 0x10, 0x08, 0x40, 0x20, 0x10, 0x08, 0x04, 0x04}; char msk2[16] = {0x20, 0x10, 0x10, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}; /* 1 X 2 00: 40, 20.20 01: 40, 10.10 02: 20, 10.08 03:-40, 08.40 04:+20, 08.20 05: 10, 08.10 06: 40, 04.08 07: 20, 04.04+ 8! 08: 10, 04.04+=9 09: 08, 04.40 0A:-40, 02.40-=B 0B:+20, 02.20* C! 0C: 10, 02.40-=D 0D: 08, 02.20*=E 0E: 04- 02.10 0F: 04- 02.40- 0! for (i=0;i<=15;i++) { printf ("%02X: %02X, %02X.%02X\n", i, msk1[i], msk2[i], msk1[(i + 7) & 0xF]); } */ unsigned long pwd; //pass2pass1 unsigned int pass1, pass2; unsigned char indx[16], seq1[16], key1[16], seq2[16], key2[16]; int show_h4code_init(unsigned char*); void main(int argc, unsigned char *argv[]) { int i, nibble; printf("\nInput 1st (low) HASP password: "); if ((stdin->flags & _F_TERM) == 0) printf("\n"); scanf("%4X", &pass1); printf("Input 2nd (high) HASP password: "); if ((stdin->flags & _F_TERM) == 0) printf("\n"); scanf("%4X", &pass2); pwd=(long) pass2*0x10000+pass1; printf("Results for passwords: %04x:%04x (0x%08lx)\n", pass1, pass2, pwd); /* Calculate unlocking indexes */ pwd = pwd^0x01081989; // xor pass2pass1 by magic constant for (i=0;i<8;i++) // generate indexes as tetrads (nibbles) { indx[i] = pwd >> (4*i) & 0xF; // prolong in reverse order (symmetrically) for second half (7 indexes) indx[15-i] = indx[i] + 7 & 0xF; // main problem when unlocking w/o pass } for (i=0;i<15;i++) if (indx[i]==0) indx[i] = 0xF; // remove all zeroes indx[15] = indx[13]; // backup original index #14 - used for encode/decode indx[13] = 0xB; // put end-of-sequence sign as index #14 /* Calculate unlocking sequences (masks and raw values) */ for (i=0;i<16;i++) { nibble = indx[i]; seq1[i] = msk1[nibble-1]; key1[i] = seq1[i] ^ raw0[i]; if (i<8) seq2[i] = msk2[nibble-1]; else seq2[i] = seq1[i]; key2[i] = seq2[i] ^ raw0[i]; } key1[0] = key1[0] ^ seq2[0]; key2[0] = key1[0]; // new specifics of algo key1[15] = msk1[indx[15]-1] ^ raw0[13]; key2[15] = key1[15]; // h4code printf("\n"); for (i=0;i<15;i++) printf("#%01X ",i); printf(" #%01X ",15); printf("\n"); for (i=0;i<15;i++) printf("%02X ",indx[i]--); printf(" %02X ",indx[15]--); printf("- indices/selectors+1 (hex)"); printf("\n"); for (i=0;i<15;i++) printf("%02d ",indx[i]); printf(" %02d ",indx[15]); printf("- indexes/selectors (decimal)"); printf("\n"); for (i=0;i<15;i++) printf("%02X ",seq1[i]); printf(" %02X ",seq1[15]); printf("- masks seq1"); printf("\n"); for (i=0;i<15;i++) printf("%02X ",key1[i]); printf(" %02X ",key1[15]); printf("- raw key1"); printf("\n"); for (i=0;i<15;i++) printf("%02X ",seq2[i]); printf(" %02X ",seq2[15]); printf("- masks seq2"); printf("\n"); for (i=0;i<15;i++) printf("%02X ",key2[i]); printf(" %02X ",key2[15]); printf("- raw key2"); show_h4code_init(indx); } // DO WE TRUST IN GOD ? // following stuff was found by slightly altering correct unlocking sequence // and then observing how that affects h4code functionality of real hasp4, // main points: // key[7] affects the last initialization byte (by xor 0x11), // shift direction is standard during init (very useful), // due to h4code algo the parity (odd/even) of first 3 bytes of init seq is // critical (very useful) int show_h4code_init(unsigned char *selectors) { int i, x; unsigned char h4iseq[8], h4code_init_id; //h4code init seq printf("\n >"); h4code_init_id = 0; for (i=0;i<5;i++) { h4iseq[i] = selectors[i+3] < 10; //it turned out simpler than expected //decimal notation is handy h4code_init_id |= h4iseq[i]< h4code init seq(%d): ",x); for (i=0;i<8;i++) { if (i<3) { if (h4iseq[i]^x) h4iseq[i] ^= 0x10; } else if (i<5) { if (!h4iseq[i]) h4iseq[i] ^= 0x10^x; else h4iseq[i] ^= x; /* specially for second variant */ } else h4iseq[i] = (h4iseq[i-5]^0x10) & ~(x^1) | x; printf("%02X ", h4iseq[i]); } return h4code_init_id; } // IN HASP WE TRUST