mirror of https://github.com/dirtbags/moth.git
Added new puzzle category, crypto.
This commit is contained in:
parent
98f50c3633
commit
ed885cafc5
|
@ -0,0 +1,16 @@
|
|||
<dl>
|
||||
<dt>Alice
|
||||
<dd>Welcome to Bletchley. It works like this: I'll say something to Bob,
|
||||
and he'll say something back. Our communication will be encrypted in some
|
||||
manner, or at least obfuscated. Your job is to get the plaintext, and
|
||||
find the puzzle key.
|
||||
<dt>Bob
|
||||
<dd>Sometimes the plaintext from one puzzle will give you a hint (or the
|
||||
cryptogaphic key) for the next. When we give you such keys, we'll always
|
||||
do so in a straightforward manner. The puzzle key for each puzzle
|
||||
is always in what I say, and there shouldn't be any tricks involved in
|
||||
figuring out what it is.
|
||||
<dt>Alice<dd>Good Luck!
|
||||
<dt>Bob<dd>You'll need it. By the way, the key is 'dirtbags'.
|
||||
</dl>
|
||||
|
|
@ -0,0 +1 @@
|
|||
dirtbags
|
|
@ -0,0 +1,3 @@
|
|||
<dl><dt>Alice<dd>nyy unvy prnfne.
|
||||
<dt>Bob<dd>prnfne vf gur xrl
|
||||
</dl>
|
|
@ -0,0 +1 @@
|
|||
ceasar
|
|
@ -0,0 +1,24 @@
|
|||
plaintext = [b'all hail ceasar.', b'ceasar is the key']
|
||||
|
||||
alpha = b'abcdefghijklmnopqrstuvwxyz'
|
||||
|
||||
def ceasar(text, r):
|
||||
out = bytearray()
|
||||
for t in text:
|
||||
if t in alpha:
|
||||
t = t - b'a'[0]
|
||||
t = (t + r)%26
|
||||
out.append(t + b'a'[0])
|
||||
else:
|
||||
out.append(t)
|
||||
return bytes(out)
|
||||
|
||||
encode = lambda text : ceasar(text, 13)
|
||||
decode = lambda text : ceasar(text, -13)
|
||||
|
||||
c = encode(plaintext[0])
|
||||
print('<dl><dt>Alice<dd>', str(c, 'utf-8'))
|
||||
assert decode(c) == plaintext[0]
|
||||
c = encode(plaintext[1])
|
||||
print('<dt>Bob<dd>', str(c, 'utf-8'), '</dl>')
|
||||
assert decode(c) == plaintext[1]
|
|
@ -0,0 +1,4 @@
|
|||
<dl>
|
||||
<dt>Alice<dd>Vkbd ntg duun puwtvbauwg dbnjwu, hlv bv'd vku dtnu htdbe jpbfebjwud td lduq bf d-hxyud, t vuekfbmlu lduq bf ntfg nxqupf epgjvxcptjkbe twcxpbvnd. Xi exlpdu, bfdvutq xi wuvvup dlhdvbvlvbxf, gxl'pu qxbfc hgvu dlhdvbvlvbxf.
|
||||
<dt>Bob<dd>Vku fuyv vzx jlsswud tpu t hbv qbiiupufv; vkug tpuf'v 'ufepgjvuq' tv tww. Xk, hg vku ztg, vku oug vkbd vbnu bd: 'vku d bd ixp dleod'.
|
||||
</dl>
|
|
@ -0,0 +1 @@
|
|||
the s is for sucks
|
|
@ -0,0 +1,48 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
plaintext = [b"This may seem relatively simple, but it's the same basic "
|
||||
b"principles as used in s-boxes, a technique used in many modern "
|
||||
b"cryptographic algoritms. Of course, instead of letter substitution, "
|
||||
b"you're doing byte substitution.",
|
||||
b"The next two puzzles are a bit different; Frequency counts (of characters) "
|
||||
b"will just reveal random noise. "
|
||||
b"Oh, by the way, the key this time is: 'the s is for sucks'."]
|
||||
|
||||
key = b"thequickbrownfxjmpdvlazygs"
|
||||
|
||||
def encode(text):
|
||||
ukey = key.upper()
|
||||
lkey = key.lower()
|
||||
assert len(set(key)) == 26, 'invalid key'
|
||||
assert key.isalpha(), 'non alpha character in key'
|
||||
out = bytearray()
|
||||
for t in text:
|
||||
if t in lkey:
|
||||
out.append(lkey[t - ord('a')])
|
||||
elif t in ukey:
|
||||
out.append(ukey[t - ord('A')])
|
||||
else:
|
||||
out.append(t)
|
||||
return bytes(out)
|
||||
|
||||
def decode(text):
|
||||
ukey = key.upper()
|
||||
lkey = key.lower()
|
||||
assert len(set(key)) == 26, 'invalid key'
|
||||
assert key.isalpha(), 'non alpha character in key'
|
||||
out = bytearray()
|
||||
for t in text:
|
||||
if t in lkey:
|
||||
out.append(ord('a') + lkey.index(bytes([t])))
|
||||
elif t in ukey:
|
||||
out.append(ord('A') + ukey.index(bytes([t])))
|
||||
else:
|
||||
out.append(t)
|
||||
return bytes(out)
|
||||
|
||||
c = encode(plaintext[0])
|
||||
print('<dl><dt>Alice<dd>', str(c, 'utf-8'))
|
||||
assert decode(c) == plaintext[0]
|
||||
c = encode(plaintext[1])
|
||||
print('<dt>Bob<dd>', str(c, 'utf-8'), '</dl>')
|
||||
assert decode(c) == plaintext[1]
|
|
@ -0,0 +1,6 @@
|
|||
<dl>
|
||||
<dt>Alice
|
||||
<dd>KiTvXqBKSkdOiVHAKgyAdZXuTwudIHqzLHcJBCXRPnxCxuxhUmdKcqvNSgkHGgYmKIdQKAOPMatvHAalZzrZcMCFGaiSklvsNsgbLiJmPagZobKLLpgJJcIMDUvKEXFJMiwVbVFKZdjDMKSvTdugBqjPBdlJTlXnDAvFUPNAFpjFESbJNsgJTnCgNeeZIwGfMkmZwnhGCDrOWWYIPafuXZrKNroELoGjXwtQdlSZZwdDTEZxTulhKsAMFthZfHGqSyxnXzdPShkXVrRqDpoNmuTINniddWNvMThBQEWAVbaRLrChBicNXWYbGuwdAQrvLdfdxEJgPErTwysQ
|
||||
<dt>Bob
|
||||
<dd>LqItUzQMBgbWoNMNNavSLvNyBStVGUCWNjgQxghYZevZYvWuBcdweBUETsflAiXPPLxBFVHUOrdhFDARCngbRdLnHiytxFnSSpknmEvZDioBdxTRLnlAOcAfPKvODVUWJpstBLmtXskjWuBBHizDKXRtPobcLVyQHjtzKiFFMwzzOVnfHTqZGKKDQinlYgZDHzmWhHEKYwtDMmDiUKrZYARDIoceQDugJhrXVOZnAbbFneByTliWIpTsMWoVGGSAIzpBZXOvIihvSBcjABbCXEZIRblsPxJFUnuXrIDBFphHpFSzUrpsNUzbPXdLNBUAInuJifwtRigMdtzWGkvLAwYqIQmEetyEPSrMHNTBRLtZCJZPRcEdDQdEXdnILAAfNpwzEsVWPUzYJVBCVbUTVojLIviMzWRpMqpQotsYAqtDcFpe
|
||||
</dl>
|
|
@ -0,0 +1 @@
|
|||
Rat Fink
|
|
@ -0,0 +1,48 @@
|
|||
#!/usr/bin/python3
|
||||
"""This is non-obvious, so let me elaborate. The message is translated to
|
||||
binary with one character per binary bit. Lower case characters are 1's,
|
||||
and upper case is 0. The letters are chosen at random. Tricky, eh?"""
|
||||
|
||||
import random
|
||||
|
||||
lower = b'abcdefghijklmnopqrstuvwxyz'
|
||||
upper = lower.upper()
|
||||
|
||||
plaintext = [b'The next puzzle starts in the same way, but the last step is '
|
||||
b'different.',
|
||||
b'We wouldn\'t want them to get stuck so early, would we? '
|
||||
b'Rat Fink']
|
||||
|
||||
def encode(text):
|
||||
out = bytearray()
|
||||
mask = 0x80
|
||||
for t in text:
|
||||
for i in range(8):
|
||||
if t & mask:
|
||||
out.append(random.choice(lower))
|
||||
else:
|
||||
out.append(random.choice(upper))
|
||||
t = t << 1
|
||||
|
||||
return bytes(out)
|
||||
|
||||
def decode(text):
|
||||
out = bytearray()
|
||||
i = 0
|
||||
while i < len(text):
|
||||
c = 0
|
||||
mask = 0x80
|
||||
for j in range(8):
|
||||
if text[i] in lower:
|
||||
c = c + mask
|
||||
mask = mask >> 1
|
||||
i = i + 1
|
||||
out.append(c)
|
||||
return bytes(out)
|
||||
|
||||
c = encode(plaintext[0])
|
||||
print('<dl><dt>Alice<dd>', str(c, 'utf-8'))
|
||||
assert decode(c) == plaintext[0]
|
||||
c = encode(plaintext[1])
|
||||
print('<dt>Bob<dd>', str(c, 'utf-8'), '</dl>')
|
||||
assert decode(c) == plaintext[1]
|
|
@ -0,0 +1,60 @@
|
|||
#!/usr/bin/python3
|
||||
'''This is the same as the previous, but it uses non-return to zero to encode
|
||||
the binary.'''
|
||||
|
||||
import random
|
||||
|
||||
lower = b'abcdefghijklmnopqrstuvwxyz'
|
||||
upper = lower.upper()
|
||||
|
||||
plaintext = [b'The next one is in Morris Code. Unlike the previous two, '
|
||||
b'they will actually need to determine some sort of key.',
|
||||
b'Morris code with a key? That sounds bizarre. probable cause']
|
||||
|
||||
def encode(text):
|
||||
out = bytearray()
|
||||
mask = 0x80
|
||||
state = 0
|
||||
for t in text:
|
||||
for i in range(8):
|
||||
next = t & mask
|
||||
if not state and not next:
|
||||
out.append(random.choice(upper))
|
||||
out.append(random.choice(lower))
|
||||
elif not state and next:
|
||||
out.append(random.choice(lower))
|
||||
out.append(random.choice(upper))
|
||||
elif state and not next:
|
||||
out.append(random.choice(upper))
|
||||
out.append(random.choice(lower))
|
||||
elif state and next:
|
||||
out.append(random.choice(lower))
|
||||
out.append(random.choice(upper))
|
||||
state = next
|
||||
t = t << 1
|
||||
|
||||
return bytes(out)
|
||||
|
||||
def decode(text):
|
||||
out = bytearray()
|
||||
i = 0
|
||||
while i < len(text):
|
||||
c = 0
|
||||
mask = 0x80
|
||||
for j in range(8):
|
||||
a = 0 if text[i] in lower else 1
|
||||
b = 0 if text[i+1] in lower else 1
|
||||
assert a != b, 'bad encoding'
|
||||
if b:
|
||||
c = c + mask
|
||||
mask = mask >> 1
|
||||
i = i + 2
|
||||
out.append(c)
|
||||
return bytes(out)
|
||||
|
||||
c = encode(plaintext[0])
|
||||
print('<dl><dt>Alice<dd>', str(c, 'utf-8'))
|
||||
assert decode(c) == plaintext[0]
|
||||
c = encode(plaintext[1])
|
||||
print('<dt>Bob<dd>', str(c, 'utf-8'), '</dl>')
|
||||
assert decode(c) == plaintext[1]
|
|
@ -0,0 +1 @@
|
|||
giant chickens
|
|
@ -0,0 +1,77 @@
|
|||
#!/usr/bin/python3
|
||||
"""This is morris code, except the dots and dashes are each represented by
|
||||
many different possible characters. The 'encryption key' is the set of
|
||||
characters that represent dots, and the set that represents dashes."""
|
||||
|
||||
import random
|
||||
|
||||
dots = b'acdfhkjnpsrtx'
|
||||
dashes = b'begilmoquvwyz'
|
||||
|
||||
morris = {'a': '.-',
|
||||
'b': '-...',
|
||||
'c': '-.-.',
|
||||
'd': '-..',
|
||||
'e': '.',
|
||||
'f': '..-.',
|
||||
'g': '--.',
|
||||
'h': '....',
|
||||
'i': '..',
|
||||
'j': '.---',
|
||||
'k': '-.-',
|
||||
'l': '.-..',
|
||||
'm': '--',
|
||||
'n': '-.',
|
||||
'o': '---',
|
||||
'p': '.--.',
|
||||
'q': '--.-',
|
||||
'r': '.-.',
|
||||
's': '...',
|
||||
't': '-',
|
||||
'u': '..-',
|
||||
'v': '...-',
|
||||
'w': '.--',
|
||||
'x': '-..-',
|
||||
'y': '-.--',
|
||||
'z': '--..',
|
||||
'.': '._._._',
|
||||
',': '--..--',
|
||||
':': '---...'}
|
||||
|
||||
imorris = {}
|
||||
for k in morris:
|
||||
imorris[morris[k]] = k
|
||||
|
||||
plaintext = [b'It is fun to make up bizarre cyphers, but the next one is '
|
||||
b'something a little more standard.',
|
||||
b'All I have to say is: giant chickens.']
|
||||
|
||||
|
||||
def encode(text):
|
||||
out = bytearray()
|
||||
for t in text:
|
||||
if t == ord(' '):
|
||||
out.append(' ')
|
||||
else:
|
||||
for bit in morris[chr(t)]:
|
||||
if bit == '.':
|
||||
out.append(random.choice(dots))
|
||||
else:
|
||||
out.append(random.choice(dashes))
|
||||
out.append(' ')
|
||||
return bytes(out)
|
||||
|
||||
def decode(text):
|
||||
text = text.replace(b' ', b'&')
|
||||
words = text.split(b'&')
|
||||
out = bytearray()
|
||||
for word in words:
|
||||
for c in word.split(' '):
|
||||
|
||||
|
||||
c = encode(plaintext[0])
|
||||
print('<dl><dt>Alice<dd>', str(c, 'utf-8'))
|
||||
assert decode(c) == plaintext[0]
|
||||
c = encode(plaintext[1])
|
||||
print('<dt>Bob<dd>', str(c, 'utf-8'), '</dl>')
|
||||
assert decode(c) == plaintext[1]
|
|
@ -0,0 +1 @@
|
|||
flaming mastiff
|
|
@ -0,0 +1,27 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
key = [43, 44, 227, 31, 255, 42, 194, 197, 187, 11, 92, 234, 57, 67, 45, 40, 66, 226, 214, 184, 167, 139, 210, 233, 22, 246, 150, 75, 186, 145, 86, 224, 17, 131, 24, 98, 74, 248, 213, 212, 72, 101, 160, 221, 243, 69, 113, 142, 127, 47, 141, 68, 247, 138, 124, 177, 192, 165, 110, 107, 203, 207, 254, 176, 154, 8, 87, 189, 228, 155, 143, 0, 220, 1, 128, 3, 169, 204, 162, 90, 156, 208, 170, 222, 95, 223, 188, 215, 174, 78, 48, 50, 244, 116, 179, 134, 171, 153, 15, 196, 135, 52, 85, 195, 71, 32, 190, 191, 21, 161, 63, 218, 64, 106, 123, 239, 235, 241, 34, 61, 144, 152, 111, 20, 172, 117, 237, 120, 80, 88, 200, 185, 109, 137, 37, 159, 183, 30, 202, 129, 250, 58, 9, 193, 41, 164, 65, 126, 46, 158, 132, 97, 166, 6, 23, 147, 105, 29, 38, 119, 76, 238, 240, 12, 201, 245, 230, 14, 206, 114, 10, 25, 60, 83, 236, 18, 231, 39, 77, 55, 252, 229, 100, 7, 28, 209, 51, 148, 181, 198, 225, 118, 173, 103, 35, 149, 91, 108, 219, 168, 140, 49, 33, 122, 82, 216, 53, 205, 13, 73, 249, 180, 81, 19, 112, 232, 217, 96, 62, 99, 4, 26, 178, 211, 199, 151, 102, 121, 253, 136, 130, 104, 133, 146, 89, 5, 157, 70, 84, 242, 182, 93, 251, 54, 16, 175, 56, 115, 94, 36, 27, 79, 59, 163, 125, 2]
|
||||
ikey = [None]*256
|
||||
for i in range(256):
|
||||
ikey[key[i]] = i
|
||||
|
||||
plaintext = [b'I think it's impressive if they get this one. It will take a '
|
||||
b'lot of work to get it right. That is, unless they do '
|
||||
b'something smart like correctly guess the value of spaces. '
|
||||
b'Frequency counts won't just be your friend here, it'll be '
|
||||
b'useful in other places too.',
|
||||
b'I'm not sure if that's enough text to give them the '
|
||||
b'ability to make a good frequency count. It's nice to '
|
||||
b'finally be at a real cypher that allows for things like '
|
||||
b'proper punctuation. Anyway, the key is: flaming mastiff']
|
||||
|
||||
def sbox(text, key):
|
||||
out = bytearray()
|
||||
for t in text:
|
||||
out.append(key[t])
|
||||
return bytes(out)
|
||||
|
||||
for p in plaintext:
|
||||
c = sbox(text, key)
|
||||
assert c == sbox(c, ikey), 'Failure'
|
||||
print(c)
|
|
@ -0,0 +1,11 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
plaintext = [b'I wonderr if they'll try doing a frequency count again? '
|
||||
b'It should work this time as well. Hopefully messing around '
|
||||
b'with simple cyphers like
|
||||
|
||||
|
||||
for p in plaintext:
|
||||
c = sbox(text, key)
|
||||
assert c == sbox(c, ikey), 'Failure'
|
||||
print(c)
|
Loading…
Reference in New Issue