1

I have been trying to brute force Key2 of ZipCrypto with first byte of CRC and last byte of encryption header to see how long would it take but i got more than 2000 valid keys. From the APPNOTE, Key2 is the used to decrypt a byte and Key2 is a result of CRC32 meaning it is a 32 bit value which should be found within the range 2147483648 to 2147483648*2.

The password for this test stream is

1234

and the CRC is

77D7DCDE

Then the stream:

50 4B 03 04 14 00 01 00 08 00 68 99 6D 58 DE DC D7 77 CB 82 07 00 0F B1 0A 00 09 00 00 00 6B 65 79 73 30 2E 74 78 74 50 3F 83 D5 C7 D4 69 6E 9B B9 E9 F2 DD 16 D5 EA 5B 41 F9 BC 59 6E 34 E8 2F 2B 49 4E DD 90 3E D8 65 5E 21 42 E6 8C 8C AD 8E

Here is the code sample:

#ifdef LINUX

#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>

typedef pthread_t thread;
typedef pthread_mutex_t mutex;

static inline void mutex_init(mutex *m)
{
    int res = pthread_mutex_init(m, NULL);
    assert(res == 0);
}

static inline void mutex_lock(mutex *m)
{
    int res = pthread_mutex_lock(m);
    assert(res == 0);
}

static inline void mutex_unlock(mutex *m)
{
    int res = pthread_mutex_unlock(m);
    assert(res == 0);
}

static thread spawn_thread(void *(f)(void *), void *arg)
{
    thread t;
    int res = pthread_create(&t, NULL, f, (void *)arg);
    if (res != 0)
        return (thread)NULL;
    return t;
}

static void join_thread(thread t)
{
    pthread_join(t, NULL);
}

static size_t num_threads(void)
{
    return (size_t)sysconf(_SC_NPROCESSORS_ONLN);
}


static uint64_t get_time(void)
{
    struct timespec ts;
    clock_gettime(CLOCK_MONOTONIC, &ts);
    return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
}

#endif


unsigned char decrypt_byte(size_t Key2) {
    uint32_t dkey = Key2;
    unsigned short temp = dkey | 2;
    return (temp * (temp ^ 1)) >> 8;
}


static bool bytecheck(const unsigned char dat)
{
    unsigned char targ = 0x77;//first byte of my Checksum
    
    if(dat == targ)
       {
            return true;
        }
    return false;
}


struct info
{
    unsigned char buffer;
    size_t start;
    size_t end;
};

// Stop when a thread finds a solution.
static volatile bool stop = false;
static void *worker(void *arg);

static thread spawn_worker( size_t start, size_t end, unsigned char buffer)
{
    struct info *info = (struct info *)malloc(sizeof(struct info));
    assert(info != NULL);
    info->start = start;
    info->end = end;
    info->buffer = buffer;
    thread t = spawn_thread(worker, info);
    if (t == (thread)NULL)
    {
        fprintf(stderr, "error: failed to spawn thread");
        exit(EXIT_FAILURE);
    }
    return t;
}
static void *worker(void *arg)
{
    struct info *info = (struct info *)arg;
    size_t start = info->start;
    size_t end = info->end;
    unsigned char buf = info->buffer;
    free(info);
    for(size_t i =start; i < end+1; i++)
    {
        if (stop)
            return NULL;
        unsigned char res = decrypt_byte(i);
        unsigned char C = buf ^ res;

        if (bytecheck(C))
        {
            printf("%zu\n",i);
            stop = true;
            return NULL;
        }
    }

}

//gcc ben.c -pg --std=gnu99 -lz -lm -lpthread -o zipcr

int main()
{

    size_t NUM_WORKERS = num_threads();
    printf("threads = %lu\n", NUM_WORKERS);
    uint64_t t0 = get_time();
    size_t tap = 2147483648;
    size_t port = tap / NUM_WORKERS;
    thread ts[NUM_WORKERS];
    for (size_t i = 0; i < NUM_WORKERS; i++)
        {
            size_t start = tap+ (i*port);
            size_t end = start+port;
            unsigned char buffer = 0xF2;
            ts[i] = spawn_worker(start, end,buffer);
        }
        for (size_t i = 0; i < NUM_WORKERS; i++)
            join_thread(ts[i]);
    uint64_t t1 = get_time();
    printf("\ntime = %lums\n", t1 - t0);

return 0;
}

Why am i getting so many false positive, what is wrong with my code?

3
  • With uint32_t dkey = Key2; unsigned short temp = dkey | 2, why are those two objects different types? Commented Mar 22 at 6:54
  • @chux-ReinstateMonica i have added full code without includes only Commented Mar 22 at 9:44
  • By the way, "is a result of CRC32 meaning it is a 32 bit value which should be found within the range 2147483648 to 2147483648*2" is not correct. The result of a CRC-32 can indeed be any 32-bit value, but a 32-bit value is in the range 0..4294967295.
    – Mark Adler
    Commented Mar 22 at 20:33

1 Answer 1

1

All of that reduces to this:

#include <stdio.h>

int main(void) {
    size_t tap = 2147483648;
    for (size_t i = tap; i < 2 * tap + 1; i++) {
        unsigned short temp = i | 2;
        unsigned char ch = 0xf2 ^ ((temp * (temp ^ 1)) >> 8);
        if (ch == 0x77)
            printf("%zu\n", i);
    }
    return 0;
}

except, that I removed the "stop", so that all results are printed. (By the way, this runs in about two seconds on my machine, so I don't get what the point of all the threading is.)

This prints 8388608 results, which is 1/256 of the number of iterations (minus one). Exactly what you'd expect when checking one byte randomly generated. There is nothing surprising here. What were you expecting?

However running it on 231 cases (plus one for some reason) makes no sense, since the input to the query is only 16 bits (a short)! Or really only 15 bits after the | 2. You only need 32768 iterations to explore the entire domain of your function.

3
  • i am expecting to get only one correct piece of Key2 that decrypts the byte that equates to CRC byte which i used to check correct password and thanks for pointing out that its only 32768 iterations needed Commented Mar 22 at 14:27
  • in short words i need guess correct 16 bit of Key2 and verify that its correct using Checksum byte Commented Mar 22 at 14:33
  • Comments are not the place for questions. There is a question field in stackoverflow for questions. It looks like you need to ask a new question about how the old zip encryption algorithm works.
    – Mark Adler
    Commented Mar 22 at 20:13

Not the answer you're looking for? Browse other questions tagged or ask your own question.