As I mentioned in yesterday’s post, there’s an Overwatch graphic of some base64 text with an unclear font… But what’s the point of writing something to solve a puzzle when you aren’t sure you have the right question?
So I made this little function which takes a base64-string and generates visually-similar versions:
#!/usr/bin/python import itertools import binascii def B64Variants(val, confusions = None): if confusions is None: confusions = ["Il1","O0"] # Use defaults val = val.translate(None, " \n\t") # Remove whitespace sections = [] for char in val: confused = False for group in confusions: if char in group: confused = True sections.append(list(group)) if not confused: if (len(sections) > 0) and isinstance(sections[-1],str): sections[-1] = sections[-1] + char else: sections.append(char) # Tidy up so we have a consistent list-of-lists for i,v in enumerate(sections): if isinstance(v,str): sections[i] = [v] for varBits in apply(itertools.product, sections): yield "".join(varBits) if __name__ == "__main__": sample = binascii.b2a_base64("Hello, World!") print "given", sample for var in B64Variants(sample): print "maybe", var
Example output:
given SGVsbG8sIFdvcmxkIQ== maybe SGVsbG8sIFdvcmxkIQ== maybe SGVsbG8sIFdvcmxklQ== maybe SGVsbG8sIFdvcmxk1Q== maybe SGVsbG8slFdvcmxkIQ== maybe SGVsbG8slFdvcmxklQ== maybe SGVsbG8slFdvcmxk1Q== maybe SGVsbG8s1FdvcmxkIQ== maybe SGVsbG8s1FdvcmxklQ== maybe SGVsbG8s1Fdvcmxk1Q==
I think the next step is to try hooking this up to code which tries to decode the cipher-stream byte by byte, skipping to a new password (or a new Base64 source-string) when the decoded byte goes outside conventional ASCII. (I’m gambling that it’ll contain an ASCII message, if it doesn’t then it’s hard to know if you’ve successfully cracked it.)
Finally, what happens if we apply this to one of the transcriptions people have made from the Overwatch Summer Games video?
U2FsdGVkXI+vupppZksvRf5pq5g5XjFRIipRkwBOKIY96Qsv2Lm+3IcmzaAILwytX/z66ZVWEQMccfIg+9m5UbuI+sit+A9cenDxxqkIaxbm4cMeh2oKhqIHhdaBKOi6XX2XDWpa6+P5o9MQw== U2FsdGVkXI+vupppZksvRf5pq5g5XjFRIipRkwBOKIY96Qsv2Lm+3IcmzaAILwytX/z66ZVWEQMccfIg+9m5UbuI+sit+A9cenDxxqkIaxbm4cMeh2oKhqIHhdaBK0i6XX2XDWpa6+P5o9MQw== U2FsdGVkXI+vupppZksvRf5pq5g5XjFRIipRkwBOKIY96Qsv2Lm+3IcmzaAILwytX/z66ZVWEQMccfIg+9m5UbuI+sit+A9cenDxxqkIaxbm4cMeh2oKhqlHhdaBKOi6XX2XDWpa6+P5o9MQw== U2FsdGVkXI+vupppZksvRf5pq5g5XjFRIipRkwBOKIY96Qsv2Lm+3IcmzaAILwytX/z66ZVWEQMccfIg+9m5UbuI+sit+A9cenDxxqkIaxbm4cMeh2oKhqlHhdaBK0i6XX2XDWpa6+P5o9MQw== U2FsdGVkXI+vupppZksvRf5pq5g5XjFRIipRkwBOKIY96Qsv2Lm+3IcmzaAILwytX/z66ZVWEQMccfIg+9m5UbuI+sit+A9cenDxxqkIaxbm4cMeh2oKhq1HhdaBKOi6XX2XDWpa6+P5o9MQw== ..snip..
78,732 variations in total. Uh oh. I’m happy with the output, but whatever I use to go through these, it needs to be able to memoize or somehow reuse whatever progress it can from variant-to-variant, rather than starting over with each new string.
P.S.
A more-realistic number would be 6,561, since we know that the first 1
is good because it’s part of the OpenSSL header, and because the letter O
is visibly wider than zero.