#include #include #include #include #include "block-sha1/sha1.h" /* Find SHA1 collisions within the first 7 hex chars (== 28 bits) */ #define num_entries (1 << 28) /* Need room for 2 ^ 28 entries */ uint32_t a[num_entries]; const char *str (uint32_t x, uint32_t *len) { /* Generate unique, short, readable string from integer */ #define buf_len 15 static char buf[buf_len]; int l; l = snprintf(buf, buf_len, "%u\n", x); if (l >= buf_len || l < 0) { printf("FAIL! l == %u\n", l); exit(1); } if (len) *len = l; return buf; } const unsigned char *sha1 (const char *s, size_t len) { static blk_SHA_CTX sha1_ctx; static unsigned char sha1_result[20]; char hdr[32]; int hdrlen; /* Make it look like a Git blob object */ hdrlen = sprintf(hdr, "blob %lu", len) + 1; blk_SHA1_Init(&sha1_ctx); blk_SHA1_Update(&sha1_ctx, hdr, hdrlen); blk_SHA1_Update(&sha1_ctx, s, len); blk_SHA1_Final(sha1_result, &sha1_ctx); return sha1_result; } const unsigned char *sha1_x (uint32_t x) { uint32_t len = 0; const char *s = str(x, &len); return sha1(s, len); } uint32_t a_index (const unsigned char *h) { uint32_t ret = (h[0] << 20) | (h[1] << 12) | (h[2] << 4) | (h[3] >> 4); return ret; } char *sha1_to_hex(const unsigned char *sha1) { static char buffer[41]; static const char hex[] = "0123456789abcdef"; int i; char *buf = buffer; for (i = 0; i < 20; i++) { unsigned int val = *sha1++; *buf++ = hex[val >> 4]; *buf++ = hex[val & 0xf]; } *buf = '\0'; return buffer; } int main (void) { uint32_t x = 0, i; memset(a, 0xff, num_entries * sizeof(uint32_t)); while (x != 0xffffffff) { i = a_index(sha1_x(x)); if (a[i] == 0xffffffff) { a[i] = x++; continue; } /* Found collision! */ uint32_t y = a[i]; printf("Found collision between entries %u and %u\n", y, x); printf("\t %u == '%s' => %s\n", y, str(y, NULL), sha1_to_hex(sha1_x(y))); printf("\t %u == '%s' => %s\n", x, str(x, NULL), sha1_to_hex(sha1_x(x))); return 1; } return 0; }