#include #include #include #include #include #include #include "parity.h" #ifdef __WIN32 #include "windows.h" #else #include "unistd.h" #endif #include "pthread.h" #include "nested_util.h" #define MEM_CHUNK 10000 #define TRY_KEYS 50 typedef struct { uint64_t key; int count; } countKeys; typedef struct { NtpKs1 *pNK; uint32_t authuid; uint64_t *keys; uint32_t keyCount; uint32_t startPos; uint32_t endPos; } RecPar; inline static int compar_int(const void *a, const void *b) { if (*(uint64_t *)b == *(uint64_t *)a) return 0; if (*(uint64_t *)b < * (uint64_t *)a) return 1; return -1; } // Compare countKeys structure static int compar_special_int(const void *a, const void *b) { return (((countKeys *)b)->count - ((countKeys *)a)->count); } // keys qsort and unique. static countKeys *uniqsort(uint64_t *possibleKeys, uint32_t size) { unsigned int i, j = 0; int count = 0; countKeys *our_counts; qsort(possibleKeys, size, sizeof(uint64_t), compar_int); our_counts = calloc(size, sizeof(countKeys)); if (our_counts == NULL) { printf("Memory allocation error for our_counts"); exit(EXIT_FAILURE); } for (i = 0; i < size; i++) { if (possibleKeys[i + 1] == possibleKeys[i]) { count++; } else { our_counts[j].key = possibleKeys[i]; our_counts[j].count = count; j++; count = 0; } } qsort(our_counts, j, sizeof(countKeys), compar_special_int); return (our_counts); } // nested decrypt static void *nested_revover(void *args) { struct Crypto1State *revstate, * revstate_start = NULL; uint64_t lfsr = 0; uint32_t i, kcount = 0; bool is_ok = true; RecPar *rp = (RecPar *)args; rp->keyCount = 0; rp->keys = NULL; //printf("Start pos is %d, End pos is %d\r\n", rp->startPos, rp->endPos); for (i = rp->startPos; i < rp->endPos; i++) { uint32_t nt_probe = rp->pNK[i].ntp ^ rp->authuid; uint32_t ks1 = rp->pNK[i].ks1; /* printf(" ntp = %"PRIu32"\r\n", nt_probe); printf(" ks1 = %"PRIu32"\r\n", ks1); printf("\r\n"); */ // And finally recover the first 32 bits of the key revstate = lfsr_recovery32(ks1, nt_probe); if (revstate_start == NULL) { revstate_start = revstate; } while ((revstate->odd != 0x0) || (revstate->even != 0x0)) { lfsr_rollback_word(revstate, nt_probe, 0); crypto1_get_lfsr(revstate, &lfsr); if (((kcount % MEM_CHUNK) == 0) || (kcount >= rp->keyCount)) { rp->keyCount += MEM_CHUNK; // printf("New chunk by %d, sizeof %lu\n", kcount, rp->keyCount * sizeof(uint64_t)); void *tmp = realloc(rp->keys, rp->keyCount * sizeof(uint64_t)); if (tmp == NULL) { printf("Memory allocation error for pk->possibleKeys"); rp->keyCount = 0; is_ok = false; break; } rp->keys = (uint64_t *)tmp; } rp->keys[kcount] = lfsr; kcount++; revstate++; } --kcount; free(revstate_start); revstate_start = NULL; if (!is_ok) { break; } } if (is_ok) { if (kcount != 0) { rp->keyCount = kcount; void *tmp = (uint64_t *)realloc(rp->keys, rp->keyCount * sizeof(uint64_t)); if (tmp == NULL) { printf("Memory allocation error for pk->possibleKeys"); rp->keyCount = 0; free(rp->keys); } else { rp->keys = tmp; } } } else { rp->keyCount = 0; free(rp->keys); } return NULL; } uint64_t *nested(NtpKs1 *pNK, uint32_t sizePNK, uint32_t authuid, uint32_t *keyCount) { #define THREAD_MAX 4 *keyCount = 0; uint32_t i, j, manyThread; uint64_t *keys = (uint64_t *)NULL; manyThread = THREAD_MAX; if (manyThread > sizePNK) { manyThread = sizePNK; } // pthread handle pthread_t *threads = calloc(sizePNK, sizeof(pthread_t)); if (threads == NULL) return NULL; // Param RecPar *pRPs = calloc(sizePNK, sizeof(RecPar)); if (pRPs == NULL) { free(threads); return NULL; } uint32_t average = sizePNK / manyThread; uint32_t modules = sizePNK % manyThread; // Assign tasks for (i = 0, j = 0; i < manyThread; i++, j += average) { pRPs[i].pNK = pNK; pRPs[i].authuid = authuid; pRPs[i].startPos = j; pRPs[i].endPos = j + average; pRPs[i].keys = NULL; // last thread can decrypt more pNK if (i == (manyThread - 1) && modules > 0) { (pRPs[i].endPos) += modules; } pthread_create(&threads[i], NULL, nested_revover, &(pRPs[i])); } for (i = 0; i < manyThread; i++) { // wait thread exit... pthread_join(threads[i], NULL); *keyCount += pRPs[i].keyCount; } free(threads); if (*keyCount == 0) { printf("Didn't recover any keys.\r\n"); free(pRPs); return NULL; } keys = calloc((*keyCount) * sizeof(uint64_t), sizeof(uint8_t)); if (keys == NULL) { printf("Cannot allocate memory to merge keys.\r\n"); free(pRPs); return NULL; } for (i = 0, j = 0; i < manyThread; i++) { if (pRPs[i].keyCount > 0) { // printf("The thread %d recover %d keys.\r\n", i, pRPs[i].keyCount); if (pRPs[i].keys != NULL) { memcpy( keys + j, pRPs[i].keys, pRPs[i].keyCount * sizeof(uint64_t) ); j += pRPs[i].keyCount; free(pRPs[i].keys); } } } countKeys *ck = uniqsort(keys, *keyCount); free(keys); keys = (uint64_t *)NULL; *keyCount = 0; if (ck == NULL) { printf("Cannot allocate memory for ck on uniqsort."); free(ck); free(pRPs); return NULL; } for (i = 0; i < TRY_KEYS; i++) { // We don't known this key, try to break it // This key can be found here two or more times if (ck[i].count > 0) { *keyCount += 1; void *tmp = realloc(keys, sizeof(uint64_t) * (*keyCount)); if (tmp == NULL) { printf("Cannot allocate memory for keys on merge."); free(ck); free(keys); free(pRPs); return NULL; } keys = tmp; keys[*keyCount - 1] = ck[i].key; } } free(ck); free(pRPs); return keys; } // Return 1 if the nonce is invalid else return 0 uint8_t valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, uint8_t *parity) { return ( (oddparity8((Nt >> 24) & 0xFF) == ((parity[0]) ^ oddparity8((NtEnc >> 24) & 0xFF) ^ BIT(Ks1, 16))) && \ (oddparity8((Nt >> 16) & 0xFF) == ((parity[1]) ^ oddparity8((NtEnc >> 16) & 0xFF) ^ BIT(Ks1, 8))) && \ (oddparity8((Nt >> 8) & 0xFF) == ((parity[2]) ^ oddparity8((NtEnc >> 8) & 0xFF) ^ BIT(Ks1, 0))) ) ? 1 : 0; }