Challenge 17:
from Crypto.Cipher import AES from base64 import b64decode from os import urandom from random import randint import string BLOCKSIZE = 16 def getRandomString(): strings = ["MDAwMDAwTm93IHRoYXQgdGhlIHBhcnR5IGlzIGp1bXBpbmc=","MDAwMDAxV2l0aCB0aGUgYmFzcyBraWNrZWQgaW4gYW5kIHRoZSBWZWdhJ3MgYXJlIHB1bXBpbic=","MDAwMDAyUXVpY2sgdG8gdGhlIHBvaW50LCB0byB0aGUgcG9pbnQsIG5vIGZha2luZw==","MDAwMDAzQ29va2luZyBNQydzIGxpa2UgYSBwb3VuZCBvZiBiYWNvbg==","MDAwMDA0QnVybmluZyAnZW0sIGlmIHlvdSBhaW4ndCBxdWljayBhbmQgbmltYmxl","MDAwMDA1SSBnbyBjcmF6eSB3aGVuIEkgaGVhciBhIGN5bWJhbA==","MDAwMDA2QW5kIGEgaGlnaCBoYXQgd2l0aCBhIHNvdXBlZCB1cCB0ZW1wbw==","MDAwMDA3SSdtIG9uIGEgcm9sbCwgaXQncyB0aW1lIHRvIGdvIHNvbG8=","MDAwMDA4b2xsaW4nIGluIG15IGZpdmUgcG9pbnQgb2g=","MDAwMDA5aXRoIG15IHJhZy10b3AgZG93biBzbyBteSBoYWlyIGNhbiBibG93"] return b64decode(strings[randint(0,len(strings)-1)]) def padding(string, blockSize): if len(string)%blockSize == 0: return string + b'\x0f'*16 byte = blockSize-(len(string)%blockSize) pad = b"".join( bytes.fromhex( hex(byte)[2:].rjust(2,"0") ) for _ in range(byte)) return string + pad def PKCS7paddingValidation(string, blocksize): byteNum = string[len(string)-1] toVerify = string[-byteNum:] if toVerify == chr(byteNum).encode()*byteNum: return True return False # Retrieve the padding used in the orignal plaintext def getOriginalPadding(lastBlock, key, previousBlock): editBlock = bytearray(previousBlock) ret = 0 while cbcDecrypt(lastBlock, key, editBlock): editBlock[ret+1] = 255 ret += 1 return chr(BLOCKSIZE - ret).encode() # Get list of ciphertext blocks def getBlocks(ciphertext): ret = [] for i in range(0,len(ciphertext)//BLOCKSIZE): ret.append(ciphertext[i*BLOCKSIZE:(i+1)*BLOCKSIZE]) return ret def cbcEncrypt(plaintext, key, iv): plaintext = padding(plaintext, BLOCKSIZE) aes = AES.new(key, AES.MODE_CBC, iv) ciphertext = aes.encrypt(plaintext) return ciphertext def cbcDecrypt(ciphertext, key, iv): aes = AES.new(key, AES.MODE_CBC, iv) plaintext = aes.decrypt(ciphertext) return PKCS7paddingValidation(plaintext, BLOCKSIZE) def cbcPaddingOracleAttack(ciphertext, key, iv): plaintext = b"" blocks = getBlocks(ciphertext) blocks.insert(0,iv) # We'll need this later for solving ambiguities originalPadding = getOriginalPadding(blocks[ len(blocks)-1 ], key, blocks[ len(blocks)-2 ]) print ("Original Paddind:",originalPadding) for i in range(0, len(blocks)-1): chunk = b"" for j in range(0,BLOCKSIZE): curBlock = bytearray(blocks[i]) if len(chunk) != 0: tmp = BLOCKSIZE - 1 for ch in range(0, len(chunk)): curBlock[tmp] = (len(chunk)+1) ^ chunk[ch] ^ curBlock[tmp] tmp -= 1 options = [] for k in range(0,256): curBlock[len(curBlock)-1-j] = k if cbcDecrypt( bytearray(blocks[i+1]), key, curBlock): options.append(k) if len(options) == 1: chunk += chr( options[0] ^ (len(chunk)+1) ^ blocks[i][BLOCKSIZE-1-j] ).encode() else: nextChar = b"" for op in options: curChar = chr( op ^ (len(chunk)+1) ^ blocks[i][BLOCKSIZE-1-j] ).encode() if curChar == originalPadding: nextChar = curChar chunk += nextChar plaintext += chunk[::-1] return plaintext def main(): key = urandom(BLOCKSIZE) iv = urandom(BLOCKSIZE) string = getRandomString() ciphertext = cbcEncrypt(string, key, iv) plaintext = cbcPaddingOracleAttack(ciphertext, key, iv) print ("Original plaintext:", string) print ("Decryption result:", plaintext) if __name__ == "__main__": main()
Challenge 18:
from Crypto.Cipher import AES from Crypto.Util import Counter import base64 BLOCKSIZE = 16 def xorStrings(data0, data1): ret = b"".join(bytes.fromhex(hex(data0[i]^data1[i])[2:].rjust(2,'0')) for i in range(min(len(data0),len(data1)))) return ret def encrypt(plaintext, key, nonce): aes = AES.new(key, AES.MODE_ECB) counter = 0 keyStream = b"" keyLen = (len(plaintext)//BLOCKSIZE) + 1 if len(plaintext)%16 != 0 else (len(plantext)//BLOCKSIZE) for i in range(0, keyLen): curCounter = bytes.fromhex(hex(counter)[2:(BLOCKSIZE+2)].rjust(BLOCKSIZE,'0'))[::-1] keyStream += aes.encrypt(nonce + curCounter) counter += 1 return xorStrings(plaintext, keyStream) def decrypt(ciphertext, key, nonce): aes = AES.new(key, AES.MODE_ECB) counter = 0 keyStream = b"" keyLen = (len(ciphertext)//BLOCKSIZE) + 1 if len(ciphertext)%16 != 0 else (len(ciphertext)//BLOCKSIZE) for i in range(0, keyLen): curCounter = bytes.fromhex(hex(counter)[2:(BLOCKSIZE+2)].rjust(BLOCKSIZE,'0'))[::-1] keyStream += aes.encrypt(nonce + curCounter) counter += 1 return xorStrings(ciphertext, keyStream) def main(): key = b"YELLOW SUBMARINE" nonce = b'\x00'*(BLOCKSIZE//2) ciphertext = base64.b64decode("L77na/nrFsKvynd6HzOoG7GHTLXsTVu9qvY/2syLXzhPweyyMTJULu/6/kXX0KSvoOLSFQ==") plaintext = decrypt(ciphertext, key, nonce) print ( plaintext.decode() ) if __name__ == "__main__": main()
Challenge 19:
from Crypto.Cipher import AES from os import urandom import base64 BLOCKSIZE = 16 plaintexts = ['SSBoYXZlIG1ldCB0aGVtIGF0IGNsb3NlIG9mIGRheQ==', 'Q29taW5nIHdpdGggdml2aWQgZmFjZXM=', 'RnJvbSBjb3VudGVyIG9yIGRlc2sgYW1vbmcgZ3JleQ==', 'RWlnaHRlZW50aC1jZW50dXJ5IGhvdXNlcy4=', 'SSBoYXZlIHBhc3NlZCB3aXRoIGEgbm9kIG9mIHRoZSBoZWFk', 'T3IgcG9saXRlIG1lYW5pbmdsZXNzIHdvcmRzLA==', 'T3IgaGF2ZSBsaW5nZXJlZCBhd2hpbGUgYW5kIHNhaWQ=', 'UG9saXRlIG1lYW5pbmdsZXNzIHdvcmRzLA==', 'QW5kIHRob3VnaHQgYmVmb3JlIEkgaGFkIGRvbmU=', 'T2YgYSBtb2NraW5nIHRhbGUgb3IgYSBnaWJl', 'VG8gcGxlYXNlIGEgY29tcGFuaW9u', 'QXJvdW5kIHRoZSBmaXJlIGF0IHRoZSBjbHViLA==', 'QmVpbmcgY2VydGFpbiB0aGF0IHRoZXkgYW5kIEk=', 'QnV0IGxpdmVkIHdoZXJlIG1vdGxleSBpcyB3b3JuOg==', 'QWxsIGNoYW5nZWQsIGNoYW5nZWQgdXR0ZXJseTo=', 'QSB0ZXJyaWJsZSBiZWF1dHkgaXMgYm9ybi4=', 'VGhhdCB3b21hbidzIGRheXMgd2VyZSBzcGVudA==', 'SW4gaWdub3JhbnQgZ29vZCB3aWxsLA==', 'SGVyIG5pZ2h0cyBpbiBhcmd1bWVudA==', 'VW50aWwgaGVyIHZvaWNlIGdyZXcgc2hyaWxsLg==', 'V2hhdCB2b2ljZSBtb3JlIHN3ZWV0IHRoYW4gaGVycw==', 'V2hlbiB5b3VuZyBhbmQgYmVhdXRpZnVsLA==', 'U2hlIHJvZGUgdG8gaGFycmllcnM/', 'VGhpcyBtYW4gaGFkIGtlcHQgYSBzY2hvb2w=', 'QW5kIHJvZGUgb3VyIHdpbmdlZCBob3JzZS4=', 'VGhpcyBvdGhlciBoaXMgaGVscGVyIGFuZCBmcmllbmQ=', 'V2FzIGNvbWluZyBpbnRvIGhpcyBmb3JjZTs=', 'SGUgbWlnaHQgaGF2ZSB3b24gZmFtZSBpbiB0aGUgZW5kLA==', 'U28gc2Vuc2l0aXZlIGhpcyBuYXR1cmUgc2VlbWVkLA==', 'U28gZGFyaW5nIGFuZCBzd2VldCBoaXMgdGhvdWdodC4=', 'VGhpcyBvdGhlciBtYW4gSSBoYWQgZHJlYW1lZA==', 'QSBkcnVua2VuLCB2YWluLWdsb3Jpb3VzIGxvdXQu', 'SGUgaGFkIGRvbmUgbW9zdCBiaXR0ZXIgd3Jvbmc=', 'VG8gc29tZSB3aG8gYXJlIG5lYXIgbXkgaGVhcnQs', 'WWV0IEkgbnVtYmVyIGhpbSBpbiB0aGUgc29uZzs=', 'SGUsIHRvbywgaGFzIHJlc2lnbmVkIGhpcyBwYXJ0', 'SW4gdGhlIGNhc3VhbCBjb21lZHk7', 'SGUsIHRvbywgaGFzIGJlZW4gY2hhbmdlZCBpbiBoaXMgdHVybiw=', 'VHJhbnNmb3JtZWQgdXR0ZXJseTo=', 'QSB0ZXJyaWJsZSBiZWF1dHkgaXMgYm9ybi4='] freqs = { 'A': 0.0651738, 'B': 0.0124248, 'C': 0.0217339, 'D': 0.0349835, 'E': 0.1241442, 'F': 0.0197881, 'G': 0.0158610, 'H': 0.0492888, 'I': 0.0558094, 'J': 0.0009033, 'K': 0.0050529, 'L': 0.0331490, 'M': 0.0202124, 'N': 0.0564513, 'O': 0.0596302, 'P': 0.0137645, 'Q': 0.0008606, 'R': 0.0497563, 'S': 0.0515760, 'T': 0.0729357, 'U': 0.0225134, 'V': 0.0082903, 'W': 0.0171272, 'X': 0.0013692, 'Y': 0.0145984, 'Z': 0.0007836, ' ': 0.1918182 } def score(s): score = 0 for c in s: cur = chr(c).upper() if cur in freqs: score += freqs[cur] return score def singleByteXor(string, n): return b"".join( bytes.fromhex(hex(n^c)[2:].rjust(2,"0")) for c in string) def xorStrings(data0, data1): ret = b"".join(bytes.fromhex(hex(data0[i]^data1[i])[2:].rjust(2,'0')) for i in range(min(len(data0),len(data1)))) return ret def encrypt(plaintext, key, nonce): aes = AES.new(key, AES.MODE_ECB) counter = 0 keyStream = b"" keyLen = (len(plaintext)//BLOCKSIZE) + 1 if len(plaintext)%16 != 0 else (len(plantext)//BLOCKSIZE) for i in range(0, keyLen): curCounter = bytes.fromhex(hex(counter)[2:(BLOCKSIZE+2)].rjust(BLOCKSIZE,'0'))[::-1] keyStream += aes.encrypt(nonce + curCounter) counter += 1 return xorStrings(plaintext, keyStream) def decrypt(ciphertext, key, nonce): aes = AES.new(key, AES.MODE_ECB) counter = 0 keyStream = b"" keyLen = (len(ciphertext)//BLOCKSIZE) + 1 if len(ciphertext)%16 != 0 else (len(ciphertext)//BLOCKSIZE) for i in range(0, keyLen): curCounter = bytes.fromhex(hex(counter)[2:(BLOCKSIZE+2)].rjust(BLOCKSIZE,'0'))[::-1] keyStream += aes.encrypt(nonce + curCounter) counter += 1 return xorStrings(ciphertext, keyStream) def getBlocks(ciphertexts, keySize): ret = [] for i in range(keySize): block = b"" for j in range(len(ciphertexts)): if i < len(ciphertexts[j]): block += bytes([ciphertexts[j][i]]) else: continue ret.append(block) return ret def getKey(blocks): key = b"" for block in blocks: maxScore = 0 keyGuess = b"" for i in range(0,256): curTry = singleByteXor(block,i) curScore = score(curTry) if curScore > maxScore: maxScore = curScore keyGuess = bytes([i]) key += keyGuess return key def main(): key = urandom(BLOCKSIZE) nonce = b'\x00'*(BLOCKSIZE//2) ciphertexts = [] for pt in plaintexts: ciphertexts.append(decrypt(base64.b64decode(pt),key,nonce)) keySize = len(max(ciphertexts, key=len)) blocks = getBlocks(ciphertexts, keySize) keyGuess = getKey(blocks) for i in range(len(ciphertexts)): print (xorStrings(ciphertexts[i],keyGuess)) if __name__ == "__main__": main()
Challenge 20:
from Crypto.Cipher import AES from os import urandom import base64 BLOCKSIZE = 16 plaintexts = ['SSdtIHJhdGVkICJSIi4uLnRoaXMgaXMgYSB3YXJuaW5nLCB5YSBiZXR0ZXIgdm9pZCAvIFBvZXRzIGFyZSBwYXJhbm9pZCwgREoncyBELXN0cm95ZWQ=', 'Q3V6IEkgY2FtZSBiYWNrIHRvIGF0dGFjayBvdGhlcnMgaW4gc3BpdGUtIC8gU3RyaWtlIGxpa2UgbGlnaHRuaW4nLCBJdCdzIHF1aXRlIGZyaWdodGVuaW4nIQ==', 'QnV0IGRvbid0IGJlIGFmcmFpZCBpbiB0aGUgZGFyaywgaW4gYSBwYXJrIC8gTm90IGEgc2NyZWFtIG9yIGEgY3J5LCBvciBhIGJhcmssIG1vcmUgbGlrZSBhIHNwYXJrOw==', 'WWEgdHJlbWJsZSBsaWtlIGEgYWxjb2hvbGljLCBtdXNjbGVzIHRpZ2h0ZW4gdXAgLyBXaGF0J3MgdGhhdCwgbGlnaHRlbiB1cCEgWW91IHNlZSBhIHNpZ2h0IGJ1dA==', 'U3VkZGVubHkgeW91IGZlZWwgbGlrZSB5b3VyIGluIGEgaG9ycm9yIGZsaWNrIC8gWW91IGdyYWIgeW91ciBoZWFydCB0aGVuIHdpc2ggZm9yIHRvbW9ycm93IHF1aWNrIQ==', 'TXVzaWMncyB0aGUgY2x1ZSwgd2hlbiBJIGNvbWUgeW91ciB3YXJuZWQgLyBBcG9jYWx5cHNlIE5vdywgd2hlbiBJJ20gZG9uZSwgeWEgZ29uZSE=', 'SGF2ZW4ndCB5b3UgZXZlciBoZWFyZCBvZiBhIE1DLW11cmRlcmVyPyAvIFRoaXMgaXMgdGhlIGRlYXRoIHBlbmFsdHksYW5kIEknbSBzZXJ2aW4nIGE=', 'RGVhdGggd2lzaCwgc28gY29tZSBvbiwgc3RlcCB0byB0aGlzIC8gSHlzdGVyaWNhbCBpZGVhIGZvciBhIGx5cmljYWwgcHJvZmVzc2lvbmlzdCE=', 'RnJpZGF5IHRoZSB0aGlydGVlbnRoLCB3YWxraW5nIGRvd24gRWxtIFN0cmVldCAvIFlvdSBjb21lIGluIG15IHJlYWxtIHlhIGdldCBiZWF0IQ==', 'VGhpcyBpcyBvZmYgbGltaXRzLCBzbyB5b3VyIHZpc2lvbnMgYXJlIGJsdXJyeSAvIEFsbCB5YSBzZWUgaXMgdGhlIG1ldGVycyBhdCBhIHZvbHVtZQ==', 'VGVycm9yIGluIHRoZSBzdHlsZXMsIG5ldmVyIGVycm9yLWZpbGVzIC8gSW5kZWVkIEknbSBrbm93bi15b3VyIGV4aWxlZCE=', 'Rm9yIHRob3NlIHRoYXQgb3Bwb3NlIHRvIGJlIGxldmVsIG9yIG5leHQgdG8gdGhpcyAvIEkgYWluJ3QgYSBkZXZpbCBhbmQgdGhpcyBhaW4ndCB0aGUgRXhvcmNpc3Qh', 'V29yc2UgdGhhbiBhIG5pZ2h0bWFyZSwgeW91IGRvbid0IGhhdmUgdG8gc2xlZXAgYSB3aW5rIC8gVGhlIHBhaW4ncyBhIG1pZ3JhaW5lIGV2ZXJ5IHRpbWUgeWEgdGhpbms=', 'Rmxhc2hiYWNrcyBpbnRlcmZlcmUsIHlhIHN0YXJ0IHRvIGhlYXI6IC8gVGhlIFItQS1LLUktTSBpbiB5b3VyIGVhcjs=', 'VGhlbiB0aGUgYmVhdCBpcyBoeXN0ZXJpY2FsIC8gVGhhdCBtYWtlcyBFcmljIGdvIGdldCBhIGF4IGFuZCBjaG9wcyB0aGUgd2Fjaw==', 'U29vbiB0aGUgbHlyaWNhbCBmb3JtYXQgaXMgc3VwZXJpb3IgLyBGYWNlcyBvZiBkZWF0aCByZW1haW4=', 'TUMncyBkZWNheWluZywgY3V6IHRoZXkgbmV2ZXIgc3RheWVkIC8gVGhlIHNjZW5lIG9mIGEgY3JpbWUgZXZlcnkgbmlnaHQgYXQgdGhlIHNob3c=', 'VGhlIGZpZW5kIG9mIGEgcmh5bWUgb24gdGhlIG1pYyB0aGF0IHlvdSBrbm93IC8gSXQncyBvbmx5IG9uZSBjYXBhYmxlLCBicmVha3MtdGhlIHVuYnJlYWthYmxl', 'TWVsb2RpZXMtdW5tYWthYmxlLCBwYXR0ZXJuLXVuZXNjYXBhYmxlIC8gQSBob3JuIGlmIHdhbnQgdGhlIHN0eWxlIEkgcG9zc2Vz', 'SSBibGVzcyB0aGUgY2hpbGQsIHRoZSBlYXJ0aCwgdGhlIGdvZHMgYW5kIGJvbWIgdGhlIHJlc3QgLyBGb3IgdGhvc2UgdGhhdCBlbnZ5IGEgTUMgaXQgY2FuIGJl', 'SGF6YXJkb3VzIHRvIHlvdXIgaGVhbHRoIHNvIGJlIGZyaWVuZGx5IC8gQSBtYXR0ZXIgb2YgbGlmZSBhbmQgZGVhdGgsIGp1c3QgbGlrZSBhIGV0Y2gtYS1za2V0Y2g=', 'U2hha2UgJ3RpbGwgeW91ciBjbGVhciwgbWFrZSBpdCBkaXNhcHBlYXIsIG1ha2UgdGhlIG5leHQgLyBBZnRlciB0aGUgY2VyZW1vbnksIGxldCB0aGUgcmh5bWUgcmVzdCBpbiBwZWFjZQ==', 'SWYgbm90LCBteSBzb3VsJ2xsIHJlbGVhc2UhIC8gVGhlIHNjZW5lIGlzIHJlY3JlYXRlZCwgcmVpbmNhcm5hdGVkLCB1cGRhdGVkLCBJJ20gZ2xhZCB5b3UgbWFkZSBpdA==', 'Q3V6IHlvdXIgYWJvdXQgdG8gc2VlIGEgZGlzYXN0cm91cyBzaWdodCAvIEEgcGVyZm9ybWFuY2UgbmV2ZXIgYWdhaW4gcGVyZm9ybWVkIG9uIGEgbWljOg==', 'THlyaWNzIG9mIGZ1cnkhIEEgZmVhcmlmaWVkIGZyZWVzdHlsZSEgLyBUaGUgIlIiIGlzIGluIHRoZSBob3VzZS10b28gbXVjaCB0ZW5zaW9uIQ==', 'TWFrZSBzdXJlIHRoZSBzeXN0ZW0ncyBsb3VkIHdoZW4gSSBtZW50aW9uIC8gUGhyYXNlcyB0aGF0J3MgZmVhcnNvbWU=', 'WW91IHdhbnQgdG8gaGVhciBzb21lIHNvdW5kcyB0aGF0IG5vdCBvbmx5IHBvdW5kcyBidXQgcGxlYXNlIHlvdXIgZWFyZHJ1bXM7IC8gSSBzaXQgYmFjayBhbmQgb2JzZXJ2ZSB0aGUgd2hvbGUgc2NlbmVyeQ==', 'VGhlbiBub25jaGFsYW50bHkgdGVsbCB5b3Ugd2hhdCBpdCBtZWFuIHRvIG1lIC8gU3RyaWN0bHkgYnVzaW5lc3MgSSdtIHF1aWNrbHkgaW4gdGhpcyBtb29k', 'QW5kIEkgZG9uJ3QgY2FyZSBpZiB0aGUgd2hvbGUgY3Jvd2QncyBhIHdpdG5lc3MhIC8gSSdtIGEgdGVhciB5b3UgYXBhcnQgYnV0IEknbSBhIHNwYXJlIHlvdSBhIGhlYXJ0', 'UHJvZ3JhbSBpbnRvIHRoZSBzcGVlZCBvZiB0aGUgcmh5bWUsIHByZXBhcmUgdG8gc3RhcnQgLyBSaHl0aG0ncyBvdXQgb2YgdGhlIHJhZGl1cywgaW5zYW5lIGFzIHRoZSBjcmF6aWVzdA==', 'TXVzaWNhbCBtYWRuZXNzIE1DIGV2ZXIgbWFkZSwgc2VlIGl0J3MgLyBOb3cgYW4gZW1lcmdlbmN5LCBvcGVuLWhlYXJ0IHN1cmdlcnk=', 'T3BlbiB5b3VyIG1pbmQsIHlvdSB3aWxsIGZpbmQgZXZlcnkgd29yZCdsbCBiZSAvIEZ1cmllciB0aGFuIGV2ZXIsIEkgcmVtYWluIHRoZSBmdXJ0dXJl', 'QmF0dGxlJ3MgdGVtcHRpbmcuLi53aGF0ZXZlciBzdWl0cyB5YSEgLyBGb3Igd29yZHMgdGhlIHNlbnRlbmNlLCB0aGVyZSdzIG5vIHJlc2VtYmxhbmNl', 'WW91IHRoaW5rIHlvdSdyZSBydWZmZXIsIHRoZW4gc3VmZmVyIHRoZSBjb25zZXF1ZW5jZXMhIC8gSSdtIG5ldmVyIGR5aW5nLXRlcnJpZnlpbmcgcmVzdWx0cw==', 'SSB3YWtlIHlhIHdpdGggaHVuZHJlZHMgb2YgdGhvdXNhbmRzIG9mIHZvbHRzIC8gTWljLXRvLW1vdXRoIHJlc3VzY2l0YXRpb24sIHJoeXRobSB3aXRoIHJhZGlhdGlvbg==', 'Tm92b2NhaW4gZWFzZSB0aGUgcGFpbiBpdCBtaWdodCBzYXZlIGhpbSAvIElmIG5vdCwgRXJpYyBCLidzIHRoZSBqdWRnZSwgdGhlIGNyb3dkJ3MgdGhlIGp1cnk=', 'WW8gUmFraW0sIHdoYXQncyB1cD8gLyBZbywgSSdtIGRvaW5nIHRoZSBrbm93bGVkZ2UsIEUuLCBtYW4gSSdtIHRyeWluZyB0byBnZXQgcGFpZCBpbiBmdWxs', 'V2VsbCwgY2hlY2sgdGhpcyBvdXQsIHNpbmNlIE5vcmJ5IFdhbHRlcnMgaXMgb3VyIGFnZW5jeSwgcmlnaHQ/IC8gVHJ1ZQ==', 'S2FyYSBMZXdpcyBpcyBvdXIgYWdlbnQsIHdvcmQgdXAgLyBaYWtpYSBhbmQgNHRoIGFuZCBCcm9hZHdheSBpcyBvdXIgcmVjb3JkIGNvbXBhbnksIGluZGVlZA==', 'T2theSwgc28gd2hvIHdlIHJvbGxpbicgd2l0aCB0aGVuPyBXZSByb2xsaW4nIHdpdGggUnVzaCAvIE9mIFJ1c2h0b3duIE1hbmFnZW1lbnQ=', 'Q2hlY2sgdGhpcyBvdXQsIHNpbmNlIHdlIHRhbGtpbmcgb3ZlciAvIFRoaXMgZGVmIGJlYXQgcmlnaHQgaGVyZSB0aGF0IEkgcHV0IHRvZ2V0aGVy', 'SSB3YW5uYSBoZWFyIHNvbWUgb2YgdGhlbSBkZWYgcmh5bWVzLCB5b3Uga25vdyB3aGF0IEknbSBzYXlpbic/IC8gQW5kIHRvZ2V0aGVyLCB3ZSBjYW4gZ2V0IHBhaWQgaW4gZnVsbA==', 'VGhpbmtpbicgb2YgYSBtYXN0ZXIgcGxhbiAvICdDdXogYWluJ3QgbnV0aGluJyBidXQgc3dlYXQgaW5zaWRlIG15IGhhbmQ=', 'U28gSSBkaWcgaW50byBteSBwb2NrZXQsIGFsbCBteSBtb25leSBpcyBzcGVudCAvIFNvIEkgZGlnIGRlZXBlciBidXQgc3RpbGwgY29taW4nIHVwIHdpdGggbGludA==', 'U28gSSBzdGFydCBteSBtaXNzaW9uLCBsZWF2ZSBteSByZXNpZGVuY2UgLyBUaGlua2luJyBob3cgY291bGQgSSBnZXQgc29tZSBkZWFkIHByZXNpZGVudHM=', 'SSBuZWVkIG1vbmV5LCBJIHVzZWQgdG8gYmUgYSBzdGljay11cCBraWQgLyBTbyBJIHRoaW5rIG9mIGFsbCB0aGUgZGV2aW91cyB0aGluZ3MgSSBkaWQ=', 'SSB1c2VkIHRvIHJvbGwgdXAsIHRoaXMgaXMgYSBob2xkIHVwLCBhaW4ndCBudXRoaW4nIGZ1bm55IC8gU3RvcCBzbWlsaW5nLCBiZSBzdGlsbCwgZG9uJ3QgbnV0aGluJyBtb3ZlIGJ1dCB0aGUgbW9uZXk=', 'QnV0IG5vdyBJIGxlYXJuZWQgdG8gZWFybiAnY3V6IEknbSByaWdodGVvdXMgLyBJIGZlZWwgZ3JlYXQsIHNvIG1heWJlIEkgbWlnaHQganVzdA==', 'U2VhcmNoIGZvciBhIG5pbmUgdG8gZml2ZSwgaWYgSSBzdHJpdmUgLyBUaGVuIG1heWJlIEknbGwgc3RheSBhbGl2ZQ==', 'U28gSSB3YWxrIHVwIHRoZSBzdHJlZXQgd2hpc3RsaW4nIHRoaXMgLyBGZWVsaW4nIG91dCBvZiBwbGFjZSAnY3V6LCBtYW4sIGRvIEkgbWlzcw==', 'QSBwZW4gYW5kIGEgcGFwZXIsIGEgc3RlcmVvLCBhIHRhcGUgb2YgLyBNZSBhbmQgRXJpYyBCLCBhbmQgYSBuaWNlIGJpZyBwbGF0ZSBvZg==', 'RmlzaCwgd2hpY2ggaXMgbXkgZmF2b3JpdGUgZGlzaCAvIEJ1dCB3aXRob3V0IG5vIG1vbmV5IGl0J3Mgc3RpbGwgYSB3aXNo', 'J0N1eiBJIGRvbid0IGxpa2UgdG8gZHJlYW0gYWJvdXQgZ2V0dGluJyBwYWlkIC8gU28gSSBkaWcgaW50byB0aGUgYm9va3Mgb2YgdGhlIHJoeW1lcyB0aGF0IEkgbWFkZQ==', 'U28gbm93IHRvIHRlc3QgdG8gc2VlIGlmIEkgZ290IHB1bGwgLyBIaXQgdGhlIHN0dWRpbywgJ2N1eiBJJ20gcGFpZCBpbiBmdWxs', 'UmFraW0sIGNoZWNrIHRoaXMgb3V0LCB5byAvIFlvdSBnbyB0byB5b3VyIGdpcmwgaG91c2UgYW5kIEknbGwgZ28gdG8gbWluZQ==', 'J0NhdXNlIG15IGdpcmwgaXMgZGVmaW5pdGVseSBtYWQgLyAnQ2F1c2UgaXQgdG9vayB1cyB0b28gbG9uZyB0byBkbyB0aGlzIGFsYnVt', 'WW8sIEkgaGVhciB3aGF0IHlvdSdyZSBzYXlpbmcgLyBTbyBsZXQncyBqdXN0IHB1bXAgdGhlIG11c2ljIHVw', 'QW5kIGNvdW50IG91ciBtb25leSAvIFlvLCB3ZWxsIGNoZWNrIHRoaXMgb3V0LCB5byBFbGk=', 'VHVybiBkb3duIHRoZSBiYXNzIGRvd24gLyBBbmQgbGV0IHRoZSBiZWF0IGp1c3Qga2VlcCBvbiByb2NraW4n', 'QW5kIHdlIG91dHRhIGhlcmUgLyBZbywgd2hhdCBoYXBwZW5lZCB0byBwZWFjZT8gLyBQZWFjZQ=='] freqs = { 'A': 0.0651738, 'B': 0.0124248, 'C': 0.0217339, 'D': 0.0349835, 'E': 0.1241442, 'F': 0.0197881, 'G': 0.0158610, 'H': 0.0492888, 'I': 0.0558094, 'J': 0.0009033, 'K': 0.0050529, 'L': 0.0331490, 'M': 0.0202124, 'N': 0.0564513, 'O': 0.0596302, 'P': 0.0137645, 'Q': 0.0008606, 'R': 0.0497563, 'S': 0.0515760, 'T': 0.0729357, 'U': 0.0225134, 'V': 0.0082903, 'W': 0.0171272, 'X': 0.0013692, 'Y': 0.0145984, 'Z': 0.0007836, ' ': 0.1918182 } def score(s): score = 0 for c in s: cur = chr(c).upper() if cur in freqs: score += freqs[cur] return score def singleByteXor(string, n): return b"".join( bytes.fromhex(hex(n^c)[2:].rjust(2,"0")) for c in string) def xorStrings(data0, data1): ret = b"".join(bytes.fromhex(hex(data0[i]^data1[i])[2:].rjust(2,'0')) for i in range(min(len(data0),len(data1)))) return ret def encrypt(plaintext, key, nonce): aes = AES.new(key, AES.MODE_ECB) counter = 0 keyStream = b"" keyLen = (len(plaintext)//BLOCKSIZE) + 1 if len(plaintext)%16 != 0 else (len(plantext)//BLOCKSIZE) for i in range(0, keyLen): curCounter = bytes.fromhex(hex(counter)[2:(BLOCKSIZE+2)].rjust(BLOCKSIZE,'0'))[::-1] keyStream += aes.encrypt(nonce + curCounter) counter += 1 return xorStrings(plaintext, keyStream) def decrypt(ciphertext, key, nonce): aes = AES.new(key, AES.MODE_ECB) counter = 0 keyStream = b"" keyLen = (len(ciphertext)//BLOCKSIZE) + 1 if len(ciphertext)%16 != 0 else (len(ciphertext)//BLOCKSIZE) for i in range(0, keyLen): curCounter = bytes.fromhex(hex(counter)[2:(BLOCKSIZE+2)].rjust(BLOCKSIZE,'0'))[::-1] keyStream += aes.encrypt(nonce + curCounter) counter += 1 return xorStrings(ciphertext, keyStream) def getBlocks(ciphertexts, keySize): ret = [] for i in range(keySize): block = b"" for j in range(len(ciphertexts)): if i < len(ciphertexts[j]): block += bytes([ciphertexts[j][i]]) else: continue ret.append(block) return ret def getKey(blocks): key = b"" for block in blocks: maxScore = 0 keyGuess = b"" for i in range(0,256): curTry = singleByteXor(block,i) curScore = score(curTry) if curScore > maxScore: maxScore = curScore keyGuess = bytes([i]) key += keyGuess return key def main(): key = urandom(BLOCKSIZE) nonce = b'\x00'*(BLOCKSIZE//2) ciphertexts = [] for pt in plaintexts: ciphertexts.append(decrypt(base64.b64decode(pt),key,nonce)) keySize = len(max(ciphertexts, key=len)) blocks = getBlocks(ciphertexts, keySize) keyGuess = getKey(blocks) for i in range(len(ciphertexts)): print (xorStrings(ciphertexts[i],keyGuess)) if __name__ == "__main__": main()
Challenge 21:
def getLowestBits(n, number_of_bits): mask = (1 << number_of_bits) - 1 return n & mask class MT19937: # Coefficients for MT19937-32 w, n, m, r = 32, 624, 397, 31 a = 0x9908b0df u, d = 11, 0xffffffff s, b = 7, 0x9d2c5680 t, c = 15, 0xefc60000 l = 18 f = 1812433253 lowerMask = (1 << r) - 1 upperMask = getLowestBits(not lowerMask, w) def __init__(self,seed): self.MT = [] self.index = self.n self.MT.append(seed) for i in range(1, self.index): self.MT.append(getLowestBits(self.f * (self.MT[i - 1] ^ (self.MT[i - 1] >> (self.w - 2))) + i, self.w)) def extract_number(self): if self.index >= self.n: self.twist() y = self.MT[self.index] y ^= (y >> self.u) & self.d y ^= (y << self.s) & self.b y ^= (y << self.t) & self.c y ^= (y >> self.l) self.index += 1 return getLowestBits(y, self.w) def twist(self): for i in range(self.n): x = (self.MT[i] & self.upperMask) + (self.MT[(i + 1) % self.n] & self.lowerMask) x_a = x >> 1 if x % 2 != 0: x_a ^= self.a self.MT[i] = self.MT[(i + self.m) % self.n] ^ x_a self.index = 0 def main(): # Check if the numbers look random print(MT19937(0).extract_number()) if __name__ == '__main__': main()
Challenge 22:
import random import time def getLowestBits(n, number_of_bits): mask = (1 << number_of_bits) - 1 return n & mask class MT19937: # Coefficients for MT19937-32 w, n, m, r = 32, 624, 397, 31 a = 0x9908b0df u, d = 11, 0xffffffff s, b = 7, 0x9d2c5680 t, c = 15, 0xefc60000 l = 18 f = 1812433253 lowerMask = (1 << r) - 1 upperMask = getLowestBits(not lowerMask, w) def __init__(self,seed): self.MT = [] self.index = self.n self.MT.append(seed) for i in range(1, self.index): self.MT.append(getLowestBits(self.f * (self.MT[i - 1] ^ (self.MT[i - 1] >> (self.w - 2))) + i, self.w)) def extract_number(self): if self.index >= self.n: self.twist() y = self.MT[self.index] y ^= (y >> self.u) & self.d y ^= (y << self.s) & self.b y ^= (y << self.t) & self.c y ^= (y >> self.l) self.index += 1 return getLowestBits(y, self.w) def twist(self): for i in range(self.n): x = (self.MT[i] & self.upperMask) + (self.MT[(i + 1) % self.n] & self.lowerMask) x_a = x >> 1 if x % 2 != 0: x_a ^= self.a self.MT[i] = self.MT[(i + self.m) % self.n] ^ x_a self.index = 0 ######################################################################################################### def runRoutine(): time.sleep(random.randint(40,100)) seed = int(time.time()) mt = MT19937(seed) time.sleep(random.randint(40,100)) return seed, mt.extract_number() def crackSeed(target): curSeed = int(time.time()) curTry = MT19937(curSeed) while curTry.extract_number() != target: curSeed -= 1 curTry = MT19937(curSeed) return curSeed def main(): print ("Running routine...") originalSeed, target = runRoutine() print ("Original seed:",originalSeed,"\nTarget output:",target,"\n") seed = crackSeed(target) print ("Found original seed:",seed) if __name__ == '__main__': main()
Challenge 23:
from os import urandom def getLowestBits(n, number_of_bits): mask = (1 << number_of_bits) - 1 return n & mask class MT19937: # Coefficients for MT19937-32 w, n, m, r = 32, 624, 397, 31 a = 0x9908b0df u, d = 11, 0xffffffff s, b = 7, 0x9d2c5680 t, c = 15, 0xefc60000 l = 18 f = 1812433253 lowerMask = (1 << r) - 1 upperMask = getLowestBits(not lowerMask, w) def __init__(self,seed): self.MT = [] self.index = self.n self.MT.append(seed) for i in range(1, self.index): self.MT.append(getLowestBits(self.f * (self.MT[i - 1] ^ (self.MT[i - 1] >> (self.w - 2))) + i, self.w)) def extractNumber(self): if self.index >= self.n: self.twist() y = self.MT[self.index] y ^= (y >> self.u) & self.d y ^= (y << self.s) & self.b y ^= (y << self.t) & self.c y ^= (y >> self.l) self.index += 1 return getLowestBits(y, self.w) def twist(self): for i in range(self.n): x = (self.MT[i] & self.upperMask) + (self.MT[(i + 1) % self.n] & self.lowerMask) x_a = x >> 1 if x % 2 != 0: x_a ^= self.a self.MT[i] = self.MT[(i + self.m) % self.n] ^ x_a self.index = 0 def untemper(x): x ^= (x >> MT19937.l) x ^= (x << MT19937.t) & MT19937.c smask = (1 << MT19937.s) - 1 x ^= (x << MT19937.s) & MT19937.b & (smask << MT19937.s) x ^= (x << MT19937.s) & MT19937.b & (smask << (MT19937.s*2)) x ^= (x << MT19937.s) & MT19937.b & (smask << (MT19937.s*3)) x ^= (x << MT19937.s) & MT19937.b & (smask << (MT19937.s*4)) umask = (1 << MT19937.u) - 1 x ^= (x >> MT19937.u) & (umask << (MT19937.u*2)) x ^= (x >> MT19937.u) & (umask << MT19937.u) x ^= (x >> MT19937.u) & umask return x def main(): seed = int(bytes.hex(urandom(10)),16) mt = MT19937(seed) newMT = [] for i in range(MT19937.n): newMT.append( untemper(mt.extractNumber()) ) clonedMT = MT19937(0) clonedMT.MT = newMT for i in range(1337): curOriginal = mt.extractNumber() curCloned = clonedMT.extractNumber() print ("\nOriginal Generated:",curOriginal) print ("Cloned Generated:",curCloned) if curOriginal != curCloned: print ("Error: different values generated!") break if __name__ == '__main__': main()
Challenge 24:
from os import urandom def xor(s1, s2): assert len(s1) == len(s2) ret = b"".join( bytes.fromhex(hex(s1[i]^s2[i])[2:].rjust(2,"0")) for i in range(0,len(s1)) ) return ret def getLowestBits(n, number_of_bits): mask = (1 << number_of_bits) - 1 return n & mask class MT19937: # Coefficients for MT19937-32 w, n, m, r = 32, 624, 397, 31 a = 0x9908b0df u, d = 11, 0xffffffff s, b = 7, 0x9d2c5680 t, c = 15, 0xefc60000 l = 18 f = 1812433253 lowerMask = (1 << r) - 1 upperMask = getLowestBits(not lowerMask, w) def __init__(self,seed): self.MT = [] self.index = self.n self.MT.append(seed) for i in range(1, self.index): self.MT.append(getLowestBits(self.f * (self.MT[i - 1] ^ (self.MT[i - 1] >> (self.w - 2))) + i, self.w)) def extractNumber(self): if self.index >= self.n: self.twist() y = self.MT[self.index] y ^= (y >> self.u) & self.d y ^= (y << self.s) & self.b y ^= (y << self.t) & self.c y ^= (y >> self.l) self.index += 1 return getLowestBits(y, self.w) def twist(self): for i in range(self.n): x = (self.MT[i] & self.upperMask) + (self.MT[(i + 1) % self.n] & self.lowerMask) x_a = x >> 1 if x % 2 != 0: x_a ^= self.a self.MT[i] = self.MT[(i + self.m) % self.n] ^ x_a self.index = 0 class MT19937Cipher: def __init__(self,seed): self.mt = MT19937(seed) def encrypt(self,plaintext): keyStream = b"" while len(keyStream) < len(plaintext): keyStream += str(self.mt.extractNumber()).encode() #ciphertext = hex(int(bytes.hex(plaintext),16) ^ int(bytes.hex(keyStream[:len(plaintext)]),16))[2:].encode() return xor(plaintext,keyStream[:len(plaintext)]) def breakCipher(ciphertext,crib): for i in range(0,2**16): curMT = MT19937Cipher(i).encrypt(ciphertext) if crib in curMT: return i return -1 def main(): seed = int(bytes.hex(urandom(2)),16) prefix = urandom(int(bytes.hex(urandom(1)),16)) plaintext = prefix + b"A"*16 ciphertext = MT19937Cipher(seed).encrypt(plaintext) recoveredSeed = breakCipher(ciphertext, b"A"*16) if recoveredSeed != -1: print ("Seed recovered successfully.\nOriginal plaintext:", MT19937Cipher(recoveredSeed).encrypt(ciphertext)) else: print ("Failed to recover seed") if __name__ == '__main__': main()