def findFakeBlockForPadOfOne(encryptedBlockToCypher): fakeBlock = bytearray(generateNRandomeBytes(len(encryptedBlockToCypher))) for byte in range(256): fakeBlock[-1] = byte if secondFunction(b''.join([fakeBlock, encryptedBlockToCypher])): return bytes(fakeBlock);
03h 03h 03h is even less likely. So you can assume that if you corrupt a decryption AND it had valid padding, you know what that padding byte is. It is easy to get tripped up on the fact that CBC plaintexts are "padded". Padding oracles have nothing to do with the actual padding on a CBC plaintext. It's an attack that targets a specific bit of code that handles decryption. You can mount a padding oracle on any CBC block, whether it's padded or not. """ from s2_10 import AES128CBCCipher from s2_11 import generateNRandomeBytes import random import base64 from s2_15 import validPKCS7Padding from s1_2 import xor s2_16KEY = generateNRandomeBytes(16) s2_16IV = generateNRandomeBytes(16) ecbCypher = AES128CBCCipher(s2_16KEY, s2_16IV) a10Strings = list(map(base64.b64decode, [b'MDAwMDAwTm93IHRoYXQgdGhlIHBhcnR5IGlzIGp1bXBpbmc=',b'MDAwMDAxV2l0aCB0aGUgYmFzcyBraWNrZWQgaW4gYW5kIHRoZSBWZWdhJ3MgYXJlIHB1bXBpbic=',b'MDAwMDAyUXVpY2sgdG8gdGhlIHBvaW50LCB0byB0aGUgcG9pbnQsIG5vIGZha2luZw==',b'MDAwMDAzQ29va2luZyBNQydzIGxpa2UgYSBwb3VuZCBvZiBiYWNvbg==',b'MDAwMDA0QnVybmluZyAnZW0sIGlmIHlvdSBhaW4ndCBxdWljayBhbmQgbmltYmxl',b'MDAwMDA1SSBnbyBjcmF6eSB3aGVuIEkgaGVhciBhIGN5bWJhbA==',b'MDAwMDA2QW5kIGEgaGlnaCBoYXQgd2l0aCBhIHNvdXBlZCB1cCB0ZW1wbw==',b'MDAwMDA3SSdtIG9uIGEgcm9sbCwgaXQncyB0aW1lIHRvIGdvIHNvbG8=',b'MDAwMDA4b2xsaW4nIGluIG15IGZpdmUgcG9pbnQgb2g=',b'MDAwMDA5aXRoIG15IHJhZy10b3AgZG93biBzbyBteSBoYWlyIGNhbiBibG93'])) def firstFunction(): randomeStringFrom10 = a10Strings[random.randint(0,9)] return (ecbCypher.encrypt(randomeStringFrom10), s2_16IV) def secondFunction(encryptedContent): enryptedMsg = encryptedContent decryptredMsg = ecbCypher.decrypt(enryptedMsg) try:
Don't overthink it. Points for automating this, but part of the reason I'm having you do this is that I think this approach is suboptimal. """ from set1_4 import readAllLinesFromFile import base64 from s2_11 import generateNRandomeBytes from s3_18 import AES128CTRCipher from set1_6Helper import getListOfColumns from set1_3 import cypherOneByteXor from s3_18 import xorNotSameSize fpath = "C:\\Programming\\pythonWorkspaces\\cryptopalsWorkspace\\set1\\19.txt" contentList = list(map(base64.b64decode, readAllLinesFromFile(fpath))) key = generateNRandomeBytes(16) nonce = (0).to_bytes(8, byteorder='little') CTRCipher = AES128CTRCipher(key) encryptedContentList = [CTRCipher.encrypt(content, nonce) for content in contentList] #somewhat similar to challenge 6 (mostly copy and past from there) oneByteXorLettersList = getListOfColumns(encryptedContentList) #cypher the key by using 1ByteXor cypher keyletters=[] for oneByteXorLetters in oneByteXorLettersList: keyletters.append(cypherOneByteXor(oneByteXorLetters,1)) cypheredKeyBytesList = [res[0][0] for res in keyletters] keyStream = bytearray(); for keyByte in cypheredKeyBytesList: keyStream.append(keyByte[0]) keyStream = bytes(keyStream)
... encoded as: [email protected]&uid=10&role=user Your "profile_for" function should not allow encoding metacharacters (& and =). Eat them, quote them, whatever you want to do, but don't let people set their email address to "[email protected]&role=admin". Now, two more easy functions. Generate a random AES key, then: Encrypt the encoded user profile under the key; "provide" that to the "attacker". Decrypt the encoded user profile and parse it. Using only the user input to profile_for() (as an oracle to generate "valid" ciphertexts) and the ciphertexts themselves, make a role=admin profile. """ from s2_11 import generateNRandomeBytes, isEBCEcrypted from s2_10 import AES128ECBCipher s2_13KEY = generateNRandomeBytes(16) ecbCipher = AES128ECBCipher(s2_13KEY) def pasreURL(urlStr): resultDic = {} keyValStrs = urlStr.split("&") for keyValStr in keyValStrs: keyValList = keyValStr.split("=") resultDic[keyValList[0]] = keyValList[1] return resultDic def profile_for(emailStr): emailPostHandle = emailStr emailPostHandle = emailPostHandle.replace("&", "^")
- to avoid it our prefix will start with a string that take two-block-size (and we guaranteed that one block in the encryption will be encryption of block of "A"'s) then (while we enlarge our prefix) we make sure our two same encryptedblocks are next to each other -ffs - we also need to make sure to ignore same encrypted blocks that appear in 'target-bytes' and 'random-prefix' (we left with the need to prove that all of this is enough or correct) """ from s1_8 import blocksHistogram from s2_11 import generateNRandomeBytes import random import base64 from s2_10 import AES128ECBCipher from s2_12 import discoverEndOfEncryptedContent s2_14KEY = generateNRandomeBytes(16) s2_14PREFIX = generateNRandomeBytes(random.randint(0, 100)) def s2_14_AES_128_ECB(controlledContent): unknownContent = base64.b64decode( "Um9sbGluJyBpbiBteSA1LjAKV2l0aCBteSByYWctdG9wIGRvd24gc28gbXkgaGFpciBjYW4gYmxvdwpUaGUgZ2lybGllcyBvbiBzdGFuZGJ5IHdhdmluZyBqdXN0IHRvIHNheSBoaQpEaWQgeW91IHN0b3A/IE5vLCBJIGp1c3QgZHJvdmUgYnkK" ) contentToEncrypt = bytearray(s2_14PREFIX) contentToEncrypt.extend(controlledContent) contentToEncrypt.extend(unknownContent) contentToEncrypt = bytes(contentToEncrypt) cbeCipher = AES128ECBCipher(s2_14KEY) encryptedContent = cbeCipher.encrypt(contentToEncrypt)