Last active
April 14, 2017 22:15
-
-
Save 25A0/b32c547b57b1346485453084a66f6111 to your computer and use it in GitHub Desktop.
Dumb bruteforcer to find preimages of capital letters([A-Z ]+) for a JavaScript 'hash' function (this one: http://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
/* | |
String.prototype.hashCode = function() { | |
var hash = 0, i, chr; | |
if (this.length === 0) return hash; | |
for (i = 0; i < this.length; i++) { | |
chr = this.charCodeAt(i); | |
hash = ((hash << 5) - hash) + chr; | |
hash |= 0; // Convert to 32bit integer | |
} | |
return hash; | |
}; | |
*/ | |
int advHash(int prev_hash, int buflen, char* buf) | |
{ | |
int hash = prev_hash; | |
int i = 0; | |
for (i = 0; i < buflen; ++i) | |
{ | |
hash = (hash << 5) - hash + buf[i]; | |
} | |
return hash; | |
} | |
int hashCode(int buflen, char* buf) | |
{ | |
return advHash(0, buflen, buf); | |
} | |
// Stores the numeric representation of c in numbuf. Say c is 'a', then "65" | |
// will be written to numbuf and numbuf + 1. | |
void put(char* numbuf, char c) | |
{ | |
// This assumes that the numeric representation has two digits in base 10 | |
if(c >= 100 || c < 10) exit(42); | |
numbuf[0] = '0' + (c/10); | |
numbuf[1] = '0' + (c%10); | |
} | |
// Picks the next word by increasing the last character, and subsequently | |
// increasing previous characters if the last character wrapped around. So, | |
// the next word after "aaz" is "aba", and the next word after "azz" is "baa". | |
// len is the current word length, charbuf is the buffer that contains the | |
// character representation of the current word, and numbuf is the buffer that | |
// contains the numeric representation of the current word. numbuf is twice | |
// as long as charbuf, assuming that each character is represented by two | |
// digits. | |
// Returns the number of changed characters. | |
// If the whole word wrapped around, returns the number of changed characters+1 | |
int next(int len, char* charbuf, char* numbuf) | |
{ | |
if(len == 0) return 0; | |
int i; | |
int wrapped; | |
char newchar; | |
i = len; | |
do { | |
i--; // Go to the previous character | |
newchar = charbuf[i]; | |
wrapped = newchar == ' '; | |
newchar = wrapped? 'A': newchar == 'Z'? ' ': newchar + 1; | |
charbuf[i] = newchar; | |
put(&numbuf[2 * i], newchar); | |
} while(wrapped && i > 0); | |
return wrapped + len - i; | |
} | |
int main(int argc, char const *argv[]) | |
{ | |
setvbuf(stdout, NULL, _IONBF, 0); | |
// How many characters to skip | |
const char* initial_word; | |
const int max_wordlen = 32; | |
int start_len; | |
if(argc > 1) { | |
initial_word = argv[1]; | |
printf("Starting with %s...\n", initial_word); | |
} else { | |
initial_word = "A"; | |
} | |
start_len = strlen(initial_word); | |
if(start_len > max_wordlen) { | |
printf("Cannot start with words longer than %d characters", | |
max_wordlen); | |
exit(1); | |
} | |
int h1 = -1113088476; | |
int h2 = 424205154; | |
char charbuf[ max_wordlen + 1]; | |
char numbuf [2*max_wordlen + 1]; | |
memset(charbuf, 0, sizeof(char) * max_wordlen + 1 ); | |
memset(numbuf, 0, 2 * (sizeof(char) * max_wordlen)+ 1 ); | |
int i; | |
for(i = 0; i < start_len; ++i) { | |
charbuf[i] = initial_word[i]; | |
put(&numbuf[2*i], initial_word[i]); | |
} | |
// cache of hashes, since they don't change that much between two words | |
int hashes[max_wordlen]; | |
int current_len = start_len; | |
while(current_len <= max_wordlen) { | |
printf("Checking length %d\n", current_len); | |
int wrapped; | |
int changed = current_len; | |
do { | |
// Compute the hashes iteratively to speed up computation of | |
// subsequent hashes. | |
// Length of unchanged prefix | |
int unchanged = current_len - changed; | |
int prev_hash = unchanged == 0? 0: hashes[unchanged - 1]; | |
for (i = 0; i < changed; ++i) | |
{ | |
hashes[unchanged + i] = advHash(prev_hash, 2, | |
&numbuf[2*(unchanged + i)]); | |
prev_hash = hashes[unchanged + i]; | |
} | |
int hash = prev_hash; | |
if(hash == h1 || hash == h2) { | |
printf("%s\n", charbuf); | |
} | |
changed = next(current_len, charbuf, numbuf); | |
wrapped = changed > current_len; | |
} while(!wrapped); | |
current_len++; | |
// Initialize the last character of the longer word | |
charbuf[current_len - 1] = 'A'; | |
put(&numbuf[2 * (current_len - 1)], 'A'); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment