// AoC 2016 day 14 #define NDEBUG "gcc -O3 14.c" #include #include #include #include #include #include #include "../_.h" E KS memmem(KS,size_t,KS,size_t); // GNU C has it, this definition is enough here #define U4 uint32_t // 4 bytes #define U1 uint8_t // 1 byte // md5 ------------------------------------------------------------------------- // from http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5 // leftrotate function definition #define FX(x, y, z) (z ^ ( x & (y ^ z) )) #define GX(x, y, z) (y ^ ( z & (y ^ x) )) #define HX(x, y, z) ((x) ^ (y) ^ (z)) #define IX(x, y, z) ((y) ^ ((x) | (~z))) #define LEFTROTATE(x, c) (((x) << (c)) | ((x) >> (32 - (c)))) #define FF(a, b, c, d, x, s, ac) { (a) += FX((b), (c), (d)) + (x) + (U4)(ac); \ (a) = LEFTROTATE((a), (s)); (a) += (b); } #define GG(a, b, c, d, x, s, ac) { (a) += GX((b), (c), (d)) + (x) + (U4)(ac); \ (a) = LEFTROTATE((a), (s)); (a) += (b); } #define HH(a, b, c, d, x, s, ac) { (a) += HX((b), (c), (d)) + (x) + (U4)(ac); \ (a) = LEFTROTATE((a), (s)); (a) += (b); } #define II(a, b, c, d, x, s, ac) { (a) += IX((b), (c), (d)) + (x) + (U4)(ac); \ (a) = LEFTROTATE((a), (s)); (a) += (b); } U4 to_int32(K U1* bytes) __ R (U4)bytes[0] | ((U4)bytes[1] << 8) | ((U4)bytes[2] << 16) | ((U4)bytes[3] << 24); _ V to_bytes(U4 val, OUT U1* bytes) __ bytes[0] = (U1)val; bytes[1] = (U1)(val >> 8); bytes[2] = (U1)(val >> 16); bytes[3] = (U1)(val >> 24); _ V to_hex(U4 val, OUT U1* twochars) __ twochars[0] = "0123456789abcdef"[val >> 4]; twochars[1] = "0123456789abcdef"[val & 0x0f]; _ V to_digest(U4 val, OUT U1* eightchars) __ to_hex( (val )&0x00ffu, OUT eightchars ); to_hex( (val >> 8)&0x00ffu, OUT eightchars+2 ); to_hex( (val >> 16)&0x00ffu, OUT eightchars+4 ); to_hex( (val >> 24)&0x00ffu, OUT eightchars+6 ); _ #define MD5HSZ 32 // 32 chars in digest for 16 bytes of md5. no '\0' at the end! V md5( K U1* initial_msg, size_t initial_len, OUT U1* digest ) __ // Returns 32-char hex digest! Without trailing '\0' <<<<<<<<<<<<<<<<<<<<<<<<< register U4 h0, h1, h2, h3; // These vars will contain the hash O U1 md5buf[100000]; // preallocated buffer, in order to skip malloc U1* msg = NULL; // Message (to prepare) U4 w[16]; register U4 a, b, c, d, i, f, temp; // Initialize variables - simple count in nibbles: h0 = 0x67452301; h1 = 0xefcdab89; h2 = 0x98badcfe; h3 = 0x10325476; //Pre-processing: //append "1" bit to message //append "0" bits until message length in bits is 448 (mod 512) //append length mod (2^64) to message size_t new_len = initial_len + 1; int mod = new_len & 0x3F; if(mod > 56) new_len += 120 - mod; else if(mod < 56) new_len += 56 - mod; // allocate a msg with new length if(new_len+8>=sizeof(md5buf)) msg = (U1*)malloc(new_len + 8); else msg = md5buf; // copy the original msg to the new one memcpy(msg, initial_msg, initial_len); // append "1" bit. Note that for a computer, 8bit is the minimum length of a datatype msg[initial_len] = 0x80; if(initial_len + 1 < new_len) memset(&msg[initial_len + 1], 0, sizeof(U1) * (new_len - 1 - initial_len)); size_t offset; for(offset = initial_len + 1; offset < new_len; ++offset) msg[offset] = 0; // append "0" bits // append the lower 32 bits of len in bits at the end of the buffer. to_bytes(initial_len<<3, msg + new_len); // append the higher 32 bits of len in bits at the end of the buffer. to_bytes(initial_len >> 29, msg + new_len + 4); // Process the message in successive 512-bit chunks: //for each 512-bit chunk of message: for(offset=0; offset=sizeof(md5buf)) free(msg); //var char digest[16] := h0 append h1 append h2 append h3 //(Output is in little-endian) //*((U4*)digest) = h0; //*((U4*)(digest + 4)) = h1; //*((U4*)(digest + 8)) = h2; //*((U4*)(digest + 12)) = h3; to_digest(h0, digest); to_digest(h1, digest + 8); to_digest(h2, digest + 16); to_digest(h3, digest + 24); _ U testmd5() __ // https://en.wikipedia.org/wiki/MD5 U1 msg[] = "The quick brown fox jumps over the lazy dog"; C digest[32]; md5( msg, sizeof(msg)-1, OUT digest ); R memcmp( digest, "9e107d9d372bb6826bd81d3542a419d6", 32 ) == 0; _ // ----------------------------------------------------------------------------- C salt[] = "jlmsuwbz"; C hashes[40000][MD5HSZ]; // plain md5 hashes C sthshs[40000][MD5HSZ]; // stretched hashes U nhashes = 0; // number of calculated hashes U nsthshs = 0; // same for stretched hashes KS getmd5( U i ) __ // md5, possible cached, of salt + number i if( i 8.71 --> 6.03 if( !testmd5() ) R 1; C h[MD5HSZ]; md5( "abc0", 4, OUT h ); // test also sample from Day 14 if( memcmp( h, "577571be4de9dcce85a041ba0410f29f", MD5HSZ )!=0 ) R 1; printf( "%u\n", solve(getmd5) ); printf( "%u\n", solve(getsh) ); R 0; _