Portsmouth Uni CipherThe Napier's Bones team (Charlie, Peter, Christina and Bill) undertook the cracking of the Portsmouth University cipher for the University Cipher Challenge. Here is our final solution [PDF]: Stage 1The first part is easy ... just a simple Morse code [View][Example] .... - - .--. -.-. --- .-.. --- -. ... .-.. .- ... .... ... .-.. .- ... .... .-. .--- -... -.. --- - ... --- -.-. -.. --- - .--. --- .-. - -.. --- - .- -.-. -.. --- - ..- -.- ... .-.. .- ... .... .--. ..- -. -.- ... .-.. .- ... .... .-. .. --. .... - .-. .. --. .... - .-. .. --. .... - .-. .. --. .... - -.. --- - --.. .. .--. and generates: HTTPCOLONSLASHSLASHRJBDOTSOCDOTPORTDOTACDOTUKSLASHPUNKSLASHRIGHTRIGHTRIGHTRIGHTDOTZIP Which gives us: http://rjb.soc.port.ac.uk/punk/rightrightrightright.zip [View] Step 2ALMPINYPMYWQECLEZIWLMJXIHFCXLVIIMXMWKSSHXSWIIXLEXCSYHMHRSXKMZIRXLEXGEIWEVAVSXILM WQIWWEKIWSZIVXASXLSYWERHCIEVWEKSMXMWKSSHXSWIIXLEXTVSKVIWWLEWFIIRQEHIMRXLIJMIPHSJ GVCTXSKVETLCWMRGIXLIJEPPSJXLIVISERIQTMVIXLMWRIBXGLETLEHELEHMRXLEXLXXTGSPSRWPEWLW PEWLVNFHSXWSGHSXTSVXHSXEGHSXYOWPEWLTYROWPEWLUAIVXCYMSTHSXDMT This is a Caeser code and generates [Example]: WHILE JULIUS MAY HAVE SHIFTED BY THREE IT IS GOOD TO SEE THAT YOU DID NOT GIVEN THAT CAESAR WROTE HIS MESSAGES OVER TWO THOUSAND YEARS AGO IT IS GOOD TO SEE THA T PROGRESS HAS BEEN MADE IN THE FIELD OF CRYPTOGRAPHY SINCE THE FALL OF THE REOA N EMPIRE THIS NEXT CHAP HAD A HAD IN THAT HTTP COLON SLASH SLASH RJB DOT SOC DOT PORT DOT AC DOT UK SLASH PUNKSLASHQWERTYU IOPDOTZIP This gives http://rjb.soc.port.ac.uk/punks/qwertyuio.zip [View] Step 3Next: WKZRGZUBHXIPESXJFIGDCQWKUCLWZAYJKZGFCAUGQRITHLMQRTHERXACWIATKLAZMFCBTXHOXREYMMJTHUSEXIHWKHJDMJVGJPSGQOXYTRINPAQEWVWCPQUCUNIJGMNIHIHEFLMGHOWIJKXYXGNIZXQJGIRNNWUGQLLVKUBWQPCAGVGROZWTIXIWHPYPWBLEWZMGHOVIJLGFEMHAZPIDWCTQBZXQTKXJHAXWHEENXUHRUKRDJQOJEYMPDJDGWCTQBEWABHIRIWICTJHPLVKDIZKPHZSEMFCAXDKNRVRRBZCJWDXZFCUAGJCERXRMOIRSQYLRKYWBSGIQJWBVINPVMGDHILXAWDQTIWVJOUHWORVWHJFWKXDCXYXDIZKPHZWCTQB which is a Vigenère code with a key of "qwertyuiop", which is one of the lines of the keyboard. [Example][Solution] and gives: GOVANBATTISTABELLASOMUSTBEROLLINGINHISGRAVECONSIDERINGHECAMEUPWITHITFIRSTALASEVERYONEKNOWSTHISCIPHERASTHATOFBLAISEDEVIGNERESNOTATTRIBUTINGITTOTHEITALIANCRYPTOGRAPHERWHOCAMECENTURIESBEFOREHIMVISITINGHTTPCOLONSLASHSLASHRJBDOTSOCDOTPORTDOTACDOTUKSLASHPUNKSLASHWILLLEAPYOUFURTHERFORWARDONTHISJOURNEYTHROUGHTIMEASSUMINGYOUADDACHARACTERSUFFIXOFBGWKZQPNDSIOAXEFCLUMTHYVRFOLLOWINGTHEFORWARDSLASH Which results in http://rjb.soc.port.ac.uk/punk/bgwkzqpndsioaxefclumthyvr.zip [View] Step 4Next: OPAPNMRORYFRXEYLNCYNSYPEYMXYXHELDUNQWRLLOXOYUEYMOMXEXVRSIYSEYNGLROWTORXACXMHYZORYLYROGXLYSMYLSOLYROAHYWYFXCADHYTRWVLERAPEOASXSXCWONRDNLLRYUVYYLFEYLSEHUWHMXSYQYOYWYXHYMDTTQSDPBRGTWATPNGZNTQOMGMEONNUWNBQYKMATYEGTRONYZMSOGSOSRYNISQYSFISBYCGYQPYPIZTQQXFBRYWIPNBXTQSEFTOYDIAEVNPRAWDWCGRTCGINOMPLURPSZRITSGTFMRRRZTPNMTXTRTHRZWQQIHR Which is a Bifid cipher [Example][Try] using the picture provided [here]. The table we use is: 1 2 3 4 5 1 B G W K Z 2 Q P N D S 3 I O A X E 4 F C L U M 5 T H Y V R and then to lay out in two rows (O is 32, P is 23, A is 33, and so on): 322233222345553255534155343553432342532325532235534534533452354324442321 .... 3253135 334525345245151212524221155125113335122231215235121324512453532232344132 .... 1315255 Next read each column one at a time (33 is A, 23 is N, 24 is D, and so on): AND SO ENDS OUR TRIP THROUGH TIME THE FINAL STOP ON THIS PART OF YOUR JOURNEY CONCLUDING WITH FELIX DELASTELLE THE FRENCH AMATEUR CRYPTOGRAPHER RENOWN FOR HIS WORK IN THE FIELD OF CRYPTOGRAPHY TIME TO THINK DIFFERENTLY TO CONTINUE TO THE NEXT STAGE YOU WILL NEED CYPHER WYTWOVFLXOTHREEQ DOT ONION YOU SHOULD KEEP PORTSM SAFE FOR THE FUTURE REMEMBER TO CONVERT NUMBERS FROM STRING TO INTEGER Resulting in: CYPHER WYTWOVFLXOTHREEQ DOT ONION cypherwy2vflxo3q.onion Clue: portsm ('keep portsm safe for the future...') Step 5If we go on the onion site that we've just found, we get a zip file containing a .ppm image [PPM file]. After looking through it, it was discovered that there was a pattern of binary for the RGB values of '2x 20x 2x' which were on top of each other. It was possible to convert the binary from left to right, top to bottom, i.e. [Speadsheet]: 20 201 20 C 20 200 20 21 201 20 o 21 201 20 21 201 21 21 200 21 n 21 299 21 21 201 20 ... Until we get the whole message, repeated: C o n g r a t u l a t i o n s . N o w t h a t w a s n ' t s o d i f f i c u l t w a s i t ? N o w o n w a r d t o t h e f i n a l s t a g e , y o u ' l l n e e d t h e s e c o n d p a r t t o t h e f i n a l p u z z l e w h i c h i s t h o o 5 a n d t h e n e x t s t a g e i s f o u n d i t p u n k s 6 a y s w 6 u j p o l . o n i o n Clue: thoo5 Step 6The Web page contained this [Page]. The code generated from the previous step was: import binascii import struct import sys val="4cc2ae9a45702a881e2ef1a7573d0ca57c02002c19e5567f7b0d05205caa30821efbeec75a2d4c577930308e0116b86f2a12187f6a195b3e7ac4d36b6b53455877ebfe5e2874ca127ea1014e4a88fe2f7175c6b216c069f4705973af11176c043bfe64564fab10c34a37b2466083d3aa4f0e46f078ab02bf550e21e25593e1c34aae278c57c9ba9308934c8f01a834b35c5fbb392a800d726edd162262f0459974e544cc0370e75b264fd0c3385f4a6765f8cf3e3492593f415ed2614de0d25e59f5f60d0a5de65a326eeb0537f5ec390b92b3fe15b9f0e91f7db8bc6c9b0b4a67304356253bb9d93bf8ed4f308108aa1c0416ed54a4cdfa5070cbfd7987a78a64052a8e2b48b2885fd2e69d3a9bb7a956bbae300198317b4f26716e1e7f6f892a0f77df356b5c5f706ec9cb4f214465117de27b472fd32e3a5e7d6f26b63e27059afc5e6a3ba85a130845042193446a4f98ffab73f992ee631637ad5555290f07f3f65c42a9a2ce4572fa4b6646f0aa5992acbe36e038f677f177e5783d37c27272ea98756d019615744b8b229f48a548994e3623a9df6f78cd612b3512498e48371fdb10eb0b4f1de915a32d61c86460ecc36e0ec5ca3f5a1bcf6474ac81270903a91b01edfd0e3c92b3543439363d65a2bab10ef03ef85b0881a1706ddf0b745291010feeb4d814569b782bf733c346fad1" val="4cc2ae9a45702a881e2ef1a7573d0ca57c0200" # xor two messages def xor(a, b): return ''.join([chr(ord(a[i]) ^ ord(b[i])) for i in range(len(a))]) #stream cipher constants a = 65539 m = 2**31 # run the stream cipher! def generateStream(key, length): x = key stream = struct.pack(">L", x) while len(stream) < len(msg): x = (a*x) % m stream += struct.pack(">L", x) return stream msg = "Test message1234444444444444444444444444444444" key = 0x12345678 # key - you need to crack this! stream = generateStream(key, len(msg)) ciphertext = xor(msg, stream) print "ciphertext: ", binascii.hexlify(ciphertext) print len(stream) print len(msg) #To decrypt: for key in range(0, 0xfffff): stream = generateStream(key, len(val)) plaintext = xor(val, stream) print plaintext The cipher is intentionally weak with the first four bytes of the key stream X-OR’ing the message stream: def generateStream(key, length): x = key stream = struct.pack(">L", x) while len(stream) < len(msg): x = (a*x) % m stream += struct.pack(">L", x) return stream The cipher is intentionally weak with the first four bytes of the key stream X-OR’ing the message stream: def generateStream(key, length): x = key stream = struct.pack(">L", x) while len(stream) < len(msg): x = (a*x) % m stream += struct.pack(">L", x) return stream Thus we just created a list of common words (with upper and lower case starting letters), and generated keys for these for the first four bytes: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace gencode { class Program { static void Main(string[] args) { string str = "4cc2ae9a"; string [] commonwords = { "and", "look","this","the","for","you","with ","have","with", "from","she","they","will","there","who ","make","like","which","when", "can","make","good","your","than","into","just"}; foreach (string s1 in commonwords) { for (int i = 0; i < 2; i++) { string s = Truncate(s1, 4); string instr = s; if (i == 0) { } else instr = Convert.ToString(char.ToUpper(instr[0]))+Convert.ToString(instr[1]) + Convert.ToString(instr[2]) + instr[3]; string hex = ConvertAsciiToHex(instr); Console.WriteLine("print g(0x" + xor(hex, str) + ") # " + s); } } } public static string Truncate( string value, int maximumLength) { if (value.Length == 3) return (value + " "); if (string.IsNullOrEmpty(value) == true) { return value; } if (value.Length > maximumLength) { return value.Substring(0, maximumLength); } return value; } public static string xor(string hex1, string hex2) { int dec1 = Convert.ToInt32(hex1, 16); int dec2 = Convert.ToInt32(hex2, 16); int result = dec1 ^ dec2; string hexResult = result.ToString("X"); return hexResult; } public static string ConvertAsciiToHex(string asciiString) { string hex = ""; foreach (char c in asciiString) { int tmp = c; hex += String.Format("{0:X2}", (uint)System.Convert.ToUInt32(tmp.ToString())); } return hex; } } } This generated all the required keys that would generate the first four letters of the cipher: print g(0x2DACCABA) # and print g(0xDACCABA) # And print g(0x20ADC1F1) # look print g(0xADC1F1) # Look print g(0x38AAC7E9) # this print g(0x18AAC7E9) # This print g(0x38AACBBA) # the print g(0x18AACBBA) # The print g(0x2AADDCBA) # for print g(0xAADDCBA) # For print g(0x35ADDBBA) # you print g(0x15ADDBBA) # You print g(0x3BABDAF2) # with print g(0x1BABDAF2) # With print g(0x24A3D8FF) # have print g(0x4A3D8FF) # Have print g(0x3BABDAF2) # with print g(0x1BABDAF2) # With print g(0x2AB0C1F7) # from print g(0xAB0C1F7) # From print g(0x3FAACBBA) # she print g(0x1FAACBBA) # She print g(0x38AACBE3) # they print g(0x18AACBE3) # They print g(0x3BABC2F6) # will print g(0x1BABC2F6) # Will print g(0x38AACBE8) # ther print g(0x18AACBE8) # Ther print g(0x3BAAC1BA) # who print g(0x1BAAC1BA) # Who print g(0x21A3C5FF) # make print g(0x1A3C5FF) # Make print g(0x20ABC5FF) # like print g(0xABC5FF) # Like print g(0x3BAAC7F9) # whic print g(0x1BAAC7F9) # Whic print g(0x3BAACBF4) # when print g(0x1BAACBF4) # When print g(0x2FA3C0BA) # can print g(0xFA3C0BA) # Can print g(0x21A3C5FF) # make print g(0x1A3C5FF) # Make print g(0x2BADC1FE) # good print g(0xBADC1FE) # Good print g(0x35ADDBE8) # your print g(0x15ADDBE8) # Your print g(0x38AACFF4) # than print g(0x18AACFF4) # Than print g(0x25ACDAF5) # into print g(0x5ACDAF5) # Into print g(0x26B7DDEE) # just print g(0x6B7DDEE) # Just For example for a key of "0xBADC1FE" generates the first four characters of "Good". Next we imported this into the Python code all these keys into the Python code: import binascii import struct import sys import string val="4cc2ae9a45702a881e2ef1a7573d0ca57c02002c19e5567f7b0d05205caa30821efbeec75a2d4c577930308e0116b86f2a12187f6a195b3e7ac4d36b6b53455877ebfe5e2874ca127ea1014e4a88fe2f7175c6b216c069f4705973af11176c043bfe64564fab10c34a37b2466083d3aa4f0e46f078ab02bf550e21e25593e1c34aae278c57c9ba9308934c8f01a834b35c5fbb392a800d726edd162262f0459974e544cc0370e75b264fd0c3385f4a6765f8cf3e3492593f415ed2614de0d25e59f5f60d0a5de65a326eeb0537f5ec390b92b3fe15b9f0e91f7db8bc6c9b0b4a67304356253bb9d93bf8ed4f308108aa1c0416ed54a4cdfa5070cbfd7987a78a64052a8e2b48b2885fd2e69d3a9bb7a956bbae300198317b4f26716e1e7f6f892a0f77df356b5c5f706ec9cb4f214465117de27b472fd32e3a5e7d6f26b63e27059afc5e6a3ba85a130845042193446a4f98ffab73f992ee631637ad5555290f07f3f65c42a9a2ce4572fa4b6646f0aa5992acbe36e038f677f177e5783d37c27272ea98756d019615744b8b229f48a548994e3623a9df6f78cd612b3512498e48371fdb10eb0b4f1de915a32d61c86460ecc36e0ec5ca3f5a1bcf6474ac81270903a91b01edfd0e3c92b3543439363d65a2bab10ef03ef85b0881a1706ddf0b745291010feeb4d814569b782bf733c346fad1" # xor two messages def xor(a, b): return ''.join([chr(ord(a[i]) ^ ord(b[i])) for i in range(len(a))]) #stream cipher constants a = 65539 m = 2**31 # run the stream cipher! def generateStream(key, length): x = key stream = struct.pack(">L", x) while len(stream) < len(msg): x = (a*x) % m stream += struct.pack(">L", x) return stream def g( key1 ): stream = generateStream(key1, len(cipher)) plaintext = xor(cipher, stream) return plaintext #To decrypt: msg="" cipher = binascii.unhexlify(val) for x in range(1, len(cipher)): msg+="a" print g(0x2DACCABA) # and print g(0xDACCABA) # And print g(0x20ADC1F1) # look print g(0xADC1F1) # Look print g(0x38AAC7E9) # this print g(0x18AAC7E9) # This print g(0x38AACBBA) # the print g(0x18AACBBA) # The print g(0x2AADDCBA) # for print g(0xAADDCBA) # For ... print g(0x21A3C5FF) # make print g(0x1A3C5FF) # Make print g(0x2BADC1FE) # good print g(0xBADC1FE) # Good print g(0x35ADDBE8) # your print g(0x15ADDBE8) # Your print g(0x38AACFF4) # than print g(0x18AACFF4) # Than print g(0x25ACDAF5) # into print g(0x5ACDAF5) # Into print g(0x26B7DDEE) # just print g(0x6B7DDEE) # Just Then when run gives garbled text, apart from "Good", which gives: Good work! If you are reading this you must have cracked the stream cipher. Hopefully in cracking this you have seen the value in creating a cryptographically secure random number generator, the same weakness in this stream cipher can also be seen in some computer-based casino games which can be used to predict play. The end is just around the corner, but to reach the end, take this final piece of the puzzle and the clue: Final piece: 3jhmu Clue: https://www.youtube.com/watch?v=_bMcXVe8zIs Final stepIf we look at the previous clues given in steps 4, 5, and 6, we get the words: portsm, thoo5, and 3jhmu. The video of Shrek basically tells us to take the 3 clues, put them together, and go to a third onion website on the tor network: portsmthoo53jhmu.onion And that is it!!! What great fun! Many thanks to Charley, especially! |