예제 #1
0
def decrypt(oracle=encryption_oracle):
    block_size = detect_block_size()
    if not is_ecb_mode(block_size, oracle):
        raise Exception('Does not use ecb mode')

    #known secret prefix
    prefix = ''

    #idea: expand known prefix one byte at a time
    #length of:
    #'a'*(block_size - (len(prefix) % block_size) - 1) + prefix + guess_byte
    #is multiple of block size all but last byte is known
    #try each possible value of next byte. For correct guess, ct blocks match first blocks of:
    #'a'*(block_size - (len(prefix) % block_size) - 1) + secret

    while True:
        #determine next byte of secret
        pad_len = block_size - (len(prefix) % block_size) - 1
        found_next = False
        #try most common (ascii) bytes first to speed up search
        for guess in ranking:
            pt = 'a' * pad_len + prefix + guess + 'a' * pad_len
            ct_blocks = aes.splitBlocks(oracle(pt), block_size)
            i = (pad_len + len(prefix) + 1) / block_size
            if ct_blocks[i - 1] == ct_blocks[2 * i - 1]:
                prefix += guess
                found_next = True
                print prefix
                break
        #Assume we are at end of secret when this occurs
        if not found_next:
            return prefix
예제 #2
0
def detect_mode():
    '''distiguishes between CBC and ECB modes given encryption oracle access'''
    pt = 'a' * (11 + 11 + 32)
    ct_blocks = aes.splitBlocks(encryption_oracle(pt))
    if ct_blocks[1] == ct_blocks[2]:
        print 'ECB'
    else:
        print 'probably CBC'
예제 #3
0
def get_key():
    ct = oracle()
    blocks = aes.splitBlocks(ct)

    #send oracle c_0 || 00..0 || c_0
    #	= aes(iv ^ p_0) || 00..0 || aes(iv ^ p_0)
    #	= aes(key ^ p_0) || 00..0 || aes(key ^ p_0)
    #This decrypts to:
    #	p_0' || p_1' || p_2' = p_0 || aes_dec(00...) ^ c_0 || key ^ p_0
    #==> key = p_0' ^ p_2'

    parts = [blocks[0], '\0' * 16, blocks[0]]
    parts.extend(blocks[3:])
    ctp = ''.join(parts)
    try:
        #p_1' = aes_dec(00...0) is non ascii with high probability
        #so we should get error with returned plaintext
        consume_ct(ctp)
    except NonAscii as e:
        blocks = aes.splitBlocks(e.args[0])
        return util.xor(blocks[0], blocks[2])
예제 #4
0
def get_pad_ct(pad_letter, oracle=encryption_oracle, block_size=16):
    #get aes(pad_letter*block_size)
    assert (len(pad_letter) == 1)

    c = oracle(pad_letter * (3 * block_size))

    #because the prefix is random, the first equal blocks are almost
    #guarrenteed to be enc(pad_letter*block_size)
    blocks = aes.splitBlocks(c, block_size)

    i = 0
    while blocks[i] != blocks[i + 1]:
        i += 1
    return blocks[i]
예제 #5
0
파일: p17.py 프로젝트: AdrS/cryptopals
def decrypt_ciphertext(ct):
	ct_blocks = aes.splitBlocks(ct)
	pt_blocks = []
	#for each block (except iv)
	for i in range(1,len(ct_blocks)):
		#Consider the first i blocks:
		#iv || c1,1 c1,2 c1,3 ... c1,16 || ... || ci,1 ci,2 ... ci,16
		suffix = ''
		#determine bytes in ith block working backward
		for _ in range(16):
			#try guessing each possible byte value
			found = False
			for g in ranking:
				#setting:
				#c'_{i - 1} = c_{i - 1} xor 00..0 || guess|| suffix
				#causes c_i to decrypt to:
				#m_i xor 00..0 || guess|| suffix = m_i1 ...x00000
				#	where x = 0 iff the guess is correct
				#slen = len(suffix)
				#t1 = '\x00'*(15 - slen) + g + suffix
				#t2 = '\x00'*(15 - slen) + chr(slen + 1)*(slen + 1)
				#setting:
				#c'_{i - 1} = c_{i - 1} xor t1 xor t2
				#causes c_i to decrypt to
				#m_i xor t1 xor t2
				#mi,1 mi,2 .. ((mi,k xor guess) xor (slen + 1)) 
				#which has valid padding if the guess is correct
				cp = xor_tail(ct_blocks[i - 1], g + suffix)
				cp = xor_tail(cp, chr(len(suffix) + 1)*(len(suffix) + 1))
				ct = ct_blocks[:i - 1]
				ct.append(cp)
				ct.append(ct_blocks[i])
				if valid_padding(''.join(ct)):
					suffix = g + suffix
					found = True
					break
			if not found:
				raise Exception("could not find value of byte")
		pt_blocks.append(suffix)
	return aes.remove_pkcs7_padding(''.join(pt_blocks))
예제 #6
0
def is_ecb_mode(block_size=16, oracle=encryption_oracle):
    '''distiguishes between CBC and ECB modes given encryption oracle access'''
    ct_blocks = aes.splitBlocks(oracle('a' * (2 * block_size)), block_size)
    return ct_blocks[0] == ct_blocks[1]
예제 #7
0
def decrypt(oracle=encryption_oracle):
    block_size = 16
    #1) get enc(r || 3 blocks of as || secret || padding)
    #	find first pair of adjacent blocks that are equal =>
    #	the equal blocks are both: enc(aaa...a)
    cpa = get_pad_ct('a')

    #2) repeat previous step to find enc(bbb...b)
    cpb = get_pad_ct('b')

    known_prefix = ''
    while True:
        #while full message not known
        #3) want: enc( ..... known_prefix <next byte of secret> <block boundary> ....)

        pad_len = 2 * block_size - len(known_prefix) % block_size - 1
        assert (block_size <= pad_len)
        assert (pad_len < 2 * block_size)

        #when <next byte of secret> is last byte of block
        #
        #c = enc(r || b*bloc_size a*pad_len secret || padding)
        #
        #has the blocks enc(b*block_size) || enc(a*block_size) next to each other

        #find lb = last block of ciphertext when <next secret byte is aligned>
        aligned = False
        while not aligned:
            c = oracle('b' * block_size + 'a' * pad_len)
            blocks = aes.splitBlocks(c, block_size)

            #check if next byte of secret is next to block boundary
            for i in range(len(blocks) - 1):
                if blocks[i] == cpb and blocks[i + 1] == cpa:
                    #it is
                    #soff = index last block - index of enc(a*block_size) + 1
                    soff = len(blocks) - (i + 1)
                    lb = blocks[-1]
                    aligned = True
                    break

        found = False
        for guess in ranking:
            #get c = enc(r || a*pad_len known_prefix guess a*pad_len secret || padding)
            #where guess is algined with byte boundary (this happends when c ends with lb
            while True:
                c = oracle('a' * pad_len + known_prefix + guess +
                           'a' * pad_len)
                if c.endswith(lb): break
                #~block_size requests
            blocks = aes.splitBlocks(c, block_size)

            #TODO: check these indicies (not correct ones)
            #blocks[-soff] = first block before secret
            #blocks[-soff - 1] = enc(end of known prefix guess)

            #offset from first block before secret to block with <next byte of secret
            coff = (pad_len + len(known_prefix) + 1) / block_size

            if blocks[-soff - 1] == blocks[-soff + coff - 1]:
                known_prefix += guess
                print known_prefix
                found = True
                break
        if not found: return known_prefix