cpkzip

What is the correct Legacy Zip encryption password processing stage?


I have grabbed the internal state (key0,key1 and key2) after password processing and i know the password, so i need to get back to initial values (key0= 0x12345678, key1=0x23456789, key2=0x34567890) but i get wrong values,even if i start with initial values and process the password, i still get wrong keys again.

From the code below i get:

88CBA221 E60DABEC 66316770

the code:

#include <time.h>
#include <stdlib.h>
#include <assert.h>
#include <ctype.h>
#include <getopt.h>
#include <math.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>


#define CRCPOLY      0xEDB88320 //0x04C11DB7 0xEDB88320 //
#define CONSTx      0x08088405U /* 134775813 */
#define INVCONST    0xd94fa8cdU /* CONSTx^{-1} */
#define CRC32(x,c)  (((x)>>8)^crctab[((x)^(c))&0xff])
#define INVCRC32(x,c)   (((x)<<8)^crcinvtab[((x)>>24)&0xff]^((c)&0xff))

uint32_t    crctab[256],crcinvtab[256];

static void mkCrcTab( ){
    unsigned int i, j, c,x;
    for( i = 0; i < 256; i++ )
    {
        c = i;
        for( j = 0; j < 8; j++ )
            if( c&1 )
                c = (c>>1) ^ CRCPOLY;
            else
                c = (c>>1);
        crctab[i] = c;
        crcinvtab[c>>24] = (c<<8) ^ i;
    }
}

int main(){
    int i;
    mkCrcTab( );
    uint32_t t0 = 0xD087EB63;
    uint32_t t1 = 0x375335B3;
    uint32_t t2 = 0x68557E28;
    uint8_t passw[10] = {
        1,2,3,4,5,6,7,8,9,0
    };
    for(int x=9; x>=0; x--){
        t0 = INVCRC32(t0,passw[x]);     
        t1 = ((t1-1)*INVCONST)- (t0&0xFF);
        t2 = INVCRC32(t2,t1>>24);
    }
    printf("%08X %08X %08X\n",t0,t1,t2);
}

And if start from password processing i get: 336FFBE3 459C8ABD 24BBF0CB

Instead of :

D087EB63 375335B3 68557E28

I have no explanation as to why this happens.

This is the output of the actual algorithm processing password:

12345678 23456789 34567890
0F12CD62 11483398 9A8BE5CE
6B644339 B7A8C716 2943427D
E0BE8D5D 70BB3140 7E983FFF
348E6771 CECF3C76 51A09805
71850BEE F0D3C2F5 CD86A60B
8879DFED 14335B6B 8DC58B53
668E4215 BC2EC981 30383A62
45B9D237 DAACD099 C58A0384
E7FD94D5 5CCCCF27 88CDD0E5
D087EB63 375335B3 68557E28

Solution

  • The way it is written above is correct except for one thing only, the password is declared as a byte array instead of char array which is then type cast to byte at the processing stage so this

    t0 = INVCRC32(t0,(uint8_t)passw[x]);
    

    and this are the answers:

    char passw[10] = {
        '1','2','3','4','5','6','7','8','9','0'
    };