Skip to content

Instantly share code, notes, and snippets.

@Nullreff
Last active December 20, 2015 15:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Nullreff/6151701 to your computer and use it in GitHub Desktop.
Save Nullreff/6151701 to your computer and use it in GitHub Desktop.
// Called whenever you press "Reload Comic"
function reload_comic(){fetch_and_set("http://prizes.prequeladventure.com/wlf2/qwtake-control-data.json", '#comic', "#votes", ".comicadjustment");}
function fetch_and_set(url, target, votes, domadjust ) {
jQuery.getJSON(url, function (data) {
/* Data is:
* f: Url with a bunch of data, seems to always be:
* "http://prizes.prequeladventure.com/wlf2/qwtake-control-crypt.txt"
*
* Passed into the 'pd' function along with the data taken for 'f' url:
* i: IV used to decode: https://code.google.com/p/crypto-js/#Custom_Key_and_IV
* k: decryption key
* l: Number of parts to remove from the start
*
* Uninteresting:
* msg: Not used
* v: Number of votes so far
*
*
*/
jQuery.get(data.f, function (ct) {
// Part that displays the comic
jQuery(target).html(pd(ct, data.l, data.k, data.i));
// And a bunch of other crap we don't care about
if ( votes ) { jQuery(votes).text(data.v); }
if ( domadjust ) {
jQuery(domadjust).filter('.notcomplete').toggle(data.l>0).end().filter('.complete').toggle(data.l<=0);
}
});
});
}
// This does all the decryption
function pd(data, start, key, iv) {
// https://code.google.com/p/crypto-js/
var C=CryptoJS, cts=[];
iv = C.enc.Hex.parse(iv);
key = C.enc.Base64.parse(key);
// The comic is stored as Base64, AES encrypted chunks taken from
// http://prizes.prequeladventure.com/wlf2/qwtake-control-crypt.txt
// when it's pulled in, all the parts are split up then all the ones
// we haven't "unlocked" yet are removed from the start
jQuery.each(data.split(/\r?\n/).slice(start), function (i, v) {
// So it decodes the first one using the key (which changes every
// time new stuff is unlocked) and IV (which appears to be constant).
var ct = C.AES.decrypt(
C.lib.CipherParams.create({ciphertext: C.enc.Base64.parse(v)}),
key,
{ iv: iv }
).toString(C.enc.Latin1);
// Save it to the array (comic data comes in reverse order).
cts.unshift(ct);
// TRICKY, generates a new key using the stuff it just decrypted
// so each part has a different decryption key that is generated
// using the previous part and its decryption key. So you only
// have to send one key and the rest of the comic decrypts itself
key = C.SHA1(ct + key);
});
return cts.join("");
}
// So in order to unlock the entire comic, you need the key for the first part
// and then set 'start' to 0. Very simple but requires knowing the key.
//
// If anyone can brute force the key for "XUkMfuNkgNnR2KWckpPDTA=="(base64),
// the whole comic is available. Although by the time you do, it's probably
// already going to have enough votes...
@chmarr
Copy link

chmarr commented Aug 5, 2013

No one has been able to produce a SHA1 collision. Even so, it would narrow the potential answer space down to the point where you could manually verify each result.

With a larger file you can do that anyway: If after 2 or 3 blocks the decrypted result is still in the ASCII range, you effectively confirmed you have the right key (or, technically, a key/iv combination).

True, I think I'm just arguing for the sake of arguing now...

What? That never happens on the internet! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment