master e16735aca093 cached
14 files
46.6 KB
16.5k tokens
53 symbols
1 requests
Download .txt
Repository: TomLous/coursera-cryptography1
Branch: master
Commit: e16735aca093
Files: 14
Total size: 46.6 KB

Directory structure:
gitextract_akths2on/

├── README.md
├── week1-problemset/
│   ├── programming_assignment.py
│   └── question7.py
├── week2-problemset/
│   ├── programming_assignment.py
│   ├── question1.py
│   ├── question2.py
│   ├── question4.py
│   ├── question5.py
│   └── question9.py
├── week3-problemset/
│   ├── programming_assignment.py
│   ├── question8.py
│   └── question9.py
└── week4-problemset/
    ├── programming_assignment.py
    └── question1.py

================================================
FILE CONTENTS
================================================

================================================
FILE: README.md
================================================
coursera-cryptography1
======================

Assignments for Coursera's Cryptography I course by Dan Boneh


================================================
FILE: week1-problemset/programming_assignment.py
================================================
# Stanford University
# Cryptography I
# https://www.coursera.org/course/crypto

# Week 1
# Question 1
# Many Time Pad 

# Let us see what goes wrong when a stream cipher key is used more than once. Below are eleven hex-encoded ciphertexts that are the result of encrypting eleven plaintexts with a stream cipher, all with the same stream cipher key. Your goal is to decrypt the last ciphertext, and submit the secret message within it as solution. 
# Hint: XOR the ciphertexts together, and consider what happens when a space is XORed with a character in [a-zA-Z]. 

import sys
from operator import methodcaller
import re

def main():
	cypherTexts = []
	# cyphertext 1 (0)
	cypherTexts.append("315c4eeaa8b5f8aaf9174145bf43e1784b8fa00dc71d885a804e5ee9fa40b16349c146fb778cdf2d3aff021dfff5b403b510d0d0455468aeb98622b137dae857553ccd8883a7bc37520e06e515d22c954eba5025b8cc57ee59418ce7dc6bc41556bdb36bbca3e8774301fbcaa3b83b220809560987815f65286764703de0f3d524400a19b159610b11ef3e")
	# cyphertext 2 (1)
	cypherTexts.append("234c02ecbbfbafa3ed18510abd11fa724fcda2018a1a8342cf064bbde548b12b07df44ba7191d9606ef4081ffde5ad46a5069d9f7f543bedb9c861bf29c7e205132eda9382b0bc2c5c4b45f919cf3a9f1cb74151f6d551f4480c82b2cb24cc5b028aa76eb7b4ab24171ab3cdadb8356f")
	# cyphertext 3 (2)
	cypherTexts.append("32510ba9a7b2bba9b8005d43a304b5714cc0bb0c8a34884dd91304b8ad40b62b07df44ba6e9d8a2368e51d04e0e7b207b70b9b8261112bacb6c866a232dfe257527dc29398f5f3251a0d47e503c66e935de81230b59b7afb5f41afa8d661cb")
	# cyphertext 4 (3)
	cypherTexts.append("32510ba9aab2a8a4fd06414fb517b5605cc0aa0dc91a8908c2064ba8ad5ea06a029056f47a8ad3306ef5021eafe1ac01a81197847a5c68a1b78769a37bc8f4575432c198ccb4ef63590256e305cd3a9544ee4160ead45aef520489e7da7d835402bca670bda8eb775200b8dabbba246b130f040d8ec6447e2c767f3d30ed81ea2e4c1404e1315a1010e7229be6636aaa")
	# cyphertext 5 (4) 
	cypherTexts.append("3f561ba9adb4b6ebec54424ba317b564418fac0dd35f8c08d31a1fe9e24fe56808c213f17c81d9607cee021dafe1e001b21ade877a5e68bea88d61b93ac5ee0d562e8e9582f5ef375f0a4ae20ed86e935de81230b59b73fb4302cd95d770c65b40aaa065f2a5e33a5a0bb5dcaba43722130f042f8ec85b7c2070")
	# cyphertext 6 (5)
	cypherTexts.append("32510bfbacfbb9befd54415da243e1695ecabd58c519cd4bd2061bbde24eb76a19d84aba34d8de287be84d07e7e9a30ee714979c7e1123a8bd9822a33ecaf512472e8e8f8db3f9635c1949e640c621854eba0d79eccf52ff111284b4cc61d11902aebc66f2b2e436434eacc0aba938220b084800c2ca4e693522643573b2c4ce35050b0cf774201f0fe52ac9f26d71b6cf61a711cc229f77ace7aa88a2f19983122b11be87a59c355d25f8e4")
	# cyphertext 7 (6)
	cypherTexts.append("32510bfbacfbb9befd54415da243e1695ecabd58c519cd4bd90f1fa6ea5ba47b01c909ba7696cf606ef40c04afe1ac0aa8148dd066592ded9f8774b529c7ea125d298e8883f5e9305f4b44f915cb2bd05af51373fd9b4af511039fa2d96f83414aaaf261bda2e97b170fb5cce2a53e675c154c0d9681596934777e2275b381ce2e40582afe67650b13e72287ff2270abcf73bb028932836fbdecfecee0a3b894473c1bbeb6b4913a536ce4f9b13f1efff71ea313c8661dd9a4ce")
	# cyphertext 8 (7)
	cypherTexts.append("315c4eeaa8b5f8bffd11155ea506b56041c6a00c8a08854dd21a4bbde54ce56801d943ba708b8a3574f40c00fff9e00fa1439fd0654327a3bfc860b92f89ee04132ecb9298f5fd2d5e4b45e40ecc3b9d59e9417df7c95bba410e9aa2ca24c5474da2f276baa3ac325918b2daada43d6712150441c2e04f6565517f317da9d3")
	# cyphertext 9 (8)
	cypherTexts.append("271946f9bbb2aeadec111841a81abc300ecaa01bd8069d5cc91005e9fe4aad6e04d513e96d99de2569bc5e50eeeca709b50a8a987f4264edb6896fb537d0a716132ddc938fb0f836480e06ed0fcd6e9759f40462f9cf57f4564186a2c1778f1543efa270bda5e933421cbe88a4a52222190f471e9bd15f652b653b7071aec59a2705081ffe72651d08f822c9ed6d76e48b63ab15d0208573a7eef027")
	# cyphertext 10 (9)
	cypherTexts.append("466d06ece998b7a2fb1d464fed2ced7641ddaa3cc31c9941cf110abbf409ed39598005b3399ccfafb61d0315fca0a314be138a9f32503bedac8067f03adbf3575c3b8edc9ba7f537530541ab0f9f3cd04ff50d66f1d559ba520e89a2cb2a83")
	# cyphertext target (10)
	cypherTexts.append("32510ba9babebbbefd001547a810e67149caee11d945cd7fc81a05e9f85aac650e9052ba6a8cd8257bf14d13e6f0a803b54fde9e77472dbff89d71b57bddef121336cb85ccb8f3315f4b52e301d16e9f52f904")
	
	
	# convert all to ASCII
	cypherTextsDecoded = map(methodcaller("decode", "hex"), cypherTexts)

	# chose two to XOR

	## This part of the program is interactive.
	## Keep guessing cribs and see how they might match in various XOR-ed cyphertexts (== XOR-ed plaintext) 
	## Finally choose the longest, fully decrypted crib (6) and the target cypher (10)
	# /begin interactive
	crib = "There are two types of cyptography: one that allows the Government to use brute force to break the code, and one that requires the Government to use brute force to break you"
	xorTextNum1 = 6
	xorTextNum2 = 10
	# /end interatcive
	
	xoredText = strxor(cypherTextsDecoded[xorTextNum1], cypherTextsDecoded[xorTextNum2])

	# loop all individual positions of the XOR-ed crypto (plain) text
	textLength = len(xoredText)
	for i in range(textLength):
			# XOR the substring with the crib
    		substrXoredText = xoredText[i:]
    		cribDraggedText = strxor(substrXoredText,crib)

    		# do an estimated guess wether the text is readable, if so print the guess (in place)
    		if(isreadable(cribDraggedText)):
				printCodePos(i, cribDraggedText, textLength, '.')
    		
    
    	print "\n\nGuess key (when the crib starts lining up):"
    	key = strxor(cypherTextsDecoded[xorTextNum1], crib)
    	print "key: %s"%key.encode('hex')

	print "\n\nDecrypt all messages using the key:"
    	for j, cypher in enumerate(cypherTextsDecoded) :
    		print "[%d] %s" % (j, strxor(cypher, key))



	
	
def strxor(a, b):     # xor two strings of different lengths
    if len(a) > len(b):
        return "".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a[:len(b)], b)])
    else:
        return "".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a, b[:len(a)])])

def isreadable(str): # check readability (allow only alphanumeric chars and some punctiation)
	return bool(re.search('^[a-zA-Z0-9\., \'\"\-_\:\(\)]+$', str))

def printCodePos(i, code, maxLen, filler): # output the guess in place of the message
	prefix =  filler*i
	ln = len(code)
	postfix = filler*(maxLen-i-ln)
	print("%s%s%s" % (prefix,code,postfix))
    	

main()
	
## Output
# The secret message is: When using a stream cipher, never use the key more than once
# ..................................................................................C


# Guess key (when the crib starts lining up):
# key: 66396e89c9dbd8cc9874352acd6395102eafce78aa7fed28a07f6bc98d29c50b69b0339a19f8aa401a9c6d708f80c066c763fef0123148cdd8e802d05ba98777335daefcecd59c433a6b268b60bf4ef03c9a611098bb3e9a3161edc7b804a33522cfd202d2c68c57376edba8c2ca50027c61246ce2a12b0c4502175010c0a1ba4625786d911100797d8a47e98b0204c4ef06c867a950f11ac989dea88fd1dbf16748749ed4c6f45b384c9d96c4

# Decrypt all messages using the key:
# [0] We can factor the number 15 with quantum computers. We can also factor the number 15 with a dog trained to bark three times - Robert Harley
# [1] Euler would probably enjoy that now his theorem becomes a corner stone of crypto - Annonymous on Euler's theorem
# [2] The nice thing about Keeyloq is now we cryptographers can drive a lot of fancy cars - Dan Boneh
# [3] The ciphertext produced by a weak encryption algorithm looks as good as ciphertext produced by a strong encryption algorithm - Philip Zimmermann
# [4] You don't want to buy a set of car keys from a guy who specializes in stealing cars - Marc Rotenberg commenting on Clipper
# [5] There are two types of cryptography - that which will keep secrets safe from your little sister, and that which will keep secrets safe from your government - Bruce Schneier
# [6] There are two types of cyptography: one that allows the Government to use brute force to break the code, and one that requires the Government to use brute force to break you
# [7] We can see the point where the chip is unhappy if a wrong bit is sent and consumes more power from the environment - Adi Shamir
# [8] A (private-key)  encryption scheme states 3 algorithms, namely a procedure for generating keys, a procedure for encrypting, and a procedure for decrypting.?
# [9]  The Concise OxfordDictionary (2006) defines crypto as the art of  writing o r solving codes. 
# [10] The secret message is: When using a stream cipher, never use the key more than once



================================================
FILE: week1-problemset/question7.py
================================================
import sys

def main():
	text1 = "attack at dawn"
	encoded1 = "6c73d5240a948c86981bc294814d".decode("hex")
	key = xor_strings(text1, encoded1)

	text2 = "attack at dusk"
	encoded2 = xor_strings(text2, key)
	print encoded2.encode("hex")

def xor_strings(strA, strB):
	return "".join(chr(ord(chrA) ^ ord(chrB)) for (chrA, chrB) in zip(strA, strB))

main()

================================================
FILE: week2-problemset/programming_assignment.py
================================================
# Stanford University
# Cryptography I
# https://www.coursera.org/course/crypto

# Week 2
# Question 1-4


# In this project you will implement two encryption/decryption systems, one using AES in CBC mode and another using AES in counter mode (CTR). In both cases the 16-byte encryption IV is chosen at random and is prepended to the ciphertext. For CBC encryption we use the PKCS5 padding scheme discussed in class (13:50). 
# While we ask that you implement both encryption and decryption, we will only test the decryption function. In the following questions you are given an AES key and a ciphertext (both are hex encoded) and your goal is to recover the plaintext and enter it in the input boxes provided below. 

# For an implementation of AES you may use an existing crypto library such as PyCrypto (Python), Crypto++ (C++), or any other. While it is fine to use the built-in AES functions, we ask that as a learning experience you implement CBC and CTR modes yourself. 

import sys
from operator import methodcaller
import re
import numpy
from Crypto.Cipher import AES
from Crypto.Util import Counter
from Crypto import Random

def main():
	blockSize = 16 # 16-byte encryption
	q1 = cbcDecrypt("140b41b22a29beb4061bda66b6747e14", "4ca00ff4c898d61e1edbf1800618fb2828a226d160dad07883d04e008a7897ee2e4b7465d5290d0c0e6c6822236e1daafb94ffe0c5da05d9476be028ad7c1d81", blockSize)	
	q2 = cbcDecrypt("140b41b22a29beb4061bda66b6747e14", "5b68629feb8606f9a6667670b75b38a5b4832d0f26e1ab7da33249de7d4afc48e713ac646ace36e872ad5fb8a512428a6e21364b0c374df45503473c5242a253", blockSize)	
	q3 = ctrDecrypt("36f18357be4dbd77f050515c73fcf9f2", "69dda8455c7dd4254bf353b773304eec0ec7702330098ce7f7520d1cbbb20fc388d1b0adb5054dbd7370849dbf0b88d393f252e764f1f5f7ad97ef79d59ce29f5f51eeca32eabedd9afa9329", blockSize)	
	q4 = ctrDecrypt("36f18357be4dbd77f050515c73fcf9f2", "770b80259ec33beb2561358a9f2dc617e46218c0a53cbeca695ae45faa8952aa0e311bde9d4e01726d3184c34451", blockSize)	
	
	print "\n\nAnswers:"
	print "Q1. ",q1
	print "Q2. ",q2
	print "Q3. ",q3
	print "Q4. ",q4

	#Result
	# CBC decryption of key/cypher 140b41b22a29beb4061bda66b6747e14  /  4ca00ff4c898d61e1edbf1800618fb2828a226d160dad07883d04e008a7897ee2e4b7465d5290d0c0e6c6822236e1daafb94ffe0c5da05d9476be028ad7c1d81
	# 1:  Basic CBC mode encryption needs padding.
	# 2:  Basic CBC mode encryption needs padding.

	# CBC decryption of key/cypher 140b41b22a29beb4061bda66b6747e14  /  5b68629feb8606f9a6667670b75b38a5b4832d0f26e1ab7da33249de7d4afc48e713ac646ace36e872ad5fb8a512428a6e21364b0c374df45503473c5242a253
	# 1:  Our implementation uses rand. IV
	# 2:  Our implementation uses rand. IV

	# CTR decryption of key/cypher 36f18357be4dbd77f050515c73fcf9f2  /  69dda8455c7dd4254bf353b773304eec0ec7702330098ce7f7520d1cbbb20fc388d1b0adb5054dbd7370849dbf0b88d393f252e764f1f5f7ad97ef79d59ce29f5f51eeca32eabedd9afa9329
	# 1:  CTR mode lets you build a stream cipher from a block cipher.
	# 2:  ?

	# CTR decryption of key/cypher 36f18357be4dbd77f050515c73fcf9f2  /  770b80259ec33beb2561358a9f2dc617e46218c0a53cbeca695ae45faa8952aa0e311bde9d4e01726d3184c34451
	# 1:  Always avoid the two time pad!
	# 2:  ?


	# Answers:
	# Q1.  Basic CBC mode encryption needs padding.
	# Q2.  Our implementation uses rand. IV
	# Q3.  CTR mode lets you build a stream cipher from a block cipher.
	# Q4.  Always avoid the two time pad!


# Do 2 variants of CTR decryption  	
def ctrDecrypt(key, cypherText, blockSize):
	print "\nCTR decryption of key/cypher",key," / ",cypherText
	res1 = ctrDecrypt1(key, cypherText, blockSize)
	res2 = ctrDecrypt2(key, cypherText, blockSize)
	print "1: ", res1 
	print "2: ", res2
	return res1

# CTR decryption variant 1 (use AES.MODE_CBC mode), 
def ctrDecrypt1(key, cypherText, blockSize):
	k = key.decode('hex')
	ct = cypherText.decode('hex')
	iv = ct[:blockSize]
	ct1 = ct[blockSize:]
	ctr = Counter.new(blockSize*8,initial_value=long(iv.encode('hex'),16))
	obj = AES.new(k,AES.MODE_CTR,counter=ctr)
	paddedStr = obj.decrypt(ct1)
	#paddingAmount = ord(paddedStr[len(paddedStr)-1:])
	return paddedStr#[:-paddingAmount]

# CTR decryption variant 2 
def ctrDecrypt2(key, cypherText, blockSize):
	cypherTextBlocks =  [cypherText[i:i+(blockSize*2)] for i in range(0, len(cypherText), (blockSize*2))]	
	iv =  long(cypherTextBlocks.pop(0), 16) 

	cypherTextBlocksDecoded = map(methodcaller("decode", "hex"), cypherTextBlocks)
	
	k = key.decode('hex')

	pt = ""

	i = 0
	for c in cypherTextBlocksDecoded:
	 	ctr = hex(iv+i << 64)[2:(2*blockSize)+2]
	 	#print ctr
	 	encIV = AES.new(k, AES.MODE_ECB).encrypt(ctr)	
	 	plaintext =  strxor(encIV, c)
	 	#print plaintext
	  	i = i + 1
	  	pt = plaintext + pt
	
	# @todo something is wrong with this implementation		
	return "?"#pt
  
# Do 2 variants of CBC decryption  	
def cbcDecrypt(key, cypherText, blockSize):
	print "\nCBC decryption of key/cypher",key," / ",cypherText
	res1 = cbcDecrypt1(key, cypherText, blockSize)
	res2 = cbcDecrypt2(key, cypherText, blockSize)
	print "1: ", res1 
	print "2: ", res2
	return res2

# CBC decryption variant 1 (use AES.MODE_CBC mode), 
def cbcDecrypt1(key, cypherText, blockSize):
	k = key.decode('hex')
	ct = cypherText.decode('hex')
	iv = ct[:blockSize]
	ct1 = ct[blockSize:]
	obj = AES.new(k,AES.MODE_CBC,iv)
	paddedStr = obj.decrypt(ct1)
	paddingAmount = ord(paddedStr[len(paddedStr)-1:])
	return paddedStr[:-paddingAmount]


# CBC decryption variant 2 defines blocks self, encrypts per block (ECB mode) and xors with previous block => plaintext
def cbcDecrypt2(key, cypherText, blockSize):
	cypherTextBlocks =  [cypherText[i:i+(blockSize*2)] for i in range(0, len(cypherText), (blockSize*2))]
	cypherTextBlocksDecoded = map(methodcaller("decode", "hex"), cypherTextBlocks)
	#iv =  cypherTextBlocksDecoded.pop(0)
	k = key.decode('hex')

	pt = ""

	iter = len(cypherTextBlocksDecoded)
	for c in reversed(cypherTextBlocksDecoded):
		iter = iter - 1
		if(iter > 0):
			cipher = AES.new(k, AES.MODE_ECB).decrypt(c)			
			plaintext = strxor(cipher, cypherTextBlocksDecoded[iter - 1])
			#print "[",iter,"]", c.encode('hex'), " => ", cipher.encode('hex'), plaintext
			pt = plaintext + pt

	paddingAmount = ord(pt[len(pt)-1:])
			
	return pt[:-paddingAmount]


# xor two strings of different lengths
def strxor(a, b):     
    if len(a) > len(b):
        return "".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a[:len(b)], b)])
    else:
        return "".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a, b[:len(a)])])

main()
	



================================================
FILE: week2-problemset/question1.py
================================================
# Stanford University
# Cryptography I
# https://www.coursera.org/course/crypto

# Week 2
# Question 1
# Consider the following five events:
# Correctly guessing a random 128-bit AES key on the first try.
# Winning a lottery with 1 million contestants (the probability is 1/106 ).
# Winning a lottery with 1 million contestants 5 times in a row (the probability is (1/106)5 ).
# Winning a lottery with 1 million contestants 6 times in a row.
# Winning a lottery with 1 million contestants 7 times in a row.
# What is the order of these events from most likely to least likely?


import sys
import numpy


def main():
	amounts = numpy.array([
		pow(2,128), 		# Correctly guessing a random 128-bit AES key on the first try.
		pow(10,6), 		# Winning a lottery with 1 million contestants (the probability is 1/10^6 ).
		pow(pow(10,6),5),		# Winning a lottery with 1 million contestants 5 times in a row (the probability is (1/106)5 ).
		pow(pow(10,6),6),		# Winning a lottery with 1 million contestants 6 times in a row.
		pow(pow(10,6),7),		# Winning a lottery with 1 million contestants 7 times in a row.
	])

	sortIndex = numpy.argsort(amounts)
		
	sortIndex = [x+1 for x in sortIndex]

	print sortIndex
	# result [2, 3, 4, 1, 5]



main()

================================================
FILE: week2-problemset/question2.py
================================================
# Stanford University
# Cryptography I
# https://www.coursera.org/course/crypto

# Week 2
# Question 2
# Suppose that using commodity hardware it is possible to build a computer for about $200 that can brute force about 1 billion AES keys per second. Suppose an organization wants to run an exhaustive search for a single 128-bit AES key and was willing to spend 4 trillion dollars to buy these machines (this is more than the annual US federal budget). How long would it take the organization to brute force this single 128-bit AES key with these machines? Ignore additional costs such as power and maintenance.


import sys
import numpy


def main():
	computerPrice = 200 # = $200 
	budget = 4*pow(10,12) # =$ 4 trillion dollars

	keysPerSecondPerComputer = pow(10,9) # 1 billion AES keys per second.
	maxNumberKeys = pow(2,128) # 128-bit AES key

	numComputers = budget / computerPrice
	keysPerSecond = keysPerSecondPerComputer * numComputers

	numberOfSeconds = maxNumberKeys / keysPerSecond 

	print numberOfSeconds , "seconds"
	print (numberOfSeconds/3600) , "hours"
	print (numberOfSeconds/3600/24) , "hours"
	print (numberOfSeconds/3600/24/365) , "years"

	hour = 60*60
	day = hour * 24
	week  = day * 7
	month  = day * 31
	year =  day * 365

	print "\n\nMore than an hour but less than a day? ", numberOfSeconds > hour and numberOfSeconds < day
	print "More than a day but less than a week? ", numberOfSeconds > day and numberOfSeconds < week
	print "More than a week but less than a month? ", numberOfSeconds > week and numberOfSeconds < month
	print "More than a 100 years but less than a million years? ", numberOfSeconds > 100*year and numberOfSeconds < pow(10,6)*year
	print "More than a billion (10^9) years? ", numberOfSeconds > pow(10,9)*year

	# 17014118346046923173 seconds
	# 4726143985013034 hours
	# 196922666042209 hours
	# 539514153540 years


	# More than an hour but less than a day?  False
	# More than a day but less than a week?  False
	# More than a week but less than a month?  False
	# More than a 100 years but less than a million years?  False
	# More than a billion (10^9) years?  True




main()

================================================
FILE: week2-problemset/question4.py
================================================
# Stanford University
# Cryptography I
# https://www.coursera.org/course/crypto

# Week 2
# Question 4
# Recall that the Luby-Rackoff theorem discussed in Lecture 3.2 states that applying a three round Feistel network to a secure PRF gives a secure block cipher. 
# Let's see what goes wrong if we only use a two round Feistel. Let F:Kx{0,1}32->{0,1}32 be a secure PRF. Recall that a 2-round Feistel defines the following PRP   
# F2:K2x{0,1}64->{0,1}64: 
# Two round Feistel
# Here R0 is the right 32 bits of the 64-bit input and L0 is the left 32 bits. 

# One of the following lines is the output of this PRP F2 using a random key, while the other three are the output of a truly random permutation f:{0,1}64->{0,1}64. All 64-bit outputs are encoded as 16 hex characters. Can you say which is the output of the PRP?   Note that since you are able to distinguish the output of F2 from random, F2 is not a secure block cipher, which is what we wanted to show. 

# Hint: First argue that there is a detectable pattern in the xor of F2(.,0^64) and F2(.,1^32 0^32). Then try to detect this pattern in the given outputs.

# On input 0^64 the output is "290b6e3a 39155d6f".    On input 1^32 0^32 the output is "d6f491c5 b645c008".
# On input 0^64 the output is "4af53267 1351e2e1".    On input 1^32 0^32 the output is "87a40cfa 8dd39154".
# On input 0^64 the output is "5f67abaf 5210722b".    On input 1^32 0^32 the output is "bbe033c0 0bc9330e".
# On input 0^64 the output is "2d1cfa42 c0b1d266".    On input 1^32 0^32 the output is "eea6e3dd b2146dd0".


import sys
import numpy
from operator import methodcaller


def main():
	cyphers = [
	[["290b6e3a","39155d6f"], ["d6f491c5","b645c008"]],
	[["4af53267","1351e2e1"], ["87a40cfa","8dd39154"]],
	[["5f67abaf","5210722b"], ["bbe033c0","0bc9330e"]],
	[["2d1cfa42","c0b1d266"], ["eea6e3dd","b2146dd0"]],

	[["5f67abaf","5210722b"], ["bbe033c0","0bc9330e"]],
	[["4af53267","1351e2e1"], ["87a40cfa","8dd39154"]],	
	[["2d1cfa42","c0b1d266"], ["eea6e3dd","b2146dd0"]],
	[["9f970f4e","932330e4"], ["6068f0b1","b645c008"]],

	]	

	for arow in cyphers:
		print "\n", arow
		for i in range(0,2):
			
			val1 = arow[0][i] #+ arow[0][1]
			val2 = arow[1][i] #+ arow[1][1]
			xor = hexStrToInt(val1) ^ hexStrToInt(val2)
			print " %s xor %s => %s" % (val1, val2, intToHexStr(xor))
		
			# [['290b6e3a', '39155d6f'], ['d6f491c5', 'b645c008']]
			# ==>  290b6e3a xor d6f491c5 => ffffffff
			#  39155d6f xor b645c008 => 8f509d67

			# [['4af53267', '1351e2e1'], ['87a40cfa', '8dd39154']]
			#  4af53267 xor 87a40cfa => cd513e9d
			#  1351e2e1 xor 8dd39154 => 9e8273b5

			# [['5f67abaf', '5210722b'], ['bbe033c0', '0bc9330e']]
			#  5f67abaf xor bbe033c0 => e487986f
			#  5210722b xor 0bc9330e => 59d94125

			# [['2d1cfa42', 'c0b1d266'], ['eea6e3dd', 'b2146dd0']]
			#  2d1cfa42 xor eea6e3dd => c3ba199f
			#  c0b1d266 xor b2146dd0 => 72a5bfb6

def hexStrToInt(s):
	return int(s, 16)

def intToHexStr(i):
	return hex(i)[2:]


main()

================================================
FILE: week2-problemset/question5.py
================================================
# Stanford University
# Cryptography I
# https://www.coursera.org/course/crypto

# Week 2
# Question 5
# Nonce-based CBC. Recall that in lecture 4.4 we said that if one wants to use CBC encryption with a non-random unique nonce then the nonce must first be encrypted with an independent PRP key and the result then used as the CBC IV. Let's see what goes wrong if one encrypts the nonce with the same PRP key as the key used for CBC encryption. 

# Let F:Kx{0,1}l->{0,1}l be a secure PRP with, say, l=128. Let n be a nonce and suppose one encrypts a message m by first computing IV=F(k,n)
# and then using this IV in CBC encryption using F(k,.). 
# Note that the same key k is used for computing the IV and for CBC encryption. We show that the resulting system is not nonce-based CPA secure. 

# The attacker begins by asking for the encryption of the two block message m=(0l,0l) with nonce n=0l. It receives back a two block ciphertext (c0,c1). Observe that by definition of CBC we know that c1=F(k,c0). Next, the attacker asks for the encryption of the one block message m1=c0 xor c1 with nonce n=c0. It receives back a one block ciphertext c'0. 

# What relation holds between c0,c1,c'0?   Note that this relation lets the adversary win the nonce-based CPA game with advantage 1.
# c0=c1 xor c'0
# c1=c0
# c1=0l
# c1=c'0



import sys
import numpy
from operator import methodcaller


def main():
	key = hexStrToInt("1a2b3c4d")

	# loop 1
	zero = hexStrToInt("00000000")
	m0Arr = [zero, zero]
	n0 = encrypt(key, zero)

	c0Arr = cbc(key, n0, m0Arr)



	# loop 2
	m1Arr = [c0Arr[0] ^ c0Arr[1]]
	n1 = c0Arr[0]

	c1Arr = cbc(key, n1, m1Arr)	

	
	c0 = int(c0Arr[0])
	c1 = int(c0Arr[1])
	c_0 = int(c1Arr[0])
	# result
	print "c0 = %s" % intToHexStr(c0), c0
	print "c1 = %s" % intToHexStr(c1), c1
	print "c'0 = %s" % intToHexStr(c_0), c_0

	

	print "\n\n"
	print "c0=c1 xor c'0 ? => %s = %s xor %s => %s" % (intToHexStr(c0), intToHexStr(c1), intToHexStr(c_0), (c1 ^ c_0 == c0) )
	print "c1=c0 ? => %s = %s  => %s" % (intToHexStr(c1), intToHexStr(c0),  (c1 == c0) )
	print "c1=0^l ? => %s = %s  => %s" % (intToHexStr(c1), intToHexStr(zero),  (c1 == zero) )
	print "c1=c'0 ? => %s = %s  => %s" % (intToHexStr(c1), intToHexStr(c_0),  (c1 == c_0) )


	# c0 = 00607c3c 6323260
	# c1 = 0859b203 140096003
	# c'0 = 0040f858 4257880



	# c0=c1 xor c'0 ? => 00607c3c = 0859b203 xor 0040f858 => False
	# c1=c0 ? => 0859b203 = 00607c3c  => False
	# c1=0^l ? => 0859b203 = 00000000  => False
	# c1=c'0 ? => 0859b203 = 0040f858  => False
	
	# @todo ??? Doing something wrong.. but what???

	

def cbc(k, iv, mArray):
	cArray = []
	lastInp = iv
	for m in mArray:
		inp = lastInp ^ m
		c = encrypt(k, inp)
		cArray.append(c)
		lastInp = c
	return cArray

	

def encrypt(k, i):
	return (i  + k )


def hexStrToInt(s):
	return int(s, 16)

def intToHexStr(i):
	return hex(i)[2:].zfill(8)


main()

================================================
FILE: week2-problemset/question9.py
================================================
# Stanford University
# Cryptography I
# https://www.coursera.org/course/crypto

# Week 2
# Question 9
# Let R:={0,1}4 and consider the following PRF F:R5xR->R defined as follows:

# F(k,x):= t=k[0] for i=1 to 4 doif (x[i-1]==1) t=t xor k[i] output t 

# That is, the key is k=(k[0],k[1],k[2],k[3],k[4]) in R5 and the function at, for example, 0101 is defined as F(k,0101)=k[0] xor k[2] xor k[4]. 

# For a random key k unknown to you, you learn that 
# F(k,0110)=0011  and  F(k,0101)=1010  and  F(k,1110)=0110 . 
# What is the value of F(k,1101)?    Note that since you are able to predict the function at a new point, this PRF is insecure.



import sys
import numpy
from operator import methodcaller


def main():
	k5 = [
		'0011', # 0
		'0101', # 1 
		'0000', # 2
		'0000', # 3
		'0000'  # 4
	]

	
	

	xTest = [
		['0110','0011'], # given
		['0101','1010'], # given
		['1110','0110'], # given
		['1101','????']  # target

	]

	print "xors applied"
	for test in xTest:
		fExplained(test[0], test[1])

	print "\n\nxors calculated"
	for test in xTest:
		f(k5, test[0], test[1])

	print "\n\n deduction:"
	print "\n1. F('0110') xor F('0101') xor F('1110') => 0011 xor 1010 xor 0110"
	print "(k[0] xor k[2] xor k[3]) xor (k[0] xor k[2] xor k[4]) xor (k[0] xor k[1] xor k[2] xor k[3]) => 1111"
	print "(k[0] xor k[1] xor k[2] xor k[4]) => 1111"
	

def fExplained(x, out):
	fstr = "k[0]"
	for i in range (1,5):
		if(int(x[i -1]) == 1):
			fstr =  fstr + ' xor k['+str(i)+"]\t"
		else:
			fstr = fstr + "\t\t\t"

	print x + " => " + fstr + " => \t" + out + " == " + str(binStrToInt(out))
	
def f(k, x, test):
	res = binStrToInt(k[0])
	for i in range (1,5):
		if(int(x[i - 1]) == 1):
			res = res ^ binStrToInt(k[i])
		
	print x + " => " + intToBinStr(res) + " => " + test



def binStrToInt(s):
	try:
		return int(s, 2)
	except ValueError:
		return s
	

def intToBinStr(i):
	return bin(i)[2:].zfill(4)


main()

================================================
FILE: week3-problemset/programming_assignment.py
================================================
# Question 1
# Suppose a web site hosts large video file F that anyone can download. 
# Browsers who download the file need to make sure the file is authentic before displaying the content to the user. 
# One approach is to have the web site hash the contents of F using a collision resistant hash and then distribute the resulting short hash value h=H(F) to users via some authenticated channel (later on we will use digital signatures for this). 
# Browsers would download the entire file F, check that H(F) is equal to the authentic hash value h and if so, display the video to the user. 

# Unfortunately, this means that the video will only begin playing after the *entire* file F has been downloaded.
# Our goal in this project is to build a file authentication system that lets browsers authenticate and play video chunks as they are downloaded without having to wait for the entire file. 

# Instead of computing a hash of the entire file, the web site breaks the file into 1KB blocks (1024 bytes). It computes the hash of the last block and appends the value to the second to last block. 
# It then computes the hash of this augmented second to last block and appends the resulting hash to the third block from the end. This process continues from the last block to the first as in the following diagram: 
# (https://d396qusza40orc.cloudfront.net/crypto/images/pp3-fig.jpg)[hashing process]
# The final hash value h0 - a hash of the first block with its appended hash - is distributed to users via the authenticated channel as above. 

# Now, a browser downloads the file F one block at a time, where each block includes the appended hash value from the diagram above. 
# When the first block (B0 || h1) is received the browser checks that H(B0 || h1) is equal to h0 and if so it begins playing the first video block. 
# When the second block (B1 || h2) is received the browser checks that H(B1 || h2) is equal to h1 and if so it plays this second block. This process continues until the very last block. 
# This way each block is authenticated and played as it is received and there is no need to wait until the entire file is downloaded. 

# It is not difficult to argue that if the hash function H is collision resistant then an attacker cannot modify any of the video blocks without being detected by the browser. 
# Indeed, since h0=H(B0 || h1) an attacker cannot find a pair (B`0,h`1)!=(B0,h1) such that h0=H(B0 || h1) since this would break collision resistance of H. 
# Therefore after the first hash check the browser is convinced that both B0 and h1 are authentic.
# Exactly the same argument proves that after the second hash check the browser is convinced that both B1 and h2 are authentic, and so on for the remaining blocks. 

# In this project we will be using SHA256 as the hash function. For an implementation of SHA256 use an existing crypto library such as PyCrypto (Python), Crypto++ (C++), or any other. 
# When appending the hash value to each block, please append it as binary data, that is, as 32 unencoded bytes (which is 256 bits). 
# If the file size is not a multiple of 1KB then the very last block will be shorter than 1KB, but all other blocks will be exactly 1KB. 

# Your task is to write code to compute the hash h0 of a given file F and to verify blocks of F as they are received by the client. In the box below please enter the (hex encoded) hash h0 for this video file.  (https://class.coursera.org/crypto-013/lecture/download.mp4?lecture_id=27)

# You can check your code by using it to hash a different file. In particular, the hex encoded h0 for this video (https://class.coursera.org/crypto-013/lecture/download.mp4?lecture_id=28) file is:
# 03c08f4ee0b576fe319338139c045c89c3e8e9409633bea29442e21425006ea8

import sys
import os

from Crypto.Hash import SHA256

def main():
	block_size = 1024 #bytes
	# Has to save the files, because they are behind coursera login
	file_target = "files/target.mp4"
	hash_target = ""

	file_check = "files/check.mp4"
	hash_check = "03c08f4ee0b576fe319338139c045c89c3e8e9409633bea29442e21425006ea8"


	h0_check = calculate_hash(file_check, block_size)
	h0_check_hex = h0_check.encode('hex')
	print "calculated h0 for",file_check,":",h0_check_hex," == ",hash_check,"? ",hash_check==h0_check_hex

	h0_target = calculate_hash(file_target, block_size)
	h0_target_hex = h0_target.encode('hex')
	print "calculated h0 for",file_target,":",h0_target_hex

	# Output:
	# Opening file: files/check.mp4  ;  16927313 bytes; 
	# calculated h0 for files/check.mp4 : 03c08f4ee0b576fe319338139c045c89c3e8e9409633bea29442e21425006ea8  ==  03c08f4ee0b576fe319338139c045c89c3e8e9409633bea29442e21425006ea8 ?  True
	# Opening file: files/target.mp4  ;  12494779 bytes; 
	# calculated h0 for files/target.mp4 : 5b96aece304a1422224f9a41b228416028f9ba26b0d1058f400200f06a589949



def calculate_hash(file_path, block_size):
	# Get file size in bytes
	file_size = os.path.getsize(file_path)
	# The last block size 
	last_block_size = file_size % block_size

	
	print "Opening file:",file_path, " ; ",file_size,"bytes; "
	fp = open(file_path, 'rb')

	last_hash = ''
	# read the chuncks
	for chunk in read_reversed_chunks(fp, file_size, last_block_size, block_size):
		# SHA-256 obj
		sha256 = SHA256.new()
		sha256.update(chunk)
		if(last_hash):
			sha256.update(last_hash)
		last_hash = sha256.digest()
	fp.close()

	# Return the last hash (h0)
	return last_hash


def read_reversed_chunks(file_object, file_size, last_chuck_size, chunk_size):
	iter = 0
	last_pos = file_size
	while last_pos>0:
		size = chunk_size
		if(iter == 0):
			size = last_chuck_size

		#print "read from",last_pos - size,"to",last_pos
		file_object.seek(last_pos - size)
		data = file_object.read(chunk_size)
		if not data:
			break

		iter = iter + 1
		last_pos -= size
		yield data

main()

================================================
FILE: week3-problemset/question8.py
================================================
# Question 8
# In this question and the next, you are asked to find collisions on two compression functions:
# f1(x,y)=AES(y,x) xor y,  and
# f2(x,y)=AES(x,x) xor y,
# where AES(x,y) is the AES-128 encryption of y under key x. 

# We provide an AES function for you to play with. The function takes as input a key k and an x value and outputs AES(k,x) once you press the "encrypt" button. 
# It takes as input a key k and a y value and outputs AES-1(k,y) once you press the "decrypt" button. All three values k,x,y are assumed to be hex values (i.e. using only characters 0-9 and a-f) and the function zero-pads them as needed. 

# Your goal is to find four distinct pairs (x1,y1),  (x2,y2),  (x3,y3),  (x4,y4) such that f1(x1,y1)=f1(x2,y2) and f2(x3,y3)=f2(x4,y4). In other words, the first two pairs are a collision for f1 and the last two pairs are a collision for f2. Once you find all four pairs, please enter them below and check your answer using the "check" button.
# Note for those using the NoScript browser extension: for the buttons to function correctly please allow Javascript from class.coursera.org and cloudfront.net to run in your browser. Note also that the "save answers" button does not function for this question and the next.


import sys
from Crypto.Cipher import AES


# Please find (x1,y1), (x2,y2) such that f1(x1,y1)=f1(x2,y2).
# => AES(y1,x1) xor y1 = AES(y2,x2) xor y2
# Unsing E for encrypt, D for decrypt:
# => E(y1,x1) xor y1 = E(y2,x2) xor y2

# Finding a flaw in AES seemed a bit too extreme for a homework assignment, so I assume message x2 is f1(x1,y1), decrypted by y2
# => E(y1,x1) xor y1 = E(y2, D(y2, E(y1,x1) xor y1) ) xor y2

# This results into
# => E(y1,x1) xor y1 = E(y1,x1) xor y1 xor y2

# x1, y1 can be anything
# y2 = 0^n, since any string of bits xor 0 is itself. 
# x2 = D(y2, E(y1,x1) xor y1)

def main():
	x1 = "12345678123456781234567812345678".decode('hex') # arbitrary 128bit string
	y1 = "90abcdef90abcdef90abcdef90abcdef".decode('hex') # arbitrary 128bit string
	y2 = "00000000000000000000000000000000".decode('hex') # 0^n string

	print "x1:",x1.encode('hex')
	print "y1:",y1.encode('hex')
	print "y2:",y2.encode('hex')

	m1 = f1(x1, y1)
	print "\nf1(x1,y1) = ",m1.encode('hex')
	
	x2 = find_x2(m1, y2)
	print "\nD(y2, f1(x1,y1)) => x2:",x2.encode('hex')

	m2 = f1(x2, y2)
	print "\n\ncheck: f1(x2,y2) =",m2.encode('hex'),"\n==",m1.encode('hex'),"? ",m1==m2

	print "\n"

	# Output:
	# x1: 12345678123456781234567812345678
	# y1: 90abcdef90abcdef90abcdef90abcdef
	# y2: 00000000000000000000000000000000

	# f1(x1,y1) =  115065c6363f7d143c4dfee65894bf7d

	# D(y2, f1(x1,y1)) => x2: 8b701b44711cc43b4f756d7977d7315c

	# check: f1(x2,y2) = 115065c6363f7d143c4dfee65894bf7d 
	# == 115065c6363f7d143c4dfee65894bf7d ?  True


def f1(x, y):
	return strxor(AES.new(y,AES.MODE_ECB).encrypt(x), y)

def find_x2(m, y):
	return AES.new(y,AES.MODE_ECB).decrypt(m)



# xor two strings of different lengths
def strxor(a, b):     
    if len(a) > len(b):
        return "".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a[:len(b)], b)])
    else:
        return "".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a, b[:len(a)])])


main()

================================================
FILE: week3-problemset/question9.py
================================================
# Question 8
# In this question and the next, you are asked to find collisions on two compression functions:
# f1(x,y)=AES(y,x) xor y,  and
# f2(x,y)=AES(x,x) xor y,
# where AES(x,y) is the AES-128 encryption of y under key x. 

# We provide an AES function for you to play with. The function takes as input a key k and an x value and outputs AES(k,x) once you press the "encrypt" button. 
# It takes as input a key k and a y value and outputs AES-1(k,y) once you press the "decrypt" button. All three values k,x,y are assumed to be hex values (i.e. using only characters 0-9 and a-f) and the function zero-pads them as needed. 

# Your goal is to find four distinct pairs (x1,y1),  (x2,y2),  (x3,y3),  (x4,y4) such that f1(x1,y1)=f1(x2,y2) and f2(x3,y3)=f2(x4,y4). 
# In other words, the first two pairs are a collision for f1 and the last two pairs are a collision for f2. 



import sys
from Crypto.Cipher import AES


# Please find (x3,y3), (x4,y4) such that f2(x3,y3)=f2(x4,y4).
# => AES(x3,x3) xor y3 = AES(x4,x4) xor y4
# Since the 'y' is independant of the Encryption, you can choose any y that E(x,x) = y
# => E(x3,x3) xor E(x3,x3) = E(x4,x4) xor E(x4,x4)

# Since any value xor itself = 0
# => 0 = 0



def main():
	x3 = "12345678123456781234567812345678".decode('hex') # arbitrary 128bit string
	x4 = "90abcdef90abcdef90abcdef90abcdef".decode('hex') # arbitrary 128bit string
	
	print "x3:",x3.encode('hex')
	print "x4:",x4.encode('hex')
	

	y3 = find_y(x3)
	print "\nE(x3,x3) = y3 = ",y3.encode('hex')

	y4 = find_y(x4)
	print "\nE(x4,x4) = y4 = ",y4.encode('hex')
	
	
	m3 = f2(x3, y3)
	print "\n\ncheck: f2(x3,y3) =",m3.encode('hex')
	m4 = f2(x4, y4)
	print "\ncheck: f2(x4,y4) =",m4.encode('hex')
	print "\nm3 == m4 ? ",m3==m4

	print "\n"

	# Output:
	# x3: 12345678123456781234567812345678
	# x4: 90abcdef90abcdef90abcdef90abcdef

	# E(x3,x3) = y3 =  d7eeee18c420faf0dc7db5ca73a2b817

	# E(x4,x4) = y4 =  ac6f20842f239c423ff5e89c870cca75

	# check: f2(x3,y3) = 00000000000000000000000000000000

	# check: f2(x4,y4) = 00000000000000000000000000000000

	# m3 == m4 ?  True


def f2(x, y):
	return strxor(AES.new(x,AES.MODE_ECB).encrypt(x), y)

def find_y(x):
	return AES.new(x,AES.MODE_ECB).encrypt(x)



# xor two strings of different lengths
def strxor(a, b):     
    if len(a) > len(b):
        return "".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a[:len(b)], b)])
    else:
        return "".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a, b[:len(a)])])


main()

================================================
FILE: week4-problemset/programming_assignment.py
================================================
# Question 1
# In this project you will experiment with a padding oracle attack against a toy web site hosted at crypto-class.appspot.com. 
# Padding oracle vulnerabilities affect a wide variety of products, including secure tokens. 
# This project will show how they can be exploited. We discussed CBC padding oracle attacks in Lecture 7.6, but if you want to read more about them, please see Vaudenay's paper. 
#
# Now to business. Suppose an attacker wishes to steal secret information from our target web site crypto-class.appspot.com. 
# The attacker suspects that the web site embeds encrypted customer data in URL parameters such as this:
# http://crypto-class.appspot.com/po?er=f20bdba6ff29eed7b046d1df9fb7000058b1ffb4210a580f748b4ac714c001bd4a61044426fb515dad3f21f18aa577c0bdf302936266926ff37dbf7035d5eeb4
# That is, when customer Alice interacts with the site, the site embeds a URL like this in web pages it sends to Alice. 
# The attacker intercepts the URL listed above and guesses that the ciphertext following the "po?er=" is a hex encoded AES CBC encryption 
# with a random IV of some secret data about Alice's session. 
#
# After some experimentation the attacker discovers that the web site is vulnerable to a CBC padding oracle attack. 
# In particular, when a decrypted CBC ciphertext ends in an invalid pad the web server returns a 403 error code (forbidden request). 
# When the CBC padding is valid, but the message is malformed, the web server returns a 404 error code (URL not found). 
#
# Armed with this information your goal is to decrypt the ciphertext listed above. To do so you can send arbitrary HTTP requests to the web site of the form
# http://crypto-class.appspot.com/po?er="your ciphertext here"
# and observe the resulting error code. The padding oracle will let you decrypt the given ciphertext one byte at a time. 
# To decrypt a single byte you will need to send up to 256 HTTP requests to the site. Keep in mind that the first ciphertext block is the random IV. 
# The decrypted message is ASCII encoded. 
#
# To get you started here is a short Python (http://spark-university.s3.amazonaws.com/stanford-crypto/projects/pp4-attack_py.html) script that sends a ciphertext supplied on the command line to the site and prints the resulting error code. 
# You can extend this script (or write one from scratch) to implement the padding oracle attack. Once you decrypt the given ciphertext, please enter the decrypted message in the box below. 

# This project shows that when using encryption you must prevent padding oracle attacks by either using encrypt-then-MAC as in EAX or GCM, 
# or if you must use MAC-then-encrypt then ensure that the site treats padding errors the same way it treats MAC errors.

import sys
import os
import urllib2
from operator import methodcaller



from Crypto.Hash import SHA256


#--------------------------------------------------------------
# padding oracle
#--------------------------------------------------------------
class PaddingOracle(object):
	def __init__(self):
		self.targetURL = 'http://crypto-class.appspot.com/po?er='

	def query(self, q):
		target = self.targetURL + urllib2.quote(q)    # Create query URL
		req = urllib2.Request(target)         # Send HTTP request to server
		try:
			f = urllib2.urlopen(req)          # Wait for response
		except urllib2.HTTPError, e:          
			return e.code == 404

#--------------------------------------------------------------
# Smart Char Guesser
#--------------------------------------------------------------
class CharGuesser(object):
	def __init__(self):
		self.letterFrequencyOrder = ['e', 't', 'a', 'o', 'i', 'n', 's', 'h', 'r', 'd', 'l', 'c', 'u', 'm', 'w', 'f', 'g', 'y', 'p', 'b', 'v', 'k', 'j', 'x', 'q', 'z']
		self.firstLetterFrequencyOrder = ['T', 'A', 'S', 'H', 'W', 'I', 'O', 'B', 'M', 'F', 'C', 'L', 'D', 'P', 'N', 'E', 'G', 'R', 'Y', 'U', 'V', 'J', 'K', 'Q', 'Z', 'X']
		self.otherCharsOrder = [' ','0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', ',', '!', '?', '&']
		self.commonBigramsOrder = ['th', 'en', 'ng', 'he', 'ed', 'of', 'in', 'to', 'al', 'er', 'it', 'de', 'an', 'ou', 'se', 're', 'ea', 'le', 'nd', 'hi', 'sa', 'at', 'is', 'si', 'on', 'or', 'ar', 'nt', 'ti', 've', 'ha', 'as', 'ra', 'es', 'te', 'ld', 'st', 'et', 'ur']
		self.charsUsed = []


	def guessPrecedingChar(self, currentChar=None):
		if(currentChar):
			# Check common bigrams
			for bigram in self.commonBigramsOrder:
				if bigram[1] == currentChar.lower():
					if not self.checkUsed(bigram[0]):
						return self.setUsed(bigram[0])
					if not self.checkUsed(bigram[0].upper()):
						return self.setUsed(bigram[0].upper())

		# Else check chars in order of probability
		for char in self.letterFrequencyOrder:
			if not self.checkUsed(char):
				return self.setUsed(char)

		# Else check uppercase chars in order of probability of first chars
		for char in self.firstLetterFrequencyOrder:
			if not self.checkUsed(char):
				return self.setUsed(char)

		# Else check common chars, puntcuation, numbers, etc
		for char in self.otherCharsOrder:
			if not self.checkUsed(char):
				return self.setUsed(char)
				
		# Else loop all ASCII from 0-255
		for char in map(lambda x: chr(x), range(0,256)):
			if not self.checkUsed(char):
				return self.setUsed(char)	
		
		# When all else fails?
		return None

	def checkUsed(self,char):
		return char in self.charsUsed

	def setUsed(self,char):
		self.charsUsed.append(char)
		return char



def main():
	cryptoText = "f20bdba6ff29eed7b046d1df9fb7000058b1ffb4210a580f748b4ac714c001bd4a61044426fb515dad3f21f18aa577c0bdf302936266926ff37dbf7035d5eeb1".decode('hex')
	blockSize = 16 # 128 bit AES
	cryptoBlocks  = splitCount(cryptoText, blockSize) # x 16 byte blocks, where block 0 is the IV
	messageBlocks = splitCount(("00" * blockSize * (len(cryptoBlocks)-1)).decode('hex'),  blockSize) # init message blocks
	## iv = cryptoBlocks.pop(0) # First item is IV in CBC crypto
	lastChar = None



	po = PaddingOracle()

	# m0 corresponds to c0, which has index 1 in cryptoBlocks. IV has index 0 in cryptoBlocks. 
	# We start with the last block
	for blockNum in reversed(range(0,len(cryptoBlocks))):


		# loop all 16 positions, last to first
		for position in reversed(range(0, blockSize)):
			paddingNum = blockSize - position
			# reinit the crypto block per position
			cryptoSourceBlock = cryptoBlocks[blockNum]
			
			# set the positions with padding XOR known char for the positions we already know (eg when padding is 2 => set position 16 to val XOR 02 xor c[16])
			for pl in range(1, paddingNum): 
				plPos = position + pl
				messageValue = messageBlocks[blockNum][plPos]
				cryptoSourceBlock[plPos] ^= messageValue ^ paddingNum

			# init a ASCII char guesser for this position
			charGuesser = CharGuesser()

			counter = 0
			while counter < 10:
				# reinit the crypto block per guess, with padding on correct pos
				cryptoSourceBlock_bak = cryptoSourceBlock
				guess = charGuesser.guessPrecedingChar(lastChar)

				# Safeguard
				if(guess == None):
					print "Nothing found"
					break;

				print guess
				print paddingNum
				print cryptoSourceBlock.encode('hex')

				# XOR the cryptoblock postion with the guess and the paddingnum
				cryptoSourceBlock[position] ^= ord(guess) ^ paddingNum
				cryptoGuess = buildCryptoString(cryptoText, (blockNum * blockSize), cryptoSourceBlock)
				if(po.query(cryptoGuess)):
					print "found char ", guess
					messageBlocks[blockNum][position] = guess
					break;

				counter += 1



			
			# print cryptoSourceBlock[blockSize - position].encode('hex') 
			# cryptoSourceBlock[position] ^= guess ^ position




	
	# po = PaddingOracle()
	# print po.query() 
	# lg = CharGuesser()
	# print lg.guessPrecedingChar('n')
	# print lg.guessPrecedingChar('n')
	# print lg.guessPrecedingChar('n')
	# print lg.guessPrecedingChar()

def splitCount(s, count):
     return [''.join(x) for x in zip(*[list(s[z::count]) for z in range(count)])]

def buildCryptoString(cryptoText, position, newBlock):
	return cryptoText[position]


main()

================================================
FILE: week4-problemset/question1.py
================================================
# Question 1
# An attacker intercepts the following ciphertext (hex encoded): 

#    20814804c1767293b99f1d9cab3bc3e7 ac1e37bfb15599e5f40eef805488281d 

# He knows that the plaintext is the ASCII encoding of the message "Pay Bob 100$" (excluding the quotes). 
# He also knows that the cipher used is CBC encryption with a random IV using AES as the underlying block cipher. 
# Show that the attacker can change the ciphertext so that it will decrypt to "Pay Bob 500$". What is the resulting ciphertext (hex encoded)? 
# This shows that CBC provides no integrity.

import sys

def main():
	# input
	cypherText = "20814804c1767293b99f1d9cab3bc3e7 ac1e37bfb15599e5f40eef805488281d".split(' ')
	
	# set the CBC parts. The first part is the IV
	cypherTextIV = cypherText[0].decode('hex')
	cypherTextC0 = cypherText[1].decode('hex')
	
	# define plaintexts
	plainText = "Pay Bob 100$"
	plainTextTarget = "Pay Bob 500$"

	# define paddings
	paddingNum1 = str(len(cypherTextC0) - len(plainText))
	padding1 = "".join([paddingNum1] * int(paddingNum1))

	paddingNum2 = str(len(cypherTextC0) - len(plainTextTarget))
	padding2 = "".join([paddingNum2] * int(paddingNum2))

	# append to plaintext the paddings
	plainText += padding1
	plainTextTarget += padding2

	# XOR the plaintext to determine the value to XOR with
	xorredPlainText = strxor(plainText, plainTextTarget)

	# Since the decription of c[0] is XORed with IV to retrieve the plaintext xor the IV with the desired mutation
	newIV = strxor(xorredPlainText, cypherTextIV)

	# new CBC 
	print "New CBC\n",newIV.encode('hex'), cypherText[1]

	# Output:
	# New CBC
	# 20814804c1767293bd9f1d9cab3bc3e7 ac1e37bfb15599e5f40eef805488281d


# xor two strings of different lengths
def strxor(a, b):     
    if len(a) > len(b):
        return "".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a[:len(b)], b)])
    else:
        return "".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a, b[:len(a)])])


main()
Download .txt
gitextract_akths2on/

├── README.md
├── week1-problemset/
│   ├── programming_assignment.py
│   └── question7.py
├── week2-problemset/
│   ├── programming_assignment.py
│   ├── question1.py
│   ├── question2.py
│   ├── question4.py
│   ├── question5.py
│   └── question9.py
├── week3-problemset/
│   ├── programming_assignment.py
│   ├── question8.py
│   └── question9.py
└── week4-problemset/
    ├── programming_assignment.py
    └── question1.py
Download .txt
SYMBOL INDEX (53 symbols across 13 files)

FILE: week1-problemset/programming_assignment.py
  function main (line 16) | def main():
  function strxor (line 82) | def strxor(a, b):     # xor two strings of different lengths
  function isreadable (line 88) | def isreadable(str): # check readability (allow only alphanumeric chars ...
  function printCodePos (line 91) | def printCodePos(i, code, maxLen, filler): # output the guess in place o...

FILE: week1-problemset/question7.py
  function main (line 3) | def main():
  function xor_strings (line 12) | def xor_strings(strA, strB):

FILE: week2-problemset/programming_assignment.py
  function main (line 22) | def main():
  function ctrDecrypt (line 61) | def ctrDecrypt(key, cypherText, blockSize):
  function ctrDecrypt1 (line 70) | def ctrDecrypt1(key, cypherText, blockSize):
  function ctrDecrypt2 (line 82) | def ctrDecrypt2(key, cypherText, blockSize):
  function cbcDecrypt (line 106) | def cbcDecrypt(key, cypherText, blockSize):
  function cbcDecrypt1 (line 115) | def cbcDecrypt1(key, cypherText, blockSize):
  function cbcDecrypt2 (line 127) | def cbcDecrypt2(key, cypherText, blockSize):
  function strxor (line 150) | def strxor(a, b):

FILE: week2-problemset/question1.py
  function main (line 20) | def main():

FILE: week2-problemset/question2.py
  function main (line 14) | def main():

FILE: week2-problemset/question4.py
  function main (line 28) | def main():
  function hexStrToInt (line 67) | def hexStrToInt(s):
  function intToHexStr (line 70) | def intToHexStr(i):

FILE: week2-problemset/question5.py
  function main (line 28) | def main():
  function cbc (line 79) | def cbc(k, iv, mArray):
  function encrypt (line 91) | def encrypt(k, i):
  function hexStrToInt (line 95) | def hexStrToInt(s):
  function intToHexStr (line 98) | def intToHexStr(i):

FILE: week2-problemset/question9.py
  function main (line 24) | def main():
  function fExplained (line 58) | def fExplained(x, out):
  function f (line 68) | def f(k, x, test):
  function binStrToInt (line 78) | def binStrToInt(s):
  function intToBinStr (line 85) | def intToBinStr(i):

FILE: week3-problemset/programming_assignment.py
  function main (line 39) | def main():
  function calculate_hash (line 65) | def calculate_hash(file_path, block_size):
  function read_reversed_chunks (line 90) | def read_reversed_chunks(file_object, file_size, last_chuck_size, chunk_...

FILE: week3-problemset/question8.py
  function main (line 33) | def main():
  function f1 (line 66) | def f1(x, y):
  function find_x2 (line 69) | def find_x2(m, y):
  function strxor (line 75) | def strxor(a, b):

FILE: week3-problemset/question9.py
  function main (line 29) | def main():
  function f2 (line 67) | def f2(x, y):
  function find_y (line 70) | def find_y(x):
  function strxor (line 76) | def strxor(a, b):

FILE: week4-problemset/programming_assignment.py
  class PaddingOracle (line 42) | class PaddingOracle(object):
    method __init__ (line 43) | def __init__(self):
    method query (line 46) | def query(self, q):
  class CharGuesser (line 57) | class CharGuesser(object):
    method __init__ (line 58) | def __init__(self):
    method guessPrecedingChar (line 66) | def guessPrecedingChar(self, currentChar=None):
    method checkUsed (line 99) | def checkUsed(self,char):
    method setUsed (line 102) | def setUsed(self,char):
  function main (line 108) | def main():
  function splitCount (line 183) | def splitCount(s, count):
  function buildCryptoString (line 186) | def buildCryptoString(cryptoText, position, newBlock):

FILE: week4-problemset/question1.py
  function main (line 13) | def main():
  function strxor (line 51) | def strxor(a, b):
Condensed preview — 14 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (51K chars).
[
  {
    "path": "README.md",
    "chars": 109,
    "preview": "coursera-cryptography1\n======================\n\nAssignments for Coursera's Cryptography I course by Dan Boneh\n"
  },
  {
    "path": "week1-problemset/programming_assignment.py",
    "chars": 8226,
    "preview": "# Stanford University\n# Cryptography I\n# https://www.coursera.org/course/crypto\n\n# Week 1\n# Question 1\n# Many Time Pad \n"
  },
  {
    "path": "week1-problemset/question7.py",
    "chars": 353,
    "preview": "import sys\n\ndef main():\n\ttext1 = \"attack at dawn\"\n\tencoded1 = \"6c73d5240a948c86981bc294814d\".decode(\"hex\")\n\tkey = xor_st"
  },
  {
    "path": "week2-problemset/programming_assignment.py",
    "chars": 6466,
    "preview": "# Stanford University\n# Cryptography I\n# https://www.coursera.org/course/crypto\n\n# Week 2\n# Question 1-4\n\n\n# In this pro"
  },
  {
    "path": "week2-problemset/question1.py",
    "chars": 1238,
    "preview": "# Stanford University\n# Cryptography I\n# https://www.coursera.org/course/crypto\n\n# Week 2\n# Question 1\n# Consider the fo"
  },
  {
    "path": "week2-problemset/question2.py",
    "chars": 2131,
    "preview": "# Stanford University\n# Cryptography I\n# https://www.coursera.org/course/crypto\n\n# Week 2\n# Question 2\n# Suppose that us"
  },
  {
    "path": "week2-problemset/question4.py",
    "chars": 2966,
    "preview": "# Stanford University\n# Cryptography I\n# https://www.coursera.org/course/crypto\n\n# Week 2\n# Question 4\n# Recall that the"
  },
  {
    "path": "week2-problemset/question5.py",
    "chars": 2875,
    "preview": "# Stanford University\n# Cryptography I\n# https://www.coursera.org/course/crypto\n\n# Week 2\n# Question 5\n# Nonce-based CBC"
  },
  {
    "path": "week2-problemset/question9.py",
    "chars": 1906,
    "preview": "# Stanford University\n# Cryptography I\n# https://www.coursera.org/course/crypto\n\n# Week 2\n# Question 9\n# Let R:={0,1}4 a"
  },
  {
    "path": "week3-problemset/programming_assignment.py",
    "chars": 5823,
    "preview": "# Question 1\n# Suppose a web site hosts large video file F that anyone can download. \n# Browsers who download the file n"
  },
  {
    "path": "week3-problemset/question8.py",
    "chars": 3178,
    "preview": "# Question 8\n# In this question and the next, you are asked to find collisions on two compression functions:\n# f1(x,y)=A"
  },
  {
    "path": "week3-problemset/question9.py",
    "chars": 2483,
    "preview": "# Question 8\n# In this question and the next, you are asked to find collisions on two compression functions:\n# f1(x,y)=A"
  },
  {
    "path": "week4-problemset/programming_assignment.py",
    "chars": 8058,
    "preview": "# Question 1\n# In this project you will experiment with a padding oracle attack against a toy web site hosted at crypto-"
  },
  {
    "path": "week4-problemset/question1.py",
    "chars": 1942,
    "preview": "# Question 1\n# An attacker intercepts the following ciphertext (hex encoded): \n\n#    20814804c1767293b99f1d9cab3bc3e7 ac"
  }
]

About this extraction

This page contains the full source code of the TomLous/coursera-cryptography1 GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 14 files (46.6 KB), approximately 16.5k tokens, and a symbol index with 53 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!