diff --git a/puzzles/crypto/140/index.html b/puzzles/crypto/140/index.html new file mode 100644 index 0000000..6dc2f61 --- /dev/null +++ b/puzzles/crypto/140/index.html @@ -0,0 +1,2 @@ +
Alice
fj v jk taf phlp rpv zs z llo zy xq okb a fru rwzd uhjp ah mmnt je jvh pos r qnlx wsvm pvbr fpkx j dot sja obxxqy idpr csm o u thhh c vp h ihdo y zmm ia j tp cfs jxf yue uv h u kssx cn et bqk pw kzsc tc o u jgnt t mg gmy amr k hjp b pu br bkh dz tqk qtt xgxypy +
Bob
cy rurj xepn nt akxj rl jrrz c e oly nnt fu usiv rr dta wqyxnr goh sj aq ia m edvt fssp ps wtqd ohl r la rht szdupb
diff --git a/puzzles/crypto/140morris.py b/puzzles/crypto/140morris.py index 2f50b9f..923a48c 100644 --- a/puzzles/crypto/140morris.py +++ b/puzzles/crypto/140morris.py @@ -34,7 +34,7 @@ morris = {'a': '.-', 'x': '-..-', 'y': '-.--', 'z': '--..', - '.': '._._._', + '.': '.-.-.-', ',': '--..--', ':': '---...'} @@ -42,32 +42,45 @@ imorris = {} for k in morris: imorris[morris[k]] = k -plaintext = [b'It is fun to make up bizarre cyphers, but the next one is ' +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.'] + b'all i have to say is: giant chickens.'] + def encode(text): out = bytearray() for t in text: if t == ord(' '): - out.append(' ') + out.extend(b' ') 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) + out.append(ord(' ')) + return bytes(out[:-1]) def decode(text): - text = text.replace(b' ', b'&') + text = text.replace(b' ', b'&') +# print(text) words = text.split(b'&') out = bytearray() for word in words: - for c in word.split(' '): - +# print(word) + word = word.strip() + for parts in word.split(b' '): + code = [] + for part in parts: + if part in dots: + code.append('.') + else: + code.append('-') + code = ''.join(code) + out.append(ord(imorris[code])) + out.append(ord(' ')) + return bytes(out[:-1]) c = encode(plaintext[0]) print('
Alice
', str(c, 'utf-8')) diff --git a/puzzles/crypto/150/index.html b/puzzles/crypto/150/index.html new file mode 100644 index 0000000..4e99057 --- /dev/null +++ b/puzzles/crypto/150/index.html @@ -0,0 +1,2 @@ +
Alice
1 11 eb 47 20 3f bf 11 20 eb d4 ef 11 20 a1 40 7b 34 ef ef 20 22 34 11 20
55 11 eb 47 34 98 11 c3 34 eb 11 eb 47 20 ef 11 da 3f 34 71 11 11 1 eb 11
3d 20 15 15 11 eb 99 bf 34 11 99 11 15 da eb 11 da 55 11 3d da 7b bf 11 eb
da 11 c3 34 eb 11 20 eb 11 7b 20 c3 47 eb 71 11 11 5f 47 99 eb 11 20 ef f3
11 f1 3f 15 34 ef ef 11 eb 47 34 98 11 87 da 11 ef da a1 34 eb 47 20 3f c3
11 ef a1 99 7b eb 11 15 20 bf 34 11 c4 da 7b 7b 34 c4 eb 15 98 11 c3 f1 34
ef ef 11 eb 47 34 11 22 99 15 f1 34 11 da 55 11 ef 40 99 c4 34 ef 71 11 8f
7b 34 6a f1 34 3f c4 98 11 c4 da f1 3f eb ef 11 3d da 3f d4 eb 11 be f1 ef
eb 11 f 34 11 98 da f1 7b 11 55 7b 20 34 3f 87 11 47 34 7b 34 f3 11 20 eb
d4 15 15 11 f 34 11 f1 ef 34 55 f1 15 11 20 3f 11 da eb 47 34 7b 11 40 15
99 c4 34 ef 11 eb da da 71 +
Bob
1 d4 a1 11 3f da eb 11 ef f1 7b 34 11 20 55 11 eb 47 99 eb d4 ef 11 34 3f
da f1 c3 47 11 eb 34 90 eb 11 eb da 11 c3 20 22 34 11 eb 47 34 a1 11 eb 47
34 11 99 f 20 15 20 eb 98 11 eb da 11 a1 99 bf 34 11 99 11 c3 da da 87 11
55 7b 34 6a f1 34 3f c4 98 11 c4 da f1 3f eb 71 11 11 1 eb d4 ef 11 3f 20
c4 34 11 eb da 11 55 20 3f 99 15 15 98 11 f 34 11 99 eb 11 99 11 7b 34 99
15 11 c4 98 40 47 34 7b 11 eb 47 99 eb 11 99 15 15 da 3d ef 11 55 da 7b 11
eb 47 20 3f c3 ef 11 15 20 bf 34 11 40 7b da 40 34 7b 11 40 f1 3f c4 eb f1
99 eb 20 da 3f 11 99 3f 87 11 c4 99 40 20 eb 99 15 20 6f 99 eb 20 da 3f 71
11 8 3f 98 3d 99 98 f3 11 eb 47 34 11 bf 34 98 11 20 ef 6e 11 55 15 99 a1
20 3f c3 11 a1 99 ef eb 20 55 55
diff --git a/puzzles/crypto/150sbox.py b/puzzles/crypto/150sbox.py index d6e7e21..78581f3 100644 --- a/puzzles/crypto/150sbox.py +++ b/puzzles/crypto/150sbox.py @@ -1,19 +1,14 @@ #!/usr/bin/python3 +import crypto + 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'] +alice = b'''I think it's impressive if they get this one. It will take a lot of work to get it right. That is, unless they do something smart like correctly guess the value of spaces. Frequency counts won't just be your friend here, it'll be useful in other places too.''' +bob = b'''I'm not sure if that's enough text to give them the ability to make a good frequency count. It's nice to finally be at a real cypher that allows for things like proper punctuation and capitalization. Anyway, the key is: flaming mastiff''' def sbox(text, key): out = bytearray() @@ -21,7 +16,7 @@ def sbox(text, key): out.append(key[t]) return bytes(out) -for p in plaintext: - c = sbox(text, key) - assert c == sbox(c, ikey), 'Failure' - print(c) +encode = lambda t: sbox(t, key) +decode = lambda t: sbox(t, ikey) + +crypto.mkIndex(encode, decode, alice, bob, crypto.hexFormat) diff --git a/puzzles/crypto/160/index.html b/puzzles/crypto/160/index.html new file mode 100644 index 0000000..68804af --- /dev/null +++ b/puzzles/crypto/160/index.html @@ -0,0 +1,2 @@ +
Alice
e8 c3 8c d5 c3 d9 8c d8 c4 c5 c2 c7 8c d8 c4 c9 d5 8b c0 c0 8c d8 de d5 8c
cd c2 c3 d8 c4 c9 de 8c ca de c9 dd d9 c9 c2 cf d5 8c cf c3 d9 c2 d8 93 8c
8c e5 d8 8c c1 c5 cb c4 d8 8c ce c9 8c ce c9 d8 d8 c9 de 8c c5 ca 8c d8 c4
c9 d5 8c c6 d9 df d8 8c c0 c3 c3 c7 c9 c8 8c ca c3 de 8c dc cd d8 d8 c9 de
c2 df 82 +
Bob
f5 c3 d9 8b c8 8c ce c9 8c cd c1 cd d6 c9 c8 8c cd d8 8c c4 c3 db 8c c3 ca
d8 c9 c2 8c d8 c4 c5 df 8c c5 df 8c d9 df c9 c8 8c c5 c2 8c c0 c5 c9 d9 8c
c3 ca 8c de c9 cd c0 8c cf de d5 dc d8 c3 82 8c 8c e5 d8 8b df 8c cd ce c3
d9 d8 8c cd df 8c c9 ca ca c9 cf d8 c5 da c9 8c cd df 8c cd 8c cf c9 cd df
cd de 8c cf d5 dc c4 c9 de 82 8c 8c cf c4 de c3 c2 c5 cf 8c ca cd c5 c0 d9
de c9
diff --git a/puzzles/crypto/160/key b/puzzles/crypto/160/key new file mode 100644 index 0000000..7f99998 --- /dev/null +++ b/puzzles/crypto/160/key @@ -0,0 +1 @@ +chronic failure diff --git a/puzzles/crypto/160xor.py b/puzzles/crypto/160xor.py index 7c68b88..f35c4b4 100644 --- a/puzzles/crypto/160xor.py +++ b/puzzles/crypto/160xor.py @@ -1,11 +1,16 @@ #!/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 +import crypto +alice = b'''Do you think they'll try another frequency count? It might be better if they just looked for patterns.''' +bob = b'''You'd be amazed at how often this is used in lieu of real crypto. It's about as effective as a ceasar cypher. chronic failure''' -for p in plaintext: - c = sbox(text, key) - assert c == sbox(c, ikey), 'Failure' - print(c) +key = 0xac + +def encode(text): + out = bytearray() + for t in text: + out.append(t ^ key) + return bytes(out) + +crypto.mkIndex(encode, encode, alice, bob, crypto.hexFormat) diff --git a/puzzles/crypto/170/index.html b/puzzles/crypto/170/index.html new file mode 100644 index 0000000..7e0313d --- /dev/null +++ b/puzzles/crypto/170/index.html @@ -0,0 +1,2 @@ +
Alice
x_tee tnhpu __our faez_ lrszt
le_ar l_ipa sston p_iyn hcok_
eisel roi__ hnsta _er_n t.iss
tooip elnk_ _i,ts sibit u__os
,sins ltule _iond mid__ y_ern
pcrts ts_ey o__m_ .__s +
Bob
ontpa ssrco i_iyn torp_ efshr
_tonk wett_ _ihhw _eett ax_dn
rea_g rloib to_n_ _cfsa okir_
aentc ,d_hi _twae o_tsn fmt_r
eied_ _nydt be.kh y__ee in_la
ngdsa gtp_r _t_af eeore andpd
d_nt_ _iuhw __lrs rolto a_dem
nr_xe .rtt_ iigys nf_ni ee_cl
diff --git a/puzzles/crypto/170/key b/puzzles/crypto/170/key new file mode 100644 index 0000000..d1265dd --- /dev/null +++ b/puzzles/crypto/170/key @@ -0,0 +1 @@ +terrifying silence diff --git a/puzzles/crypto/170transpose.py b/puzzles/crypto/170transpose.py new file mode 100644 index 0000000..c4dd231 --- /dev/null +++ b/puzzles/crypto/170transpose.py @@ -0,0 +1,30 @@ +import crypto + +alpha = b'abcdefghiklmnoprstuw' + +alice = b'''The next four puzzles are all transposition cyphers like this one. Transposition, like substition, is still used in modern crypto systems. ''' +bob = b'''Transposition cyphers often work with the text arranged into blocks of a certain width, often as determined by the key. Dangling parts are often padded with nulls or random text. terrifying silence ''' +alice = alice.replace(b' ', b'_').lower() +bob = bob.replace(b' ', b'_').lower() + +map = [6, 3, 0, 5, 2, 7, 4, 1] +imap = [2, 7, 4, 1, 6, 3, 0, 5] + +def transform(text, map): + assert len(text) % 8 == 0, 'Text must be multiple of 8 in length. '\ + '%d more chars needed.' % (8 - len(text) % 8) + + out = bytearray() + i = 0 + while i < len(text): + for j in range(8): + out.append( text[i + map[j]] ) + i = i+8 + return bytes(out) + +encode = lambda t : transform(t, map) +decode = lambda t : transform(t, imap) + +crypto.mkIndex(encode, decode, alice, bob, crypto.groups) + + diff --git a/puzzles/crypto/180/index.html b/puzzles/crypto/180/index.html new file mode 100644 index 0000000..0cac490 --- /dev/null +++ b/puzzles/crypto/180/index.html @@ -0,0 +1,3 @@ +b"t_iwey_6hf_ussre'd_sysuysoshfsan_3_eonz_t.tr_noiutp_nteo_st0_7_rezmr__ewo_nbihade_ro_i_4.k_xluo_t_etagsoe_apk_nea1__ettecnihg'_p_tnrsr.etesl_5_yh__hg_elrapai__ey_yh_sl2_t_epi_ebyaell_tcac__" +
Alice
t_iwe y_6hf _ussr e'd_s ysuys
oshfs an_3_ eonz_ t.tr_ noiut
p_nte o_st0 _7_re zmr__ ewo_n
bihad e_ro_ i_4.k _xluo _t_et
agsoe _apk_ nea1_ _ette cnihg
'_p_t nrsr. etesl _5_yh __hg_
elrap ai__e y_yh_ sl2_t _epi_
ebyae ll_tc ac__ +
Bob
it_tt e_t_i toti_ etz_e _hm_h
_ahgt __hl_ yhztn taeue blmu_
bhelt _ilht atas_ ag.ew ean_h
fseie k_nes so_so _r,ie o__sn
et_sa ir_sn td_t_ rpi_c _oi_m
cii_' o_w?k _usse
diff --git a/puzzles/crypto/180/key b/puzzles/crypto/180/key new file mode 100644 index 0000000..4c3e56d --- /dev/null +++ b/puzzles/crypto/180/key @@ -0,0 +1 @@ +The key for this puzzle is this sentence diff --git a/puzzles/crypto/180rotate.py b/puzzles/crypto/180rotate.py new file mode 100644 index 0000000..8f57e25 --- /dev/null +++ b/puzzles/crypto/180rotate.py @@ -0,0 +1,47 @@ +import crypto + +import itertools + +width = 7 + +alice = b'''The key for this one was essentially 0 1 2 3 4 5 6 7. The key for the next puzzle is much stronger. I bet they're glad we're not also applying a substitution cypher as a secondary step. ''' +bob = b'''I take that to mean it uses the same basic algorithm. I guess it won't be too hard then, will it? The key for this puzzle is this sentence''' +alice = alice.lower().replace(b' ', b'_') +bob = bob.lower().replace(b' ', b'_') + +def rotate(text): + out = bytearray() + assert len(text) % width == 0, 'At %d of %d.' % (len(text) % width, width) + + slices = [bytearray(text[i:i+width]) for i in range(0, len(text), width)] + nextSlice = slices.pop(0) + while len(out) < len(text): + if nextSlice: + out.append(nextSlice.pop(0)) + slices.append(nextSlice) + nextSlice = slices.pop(0) + + return bytes(out) + +def unrotate(text): + out = bytearray() + assert len(text) % width == 0 + + slices = [] + for i in range(len(text) // width): + slices.append([]) + + inText = bytearray(text) + while inText: + slice = slices.pop(0) + slice.append(inText.pop(0)) + slices.append(slice) + + for slice in slices: + out.extend(slice) + + return bytes(out) + +print(rotate(alice)) + +crypto.mkIndex(rotate, unrotate, alice, bob, crypto.groups) diff --git a/puzzles/crypto/190/index.html b/puzzles/crypto/190/index.html new file mode 100644 index 0000000..f77e708 --- /dev/null +++ b/puzzles/crypto/190/index.html @@ -0,0 +1,2 @@ +
Alice
e_mse o_rtt pii'i n_dru ueu._
ieron niosn i,ot_ nuvi_ toowd
_idcg o__st _nhae legoh lnfdh
rceir tiasn d_koo efe_s ii_to
__dp_ hroo_ tnyw_ _rt_t +
Bob
'slu_ cnnmo eeq_b gutnn tptn_
st_s_ sodsp ioyr; __r_r fmssl
oiss. aiimn abato ebify t_nso
i_til wamio asnte ensfn necoh
on_tt _shtc na_ol ssloi talrf
_io__ hti.m nsioo i_uor ni)is
_n_u_ c_rgy utto_ o__ia ftase
tt_ro h_c__ hmton _ehec nasta
__rt( rooai ha'fo il_tp yao_e
dacai imnpb _iaft tsiye toa_a
fscu_ i_bu_ ghea_ tpisf thnii
rpfpa _wtyg i_utt _ro_i _tcna
diff --git a/puzzles/crypto/190rotate.py b/puzzles/crypto/190rotate.py new file mode 100644 index 0000000..8d9da3d --- /dev/null +++ b/puzzles/crypto/190rotate.py @@ -0,0 +1,42 @@ +import crypto + +import itertools + +width = 5 + +alice = b'''If we did the morris code encoding prior to this transposition, I don't think anyone would ever figure out the solution.''' +bob = b'''That's basically true of the combination of many of these techniques. Combining a substitution along with a permutation (or transposition) satisfies the Shannon's diffusion principle of cryptography; you want to try to get rid of as much statistical information as possible. statistical information''' +alice = alice.lower().replace(b' ', b'_') +bob = bob.lower().replace(b' ', b'_') + +key = [4,2,3,1,0] + +def rotate(text): + out = bytearray() + assert len(text) % width == 0, 'At %d of %d.' % (len(text) % width, width) + + slices = [bytearray(text[i:i+width]) for i in range(0, len(text), width)] + for i in range(width): + for slice in slices: + out.append(slice[key[i]]) + + return bytes(out) + +def unrotate(text): + out = bytearray() + assert len(text) % width == 0 + + # Make column slices, and rearrange them according to the key. + size = len(text) // width + tSlices = [bytearray(text[i*size:i*size+size]) for i in range(width)] + slices = [None] * width + for i in range(width): + slices[key[i]] = tSlices[i] + + while len(out) < len(text): + for i in range(5): + out.append(slices[i].pop(0)) + + return bytes(out) + +crypto.mkIndex(rotate, unrotate, alice, bob, crypto.groups) diff --git a/puzzles/crypto/crypto.py b/puzzles/crypto/crypto.py new file mode 100644 index 0000000..f007759 --- /dev/null +++ b/puzzles/crypto/crypto.py @@ -0,0 +1,34 @@ +def mkIndex(encode, decode, alice, bob, + format=lambda s: str(s, 'utf-8')): + """Write out the index.html contents. +@param encode: function to encrypt the plaintext +@param decode: function to decrypt the plaintext +@param alice: plaintext of alice line +@param bob: plaintext of bob line +@param format: formatter for the cypher text, run out output of encode before + printing. Does string conversion by default.""" + c = encode(alice) + print('
Alice
', format(c)) + assert decode(c) == alice + c = encode(bob) + print('
Bob
', format(c), '
') + assert decode(c) == bob + +def hexFormat(text): + return groups(text, 5, '{0:x} ') + +def groups(text, perLine=5, format='{0:c}'): + i = 0 + out = [] + while i < len(text): + out.append(format.format(text[i])) + + if i % (perLine*5) == (perLine * 5 - 1): + out.append('
') + elif i % 5 == 4: + out.append(' ') + + i = i + 1 + + return ''.join(out) +