[
  {
    "path": "README.md",
    "content": "coursera-cryptography1\n======================\n\nAssignments for Coursera's Cryptography I course by Dan Boneh\n"
  },
  {
    "path": "week1-problemset/programming_assignment.py",
    "content": "# Stanford University\n# Cryptography I\n# https://www.coursera.org/course/crypto\n\n# Week 1\n# Question 1\n# Many Time Pad \n\n# 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. \n# Hint: XOR the ciphertexts together, and consider what happens when a space is XORed with a character in [a-zA-Z]. \n\nimport sys\nfrom operator import methodcaller\nimport re\n\ndef main():\n\tcypherTexts = []\n\t# cyphertext 1 (0)\n\tcypherTexts.append(\"315c4eeaa8b5f8aaf9174145bf43e1784b8fa00dc71d885a804e5ee9fa40b16349c146fb778cdf2d3aff021dfff5b403b510d0d0455468aeb98622b137dae857553ccd8883a7bc37520e06e515d22c954eba5025b8cc57ee59418ce7dc6bc41556bdb36bbca3e8774301fbcaa3b83b220809560987815f65286764703de0f3d524400a19b159610b11ef3e\")\n\t# cyphertext 2 (1)\n\tcypherTexts.append(\"234c02ecbbfbafa3ed18510abd11fa724fcda2018a1a8342cf064bbde548b12b07df44ba7191d9606ef4081ffde5ad46a5069d9f7f543bedb9c861bf29c7e205132eda9382b0bc2c5c4b45f919cf3a9f1cb74151f6d551f4480c82b2cb24cc5b028aa76eb7b4ab24171ab3cdadb8356f\")\n\t# cyphertext 3 (2)\n\tcypherTexts.append(\"32510ba9a7b2bba9b8005d43a304b5714cc0bb0c8a34884dd91304b8ad40b62b07df44ba6e9d8a2368e51d04e0e7b207b70b9b8261112bacb6c866a232dfe257527dc29398f5f3251a0d47e503c66e935de81230b59b7afb5f41afa8d661cb\")\n\t# cyphertext 4 (3)\n\tcypherTexts.append(\"32510ba9aab2a8a4fd06414fb517b5605cc0aa0dc91a8908c2064ba8ad5ea06a029056f47a8ad3306ef5021eafe1ac01a81197847a5c68a1b78769a37bc8f4575432c198ccb4ef63590256e305cd3a9544ee4160ead45aef520489e7da7d835402bca670bda8eb775200b8dabbba246b130f040d8ec6447e2c767f3d30ed81ea2e4c1404e1315a1010e7229be6636aaa\")\n\t# cyphertext 5 (4) \n\tcypherTexts.append(\"3f561ba9adb4b6ebec54424ba317b564418fac0dd35f8c08d31a1fe9e24fe56808c213f17c81d9607cee021dafe1e001b21ade877a5e68bea88d61b93ac5ee0d562e8e9582f5ef375f0a4ae20ed86e935de81230b59b73fb4302cd95d770c65b40aaa065f2a5e33a5a0bb5dcaba43722130f042f8ec85b7c2070\")\n\t# cyphertext 6 (5)\n\tcypherTexts.append(\"32510bfbacfbb9befd54415da243e1695ecabd58c519cd4bd2061bbde24eb76a19d84aba34d8de287be84d07e7e9a30ee714979c7e1123a8bd9822a33ecaf512472e8e8f8db3f9635c1949e640c621854eba0d79eccf52ff111284b4cc61d11902aebc66f2b2e436434eacc0aba938220b084800c2ca4e693522643573b2c4ce35050b0cf774201f0fe52ac9f26d71b6cf61a711cc229f77ace7aa88a2f19983122b11be87a59c355d25f8e4\")\n\t# cyphertext 7 (6)\n\tcypherTexts.append(\"32510bfbacfbb9befd54415da243e1695ecabd58c519cd4bd90f1fa6ea5ba47b01c909ba7696cf606ef40c04afe1ac0aa8148dd066592ded9f8774b529c7ea125d298e8883f5e9305f4b44f915cb2bd05af51373fd9b4af511039fa2d96f83414aaaf261bda2e97b170fb5cce2a53e675c154c0d9681596934777e2275b381ce2e40582afe67650b13e72287ff2270abcf73bb028932836fbdecfecee0a3b894473c1bbeb6b4913a536ce4f9b13f1efff71ea313c8661dd9a4ce\")\n\t# cyphertext 8 (7)\n\tcypherTexts.append(\"315c4eeaa8b5f8bffd11155ea506b56041c6a00c8a08854dd21a4bbde54ce56801d943ba708b8a3574f40c00fff9e00fa1439fd0654327a3bfc860b92f89ee04132ecb9298f5fd2d5e4b45e40ecc3b9d59e9417df7c95bba410e9aa2ca24c5474da2f276baa3ac325918b2daada43d6712150441c2e04f6565517f317da9d3\")\n\t# cyphertext 9 (8)\n\tcypherTexts.append(\"271946f9bbb2aeadec111841a81abc300ecaa01bd8069d5cc91005e9fe4aad6e04d513e96d99de2569bc5e50eeeca709b50a8a987f4264edb6896fb537d0a716132ddc938fb0f836480e06ed0fcd6e9759f40462f9cf57f4564186a2c1778f1543efa270bda5e933421cbe88a4a52222190f471e9bd15f652b653b7071aec59a2705081ffe72651d08f822c9ed6d76e48b63ab15d0208573a7eef027\")\n\t# cyphertext 10 (9)\n\tcypherTexts.append(\"466d06ece998b7a2fb1d464fed2ced7641ddaa3cc31c9941cf110abbf409ed39598005b3399ccfafb61d0315fca0a314be138a9f32503bedac8067f03adbf3575c3b8edc9ba7f537530541ab0f9f3cd04ff50d66f1d559ba520e89a2cb2a83\")\n\t# cyphertext target (10)\n\tcypherTexts.append(\"32510ba9babebbbefd001547a810e67149caee11d945cd7fc81a05e9f85aac650e9052ba6a8cd8257bf14d13e6f0a803b54fde9e77472dbff89d71b57bddef121336cb85ccb8f3315f4b52e301d16e9f52f904\")\n\t\n\t\n\t# convert all to ASCII\n\tcypherTextsDecoded = map(methodcaller(\"decode\", \"hex\"), cypherTexts)\n\n\t# chose two to XOR\n\n\t## This part of the program is interactive.\n\t## Keep guessing cribs and see how they might match in various XOR-ed cyphertexts (== XOR-ed plaintext) \n\t## Finally choose the longest, fully decrypted crib (6) and the target cypher (10)\n\t# /begin interactive\n\tcrib = \"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\"\n\txorTextNum1 = 6\n\txorTextNum2 = 10\n\t# /end interatcive\n\t\n\txoredText = strxor(cypherTextsDecoded[xorTextNum1], cypherTextsDecoded[xorTextNum2])\n\n\t# loop all individual positions of the XOR-ed crypto (plain) text\n\ttextLength = len(xoredText)\n\tfor i in range(textLength):\n\t\t\t# XOR the substring with the crib\n    \t\tsubstrXoredText = xoredText[i:]\n    \t\tcribDraggedText = strxor(substrXoredText,crib)\n\n    \t\t# do an estimated guess wether the text is readable, if so print the guess (in place)\n    \t\tif(isreadable(cribDraggedText)):\n\t\t\t\tprintCodePos(i, cribDraggedText, textLength, '.')\n    \t\t\n    \n    \tprint \"\\n\\nGuess key (when the crib starts lining up):\"\n    \tkey = strxor(cypherTextsDecoded[xorTextNum1], crib)\n    \tprint \"key: %s\"%key.encode('hex')\n\n\tprint \"\\n\\nDecrypt all messages using the key:\"\n    \tfor j, cypher in enumerate(cypherTextsDecoded) :\n    \t\tprint \"[%d] %s\" % (j, strxor(cypher, key))\n\n\n\n\t\n\t\ndef strxor(a, b):     # xor two strings of different lengths\n    if len(a) > len(b):\n        return \"\".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a[:len(b)], b)])\n    else:\n        return \"\".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a, b[:len(a)])])\n\ndef isreadable(str): # check readability (allow only alphanumeric chars and some punctiation)\n\treturn bool(re.search('^[a-zA-Z0-9\\., \\'\\\"\\-_\\:\\(\\)]+$', str))\n\ndef printCodePos(i, code, maxLen, filler): # output the guess in place of the message\n\tprefix =  filler*i\n\tln = len(code)\n\tpostfix = filler*(maxLen-i-ln)\n\tprint(\"%s%s%s\" % (prefix,code,postfix))\n    \t\n\nmain()\n\t\n## Output\n# The secret message is: When using a stream cipher, never use the key more than once\n# ..................................................................................C\n\n\n# Guess key (when the crib starts lining up):\n# key: 66396e89c9dbd8cc9874352acd6395102eafce78aa7fed28a07f6bc98d29c50b69b0339a19f8aa401a9c6d708f80c066c763fef0123148cdd8e802d05ba98777335daefcecd59c433a6b268b60bf4ef03c9a611098bb3e9a3161edc7b804a33522cfd202d2c68c57376edba8c2ca50027c61246ce2a12b0c4502175010c0a1ba4625786d911100797d8a47e98b0204c4ef06c867a950f11ac989dea88fd1dbf16748749ed4c6f45b384c9d96c4\n\n# Decrypt all messages using the key:\n# [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\n# [1] Euler would probably enjoy that now his theorem becomes a corner stone of crypto - Annonymous on Euler's theorem\n# [2] The nice thing about Keeyloq is now we cryptographers can drive a lot of fancy cars - Dan Boneh\n# [3] The ciphertext produced by a weak encryption algorithm looks as good as ciphertext produced by a strong encryption algorithm - Philip Zimmermann\n# [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\n# [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\n# [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\n# [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\n# [8] A (private-key)  encryption scheme states 3 algorithms, namely a procedure for generating keys, a procedure for encrypting, and a procedure for decrypting.?\n# [9]  The Concise OxfordDictionary (2006) defines crypto as the art of  writing o r solving codes. \n# [10] The secret message is: When using a stream cipher, never use the key more than once\n\n"
  },
  {
    "path": "week1-problemset/question7.py",
    "content": "import sys\n\ndef main():\n\ttext1 = \"attack at dawn\"\n\tencoded1 = \"6c73d5240a948c86981bc294814d\".decode(\"hex\")\n\tkey = xor_strings(text1, encoded1)\n\n\ttext2 = \"attack at dusk\"\n\tencoded2 = xor_strings(text2, key)\n\tprint encoded2.encode(\"hex\")\n\ndef xor_strings(strA, strB):\n\treturn \"\".join(chr(ord(chrA) ^ ord(chrB)) for (chrA, chrB) in zip(strA, strB))\n\nmain()"
  },
  {
    "path": "week2-problemset/programming_assignment.py",
    "content": "# 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 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). \n# 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. \n\n# 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. \n\nimport sys\nfrom operator import methodcaller\nimport re\nimport numpy\nfrom Crypto.Cipher import AES\nfrom Crypto.Util import Counter\nfrom Crypto import Random\n\ndef main():\n\tblockSize = 16 # 16-byte encryption\n\tq1 = cbcDecrypt(\"140b41b22a29beb4061bda66b6747e14\", \"4ca00ff4c898d61e1edbf1800618fb2828a226d160dad07883d04e008a7897ee2e4b7465d5290d0c0e6c6822236e1daafb94ffe0c5da05d9476be028ad7c1d81\", blockSize)\t\n\tq2 = cbcDecrypt(\"140b41b22a29beb4061bda66b6747e14\", \"5b68629feb8606f9a6667670b75b38a5b4832d0f26e1ab7da33249de7d4afc48e713ac646ace36e872ad5fb8a512428a6e21364b0c374df45503473c5242a253\", blockSize)\t\n\tq3 = ctrDecrypt(\"36f18357be4dbd77f050515c73fcf9f2\", \"69dda8455c7dd4254bf353b773304eec0ec7702330098ce7f7520d1cbbb20fc388d1b0adb5054dbd7370849dbf0b88d393f252e764f1f5f7ad97ef79d59ce29f5f51eeca32eabedd9afa9329\", blockSize)\t\n\tq4 = ctrDecrypt(\"36f18357be4dbd77f050515c73fcf9f2\", \"770b80259ec33beb2561358a9f2dc617e46218c0a53cbeca695ae45faa8952aa0e311bde9d4e01726d3184c34451\", blockSize)\t\n\t\n\tprint \"\\n\\nAnswers:\"\n\tprint \"Q1. \",q1\n\tprint \"Q2. \",q2\n\tprint \"Q3. \",q3\n\tprint \"Q4. \",q4\n\n\t#Result\n\t# CBC decryption of key/cypher 140b41b22a29beb4061bda66b6747e14  /  4ca00ff4c898d61e1edbf1800618fb2828a226d160dad07883d04e008a7897ee2e4b7465d5290d0c0e6c6822236e1daafb94ffe0c5da05d9476be028ad7c1d81\n\t# 1:  Basic CBC mode encryption needs padding.\n\t# 2:  Basic CBC mode encryption needs padding.\n\n\t# CBC decryption of key/cypher 140b41b22a29beb4061bda66b6747e14  /  5b68629feb8606f9a6667670b75b38a5b4832d0f26e1ab7da33249de7d4afc48e713ac646ace36e872ad5fb8a512428a6e21364b0c374df45503473c5242a253\n\t# 1:  Our implementation uses rand. IV\n\t# 2:  Our implementation uses rand. IV\n\n\t# CTR decryption of key/cypher 36f18357be4dbd77f050515c73fcf9f2  /  69dda8455c7dd4254bf353b773304eec0ec7702330098ce7f7520d1cbbb20fc388d1b0adb5054dbd7370849dbf0b88d393f252e764f1f5f7ad97ef79d59ce29f5f51eeca32eabedd9afa9329\n\t# 1:  CTR mode lets you build a stream cipher from a block cipher.\n\t# 2:  ?\n\n\t# CTR decryption of key/cypher 36f18357be4dbd77f050515c73fcf9f2  /  770b80259ec33beb2561358a9f2dc617e46218c0a53cbeca695ae45faa8952aa0e311bde9d4e01726d3184c34451\n\t# 1:  Always avoid the two time pad!\n\t# 2:  ?\n\n\n\t# Answers:\n\t# Q1.  Basic CBC mode encryption needs padding.\n\t# Q2.  Our implementation uses rand. IV\n\t# Q3.  CTR mode lets you build a stream cipher from a block cipher.\n\t# Q4.  Always avoid the two time pad!\n\n\n# Do 2 variants of CTR decryption  \t\ndef ctrDecrypt(key, cypherText, blockSize):\n\tprint \"\\nCTR decryption of key/cypher\",key,\" / \",cypherText\n\tres1 = ctrDecrypt1(key, cypherText, blockSize)\n\tres2 = ctrDecrypt2(key, cypherText, blockSize)\n\tprint \"1: \", res1 \n\tprint \"2: \", res2\n\treturn res1\n\n# CTR decryption variant 1 (use AES.MODE_CBC mode), \ndef ctrDecrypt1(key, cypherText, blockSize):\n\tk = key.decode('hex')\n\tct = cypherText.decode('hex')\n\tiv = ct[:blockSize]\n\tct1 = ct[blockSize:]\n\tctr = Counter.new(blockSize*8,initial_value=long(iv.encode('hex'),16))\n\tobj = AES.new(k,AES.MODE_CTR,counter=ctr)\n\tpaddedStr = obj.decrypt(ct1)\n\t#paddingAmount = ord(paddedStr[len(paddedStr)-1:])\n\treturn paddedStr#[:-paddingAmount]\n\n# CTR decryption variant 2 \ndef ctrDecrypt2(key, cypherText, blockSize):\n\tcypherTextBlocks =  [cypherText[i:i+(blockSize*2)] for i in range(0, len(cypherText), (blockSize*2))]\t\n\tiv =  long(cypherTextBlocks.pop(0), 16) \n\n\tcypherTextBlocksDecoded = map(methodcaller(\"decode\", \"hex\"), cypherTextBlocks)\n\t\n\tk = key.decode('hex')\n\n\tpt = \"\"\n\n\ti = 0\n\tfor c in cypherTextBlocksDecoded:\n\t \tctr = hex(iv+i << 64)[2:(2*blockSize)+2]\n\t \t#print ctr\n\t \tencIV = AES.new(k, AES.MODE_ECB).encrypt(ctr)\t\n\t \tplaintext =  strxor(encIV, c)\n\t \t#print plaintext\n\t  \ti = i + 1\n\t  \tpt = plaintext + pt\n\t\n\t# @todo something is wrong with this implementation\t\t\n\treturn \"?\"#pt\n  \n# Do 2 variants of CBC decryption  \t\ndef cbcDecrypt(key, cypherText, blockSize):\n\tprint \"\\nCBC decryption of key/cypher\",key,\" / \",cypherText\n\tres1 = cbcDecrypt1(key, cypherText, blockSize)\n\tres2 = cbcDecrypt2(key, cypherText, blockSize)\n\tprint \"1: \", res1 \n\tprint \"2: \", res2\n\treturn res2\n\n# CBC decryption variant 1 (use AES.MODE_CBC mode), \ndef cbcDecrypt1(key, cypherText, blockSize):\n\tk = key.decode('hex')\n\tct = cypherText.decode('hex')\n\tiv = ct[:blockSize]\n\tct1 = ct[blockSize:]\n\tobj = AES.new(k,AES.MODE_CBC,iv)\n\tpaddedStr = obj.decrypt(ct1)\n\tpaddingAmount = ord(paddedStr[len(paddedStr)-1:])\n\treturn paddedStr[:-paddingAmount]\n\n\n# CBC decryption variant 2 defines blocks self, encrypts per block (ECB mode) and xors with previous block => plaintext\ndef cbcDecrypt2(key, cypherText, blockSize):\n\tcypherTextBlocks =  [cypherText[i:i+(blockSize*2)] for i in range(0, len(cypherText), (blockSize*2))]\n\tcypherTextBlocksDecoded = map(methodcaller(\"decode\", \"hex\"), cypherTextBlocks)\n\t#iv =  cypherTextBlocksDecoded.pop(0)\n\tk = key.decode('hex')\n\n\tpt = \"\"\n\n\titer = len(cypherTextBlocksDecoded)\n\tfor c in reversed(cypherTextBlocksDecoded):\n\t\titer = iter - 1\n\t\tif(iter > 0):\n\t\t\tcipher = AES.new(k, AES.MODE_ECB).decrypt(c)\t\t\t\n\t\t\tplaintext = strxor(cipher, cypherTextBlocksDecoded[iter - 1])\n\t\t\t#print \"[\",iter,\"]\", c.encode('hex'), \" => \", cipher.encode('hex'), plaintext\n\t\t\tpt = plaintext + pt\n\n\tpaddingAmount = ord(pt[len(pt)-1:])\n\t\t\t\n\treturn pt[:-paddingAmount]\n\n\n# xor two strings of different lengths\ndef strxor(a, b):     \n    if len(a) > len(b):\n        return \"\".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a[:len(b)], b)])\n    else:\n        return \"\".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a, b[:len(a)])])\n\nmain()\n\t\n\n"
  },
  {
    "path": "week2-problemset/question1.py",
    "content": "# Stanford University\n# Cryptography I\n# https://www.coursera.org/course/crypto\n\n# Week 2\n# Question 1\n# Consider the following five events:\n# Correctly guessing a random 128-bit AES key on the first try.\n# Winning a lottery with 1 million contestants (the probability is 1/106 ).\n# Winning a lottery with 1 million contestants 5 times in a row (the probability is (1/106)5 ).\n# Winning a lottery with 1 million contestants 6 times in a row.\n# Winning a lottery with 1 million contestants 7 times in a row.\n# What is the order of these events from most likely to least likely?\n\n\nimport sys\nimport numpy\n\n\ndef main():\n\tamounts = numpy.array([\n\t\tpow(2,128), \t\t# Correctly guessing a random 128-bit AES key on the first try.\n\t\tpow(10,6), \t\t# Winning a lottery with 1 million contestants (the probability is 1/10^6 ).\n\t\tpow(pow(10,6),5),\t\t# Winning a lottery with 1 million contestants 5 times in a row (the probability is (1/106)5 ).\n\t\tpow(pow(10,6),6),\t\t# Winning a lottery with 1 million contestants 6 times in a row.\n\t\tpow(pow(10,6),7),\t\t# Winning a lottery with 1 million contestants 7 times in a row.\n\t])\n\n\tsortIndex = numpy.argsort(amounts)\n\t\t\n\tsortIndex = [x+1 for x in sortIndex]\n\n\tprint sortIndex\n\t# result [2, 3, 4, 1, 5]\n\n\n\nmain()"
  },
  {
    "path": "week2-problemset/question2.py",
    "content": "# Stanford University\n# Cryptography I\n# https://www.coursera.org/course/crypto\n\n# Week 2\n# Question 2\n# 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.\n\n\nimport sys\nimport numpy\n\n\ndef main():\n\tcomputerPrice = 200 # = $200 \n\tbudget = 4*pow(10,12) # =$ 4 trillion dollars\n\n\tkeysPerSecondPerComputer = pow(10,9) # 1 billion AES keys per second.\n\tmaxNumberKeys = pow(2,128) # 128-bit AES key\n\n\tnumComputers = budget / computerPrice\n\tkeysPerSecond = keysPerSecondPerComputer * numComputers\n\n\tnumberOfSeconds = maxNumberKeys / keysPerSecond \n\n\tprint numberOfSeconds , \"seconds\"\n\tprint (numberOfSeconds/3600) , \"hours\"\n\tprint (numberOfSeconds/3600/24) , \"hours\"\n\tprint (numberOfSeconds/3600/24/365) , \"years\"\n\n\thour = 60*60\n\tday = hour * 24\n\tweek  = day * 7\n\tmonth  = day * 31\n\tyear =  day * 365\n\n\tprint \"\\n\\nMore than an hour but less than a day? \", numberOfSeconds > hour and numberOfSeconds < day\n\tprint \"More than a day but less than a week? \", numberOfSeconds > day and numberOfSeconds < week\n\tprint \"More than a week but less than a month? \", numberOfSeconds > week and numberOfSeconds < month\n\tprint \"More than a 100 years but less than a million years? \", numberOfSeconds > 100*year and numberOfSeconds < pow(10,6)*year\n\tprint \"More than a billion (10^9) years? \", numberOfSeconds > pow(10,9)*year\n\n\t# 17014118346046923173 seconds\n\t# 4726143985013034 hours\n\t# 196922666042209 hours\n\t# 539514153540 years\n\n\n\t# More than an hour but less than a day?  False\n\t# More than a day but less than a week?  False\n\t# More than a week but less than a month?  False\n\t# More than a 100 years but less than a million years?  False\n\t# More than a billion (10^9) years?  True\n\n\n\n\nmain()"
  },
  {
    "path": "week2-problemset/question4.py",
    "content": "# Stanford University\n# Cryptography I\n# https://www.coursera.org/course/crypto\n\n# Week 2\n# Question 4\n# 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. \n# 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   \n# F2:K2x{0,1}64->{0,1}64: \n# Two round Feistel\n# Here R0 is the right 32 bits of the 64-bit input and L0 is the left 32 bits. \n\n# 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. \n\n# 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.\n\n# On input 0^64 the output is \"290b6e3a 39155d6f\".    On input 1^32 0^32 the output is \"d6f491c5 b645c008\".\n# On input 0^64 the output is \"4af53267 1351e2e1\".    On input 1^32 0^32 the output is \"87a40cfa 8dd39154\".\n# On input 0^64 the output is \"5f67abaf 5210722b\".    On input 1^32 0^32 the output is \"bbe033c0 0bc9330e\".\n# On input 0^64 the output is \"2d1cfa42 c0b1d266\".    On input 1^32 0^32 the output is \"eea6e3dd b2146dd0\".\n\n\nimport sys\nimport numpy\nfrom operator import methodcaller\n\n\ndef main():\n\tcyphers = [\n\t[[\"290b6e3a\",\"39155d6f\"], [\"d6f491c5\",\"b645c008\"]],\n\t[[\"4af53267\",\"1351e2e1\"], [\"87a40cfa\",\"8dd39154\"]],\n\t[[\"5f67abaf\",\"5210722b\"], [\"bbe033c0\",\"0bc9330e\"]],\n\t[[\"2d1cfa42\",\"c0b1d266\"], [\"eea6e3dd\",\"b2146dd0\"]],\n\n\t[[\"5f67abaf\",\"5210722b\"], [\"bbe033c0\",\"0bc9330e\"]],\n\t[[\"4af53267\",\"1351e2e1\"], [\"87a40cfa\",\"8dd39154\"]],\t\n\t[[\"2d1cfa42\",\"c0b1d266\"], [\"eea6e3dd\",\"b2146dd0\"]],\n\t[[\"9f970f4e\",\"932330e4\"], [\"6068f0b1\",\"b645c008\"]],\n\n\t]\t\n\n\tfor arow in cyphers:\n\t\tprint \"\\n\", arow\n\t\tfor i in range(0,2):\n\t\t\t\n\t\t\tval1 = arow[0][i] #+ arow[0][1]\n\t\t\tval2 = arow[1][i] #+ arow[1][1]\n\t\t\txor = hexStrToInt(val1) ^ hexStrToInt(val2)\n\t\t\tprint \" %s xor %s => %s\" % (val1, val2, intToHexStr(xor))\n\t\t\n\t\t\t# [['290b6e3a', '39155d6f'], ['d6f491c5', 'b645c008']]\n\t\t\t# ==>  290b6e3a xor d6f491c5 => ffffffff\n\t\t\t#  39155d6f xor b645c008 => 8f509d67\n\n\t\t\t# [['4af53267', '1351e2e1'], ['87a40cfa', '8dd39154']]\n\t\t\t#  4af53267 xor 87a40cfa => cd513e9d\n\t\t\t#  1351e2e1 xor 8dd39154 => 9e8273b5\n\n\t\t\t# [['5f67abaf', '5210722b'], ['bbe033c0', '0bc9330e']]\n\t\t\t#  5f67abaf xor bbe033c0 => e487986f\n\t\t\t#  5210722b xor 0bc9330e => 59d94125\n\n\t\t\t# [['2d1cfa42', 'c0b1d266'], ['eea6e3dd', 'b2146dd0']]\n\t\t\t#  2d1cfa42 xor eea6e3dd => c3ba199f\n\t\t\t#  c0b1d266 xor b2146dd0 => 72a5bfb6\n\ndef hexStrToInt(s):\n\treturn int(s, 16)\n\ndef intToHexStr(i):\n\treturn hex(i)[2:]\n\n\nmain()"
  },
  {
    "path": "week2-problemset/question5.py",
    "content": "# Stanford University\n# Cryptography I\n# https://www.coursera.org/course/crypto\n\n# Week 2\n# Question 5\n# 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. \n\n# 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)\n# and then using this IV in CBC encryption using F(k,.). \n# 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. \n\n# 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. \n\n# What relation holds between c0,c1,c'0?   Note that this relation lets the adversary win the nonce-based CPA game with advantage 1.\n# c0=c1 xor c'0\n# c1=c0\n# c1=0l\n# c1=c'0\n\n\n\nimport sys\nimport numpy\nfrom operator import methodcaller\n\n\ndef main():\n\tkey = hexStrToInt(\"1a2b3c4d\")\n\n\t# loop 1\n\tzero = hexStrToInt(\"00000000\")\n\tm0Arr = [zero, zero]\n\tn0 = encrypt(key, zero)\n\n\tc0Arr = cbc(key, n0, m0Arr)\n\n\n\n\t# loop 2\n\tm1Arr = [c0Arr[0] ^ c0Arr[1]]\n\tn1 = c0Arr[0]\n\n\tc1Arr = cbc(key, n1, m1Arr)\t\n\n\t\n\tc0 = int(c0Arr[0])\n\tc1 = int(c0Arr[1])\n\tc_0 = int(c1Arr[0])\n\t# result\n\tprint \"c0 = %s\" % intToHexStr(c0), c0\n\tprint \"c1 = %s\" % intToHexStr(c1), c1\n\tprint \"c'0 = %s\" % intToHexStr(c_0), c_0\n\n\t\n\n\tprint \"\\n\\n\"\n\tprint \"c0=c1 xor c'0 ? => %s = %s xor %s => %s\" % (intToHexStr(c0), intToHexStr(c1), intToHexStr(c_0), (c1 ^ c_0 == c0) )\n\tprint \"c1=c0 ? => %s = %s  => %s\" % (intToHexStr(c1), intToHexStr(c0),  (c1 == c0) )\n\tprint \"c1=0^l ? => %s = %s  => %s\" % (intToHexStr(c1), intToHexStr(zero),  (c1 == zero) )\n\tprint \"c1=c'0 ? => %s = %s  => %s\" % (intToHexStr(c1), intToHexStr(c_0),  (c1 == c_0) )\n\n\n\t# c0 = 00607c3c 6323260\n\t# c1 = 0859b203 140096003\n\t# c'0 = 0040f858 4257880\n\n\n\n\t# c0=c1 xor c'0 ? => 00607c3c = 0859b203 xor 0040f858 => False\n\t# c1=c0 ? => 0859b203 = 00607c3c  => False\n\t# c1=0^l ? => 0859b203 = 00000000  => False\n\t# c1=c'0 ? => 0859b203 = 0040f858  => False\n\t\n\t# @todo ??? Doing something wrong.. but what???\n\n\t\n\ndef cbc(k, iv, mArray):\n\tcArray = []\n\tlastInp = iv\n\tfor m in mArray:\n\t\tinp = lastInp ^ m\n\t\tc = encrypt(k, inp)\n\t\tcArray.append(c)\n\t\tlastInp = c\n\treturn cArray\n\n\t\n\ndef encrypt(k, i):\n\treturn (i  + k )\n\n\ndef hexStrToInt(s):\n\treturn int(s, 16)\n\ndef intToHexStr(i):\n\treturn hex(i)[2:].zfill(8)\n\n\nmain()"
  },
  {
    "path": "week2-problemset/question9.py",
    "content": "# 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 and consider the following PRF F:R5xR->R defined as follows:\n\n# F(k,x):= t=k[0] for i=1 to 4 doif (x[i-1]==1) t=t xor k[i] output t \n\n# 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]. \n\n# For a random key k unknown to you, you learn that \n# F(k,0110)=0011  and  F(k,0101)=1010  and  F(k,1110)=0110 . \n# 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.\n\n\n\nimport sys\nimport numpy\nfrom operator import methodcaller\n\n\ndef main():\n\tk5 = [\n\t\t'0011', # 0\n\t\t'0101', # 1 \n\t\t'0000', # 2\n\t\t'0000', # 3\n\t\t'0000'  # 4\n\t]\n\n\t\n\t\n\n\txTest = [\n\t\t['0110','0011'], # given\n\t\t['0101','1010'], # given\n\t\t['1110','0110'], # given\n\t\t['1101','????']  # target\n\n\t]\n\n\tprint \"xors applied\"\n\tfor test in xTest:\n\t\tfExplained(test[0], test[1])\n\n\tprint \"\\n\\nxors calculated\"\n\tfor test in xTest:\n\t\tf(k5, test[0], test[1])\n\n\tprint \"\\n\\n deduction:\"\n\tprint \"\\n1. F('0110') xor F('0101') xor F('1110') => 0011 xor 1010 xor 0110\"\n\tprint \"(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\"\n\tprint \"(k[0] xor k[1] xor k[2] xor k[4]) => 1111\"\n\t\n\ndef fExplained(x, out):\n\tfstr = \"k[0]\"\n\tfor i in range (1,5):\n\t\tif(int(x[i -1]) == 1):\n\t\t\tfstr =  fstr + ' xor k['+str(i)+\"]\\t\"\n\t\telse:\n\t\t\tfstr = fstr + \"\\t\\t\\t\"\n\n\tprint x + \" => \" + fstr + \" => \\t\" + out + \" == \" + str(binStrToInt(out))\n\t\ndef f(k, x, test):\n\tres = binStrToInt(k[0])\n\tfor i in range (1,5):\n\t\tif(int(x[i - 1]) == 1):\n\t\t\tres = res ^ binStrToInt(k[i])\n\t\t\n\tprint x + \" => \" + intToBinStr(res) + \" => \" + test\n\n\n\ndef binStrToInt(s):\n\ttry:\n\t\treturn int(s, 2)\n\texcept ValueError:\n\t\treturn s\n\t\n\ndef intToBinStr(i):\n\treturn bin(i)[2:].zfill(4)\n\n\nmain()"
  },
  {
    "path": "week3-problemset/programming_assignment.py",
    "content": "# Question 1\n# Suppose a web site hosts large video file F that anyone can download. \n# Browsers who download the file need to make sure the file is authentic before displaying the content to the user. \n# 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). \n# 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. \n\n# Unfortunately, this means that the video will only begin playing after the *entire* file F has been downloaded.\n# 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. \n\n# 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. \n# 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: \n# (https://d396qusza40orc.cloudfront.net/crypto/images/pp3-fig.jpg)[hashing process]\n# 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. \n\n# Now, a browser downloads the file F one block at a time, where each block includes the appended hash value from the diagram above. \n# 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. \n# 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. \n# 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. \n\n# 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. \n# 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. \n# Therefore after the first hash check the browser is convinced that both B0 and h1 are authentic.\n# 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. \n\n# 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. \n# When appending the hash value to each block, please append it as binary data, that is, as 32 unencoded bytes (which is 256 bits). \n# 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. \n\n# 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)\n\n# 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:\n# 03c08f4ee0b576fe319338139c045c89c3e8e9409633bea29442e21425006ea8\n\nimport sys\nimport os\n\nfrom Crypto.Hash import SHA256\n\ndef main():\n\tblock_size = 1024 #bytes\n\t# Has to save the files, because they are behind coursera login\n\tfile_target = \"files/target.mp4\"\n\thash_target = \"\"\n\n\tfile_check = \"files/check.mp4\"\n\thash_check = \"03c08f4ee0b576fe319338139c045c89c3e8e9409633bea29442e21425006ea8\"\n\n\n\th0_check = calculate_hash(file_check, block_size)\n\th0_check_hex = h0_check.encode('hex')\n\tprint \"calculated h0 for\",file_check,\":\",h0_check_hex,\" == \",hash_check,\"? \",hash_check==h0_check_hex\n\n\th0_target = calculate_hash(file_target, block_size)\n\th0_target_hex = h0_target.encode('hex')\n\tprint \"calculated h0 for\",file_target,\":\",h0_target_hex\n\n\t# Output:\n\t# Opening file: files/check.mp4  ;  16927313 bytes; \n\t# calculated h0 for files/check.mp4 : 03c08f4ee0b576fe319338139c045c89c3e8e9409633bea29442e21425006ea8  ==  03c08f4ee0b576fe319338139c045c89c3e8e9409633bea29442e21425006ea8 ?  True\n\t# Opening file: files/target.mp4  ;  12494779 bytes; \n\t# calculated h0 for files/target.mp4 : 5b96aece304a1422224f9a41b228416028f9ba26b0d1058f400200f06a589949\n\n\n\ndef calculate_hash(file_path, block_size):\n\t# Get file size in bytes\n\tfile_size = os.path.getsize(file_path)\n\t# The last block size \n\tlast_block_size = file_size % block_size\n\n\t\n\tprint \"Opening file:\",file_path, \" ; \",file_size,\"bytes; \"\n\tfp = open(file_path, 'rb')\n\n\tlast_hash = ''\n\t# read the chuncks\n\tfor chunk in read_reversed_chunks(fp, file_size, last_block_size, block_size):\n\t\t# SHA-256 obj\n\t\tsha256 = SHA256.new()\n\t\tsha256.update(chunk)\n\t\tif(last_hash):\n\t\t\tsha256.update(last_hash)\n\t\tlast_hash = sha256.digest()\n\tfp.close()\n\n\t# Return the last hash (h0)\n\treturn last_hash\n\n\ndef read_reversed_chunks(file_object, file_size, last_chuck_size, chunk_size):\n\titer = 0\n\tlast_pos = file_size\n\twhile last_pos>0:\n\t\tsize = chunk_size\n\t\tif(iter == 0):\n\t\t\tsize = last_chuck_size\n\n\t\t#print \"read from\",last_pos - size,\"to\",last_pos\n\t\tfile_object.seek(last_pos - size)\n\t\tdata = file_object.read(chunk_size)\n\t\tif not data:\n\t\t\tbreak\n\n\t\titer = iter + 1\n\t\tlast_pos -= size\n\t\tyield data\n\nmain()"
  },
  {
    "path": "week3-problemset/question8.py",
    "content": "# Question 8\n# In this question and the next, you are asked to find collisions on two compression functions:\n# f1(x,y)=AES(y,x) xor y,  and\n# f2(x,y)=AES(x,x) xor y,\n# where AES(x,y) is the AES-128 encryption of y under key x. \n\n# 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. \n# 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. \n\n# 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.\n# 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.\n\n\nimport sys\nfrom Crypto.Cipher import AES\n\n\n# Please find (x1,y1), (x2,y2) such that f1(x1,y1)=f1(x2,y2).\n# => AES(y1,x1) xor y1 = AES(y2,x2) xor y2\n# Unsing E for encrypt, D for decrypt:\n# => E(y1,x1) xor y1 = E(y2,x2) xor y2\n\n# 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\n# => E(y1,x1) xor y1 = E(y2, D(y2, E(y1,x1) xor y1) ) xor y2\n\n# This results into\n# => E(y1,x1) xor y1 = E(y1,x1) xor y1 xor y2\n\n# x1, y1 can be anything\n# y2 = 0^n, since any string of bits xor 0 is itself. \n# x2 = D(y2, E(y1,x1) xor y1)\n\ndef main():\n\tx1 = \"12345678123456781234567812345678\".decode('hex') # arbitrary 128bit string\n\ty1 = \"90abcdef90abcdef90abcdef90abcdef\".decode('hex') # arbitrary 128bit string\n\ty2 = \"00000000000000000000000000000000\".decode('hex') # 0^n string\n\n\tprint \"x1:\",x1.encode('hex')\n\tprint \"y1:\",y1.encode('hex')\n\tprint \"y2:\",y2.encode('hex')\n\n\tm1 = f1(x1, y1)\n\tprint \"\\nf1(x1,y1) = \",m1.encode('hex')\n\t\n\tx2 = find_x2(m1, y2)\n\tprint \"\\nD(y2, f1(x1,y1)) => x2:\",x2.encode('hex')\n\n\tm2 = f1(x2, y2)\n\tprint \"\\n\\ncheck: f1(x2,y2) =\",m2.encode('hex'),\"\\n==\",m1.encode('hex'),\"? \",m1==m2\n\n\tprint \"\\n\"\n\n\t# Output:\n\t# x1: 12345678123456781234567812345678\n\t# y1: 90abcdef90abcdef90abcdef90abcdef\n\t# y2: 00000000000000000000000000000000\n\n\t# f1(x1,y1) =  115065c6363f7d143c4dfee65894bf7d\n\n\t# D(y2, f1(x1,y1)) => x2: 8b701b44711cc43b4f756d7977d7315c\n\n\t# check: f1(x2,y2) = 115065c6363f7d143c4dfee65894bf7d \n\t# == 115065c6363f7d143c4dfee65894bf7d ?  True\n\n\ndef f1(x, y):\n\treturn strxor(AES.new(y,AES.MODE_ECB).encrypt(x), y)\n\ndef find_x2(m, y):\n\treturn AES.new(y,AES.MODE_ECB).decrypt(m)\n\n\n\n# xor two strings of different lengths\ndef strxor(a, b):     \n    if len(a) > len(b):\n        return \"\".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a[:len(b)], b)])\n    else:\n        return \"\".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a, b[:len(a)])])\n\n\nmain()"
  },
  {
    "path": "week3-problemset/question9.py",
    "content": "# Question 8\n# In this question and the next, you are asked to find collisions on two compression functions:\n# f1(x,y)=AES(y,x) xor y,  and\n# f2(x,y)=AES(x,x) xor y,\n# where AES(x,y) is the AES-128 encryption of y under key x. \n\n# 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. \n# 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. \n\n# 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). \n# In other words, the first two pairs are a collision for f1 and the last two pairs are a collision for f2. \n\n\n\nimport sys\nfrom Crypto.Cipher import AES\n\n\n# Please find (x3,y3), (x4,y4) such that f2(x3,y3)=f2(x4,y4).\n# => AES(x3,x3) xor y3 = AES(x4,x4) xor y4\n# Since the 'y' is independant of the Encryption, you can choose any y that E(x,x) = y\n# => E(x3,x3) xor E(x3,x3) = E(x4,x4) xor E(x4,x4)\n\n# Since any value xor itself = 0\n# => 0 = 0\n\n\n\ndef main():\n\tx3 = \"12345678123456781234567812345678\".decode('hex') # arbitrary 128bit string\n\tx4 = \"90abcdef90abcdef90abcdef90abcdef\".decode('hex') # arbitrary 128bit string\n\t\n\tprint \"x3:\",x3.encode('hex')\n\tprint \"x4:\",x4.encode('hex')\n\t\n\n\ty3 = find_y(x3)\n\tprint \"\\nE(x3,x3) = y3 = \",y3.encode('hex')\n\n\ty4 = find_y(x4)\n\tprint \"\\nE(x4,x4) = y4 = \",y4.encode('hex')\n\t\n\t\n\tm3 = f2(x3, y3)\n\tprint \"\\n\\ncheck: f2(x3,y3) =\",m3.encode('hex')\n\tm4 = f2(x4, y4)\n\tprint \"\\ncheck: f2(x4,y4) =\",m4.encode('hex')\n\tprint \"\\nm3 == m4 ? \",m3==m4\n\n\tprint \"\\n\"\n\n\t# Output:\n\t# x3: 12345678123456781234567812345678\n\t# x4: 90abcdef90abcdef90abcdef90abcdef\n\n\t# E(x3,x3) = y3 =  d7eeee18c420faf0dc7db5ca73a2b817\n\n\t# E(x4,x4) = y4 =  ac6f20842f239c423ff5e89c870cca75\n\n\t# check: f2(x3,y3) = 00000000000000000000000000000000\n\n\t# check: f2(x4,y4) = 00000000000000000000000000000000\n\n\t# m3 == m4 ?  True\n\n\ndef f2(x, y):\n\treturn strxor(AES.new(x,AES.MODE_ECB).encrypt(x), y)\n\ndef find_y(x):\n\treturn AES.new(x,AES.MODE_ECB).encrypt(x)\n\n\n\n# xor two strings of different lengths\ndef strxor(a, b):     \n    if len(a) > len(b):\n        return \"\".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a[:len(b)], b)])\n    else:\n        return \"\".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a, b[:len(a)])])\n\n\nmain()"
  },
  {
    "path": "week4-problemset/programming_assignment.py",
    "content": "# Question 1\n# In this project you will experiment with a padding oracle attack against a toy web site hosted at crypto-class.appspot.com. \n# Padding oracle vulnerabilities affect a wide variety of products, including secure tokens. \n# 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. \n#\n# Now to business. Suppose an attacker wishes to steal secret information from our target web site crypto-class.appspot.com. \n# The attacker suspects that the web site embeds encrypted customer data in URL parameters such as this:\n# http://crypto-class.appspot.com/po?er=f20bdba6ff29eed7b046d1df9fb7000058b1ffb4210a580f748b4ac714c001bd4a61044426fb515dad3f21f18aa577c0bdf302936266926ff37dbf7035d5eeb4\n# That is, when customer Alice interacts with the site, the site embeds a URL like this in web pages it sends to Alice. \n# The attacker intercepts the URL listed above and guesses that the ciphertext following the \"po?er=\" is a hex encoded AES CBC encryption \n# with a random IV of some secret data about Alice's session. \n#\n# After some experimentation the attacker discovers that the web site is vulnerable to a CBC padding oracle attack. \n# In particular, when a decrypted CBC ciphertext ends in an invalid pad the web server returns a 403 error code (forbidden request). \n# When the CBC padding is valid, but the message is malformed, the web server returns a 404 error code (URL not found). \n#\n# 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\n# http://crypto-class.appspot.com/po?er=\"your ciphertext here\"\n# and observe the resulting error code. The padding oracle will let you decrypt the given ciphertext one byte at a time. \n# 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. \n# The decrypted message is ASCII encoded. \n#\n# 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. \n# 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. \n\n# This project shows that when using encryption you must prevent padding oracle attacks by either using encrypt-then-MAC as in EAX or GCM, \n# or if you must use MAC-then-encrypt then ensure that the site treats padding errors the same way it treats MAC errors.\n\nimport sys\nimport os\nimport urllib2\nfrom operator import methodcaller\n\n\n\nfrom Crypto.Hash import SHA256\n\n\n#--------------------------------------------------------------\n# padding oracle\n#--------------------------------------------------------------\nclass PaddingOracle(object):\n\tdef __init__(self):\n\t\tself.targetURL = 'http://crypto-class.appspot.com/po?er='\n\n\tdef query(self, q):\n\t\ttarget = self.targetURL + urllib2.quote(q)    # Create query URL\n\t\treq = urllib2.Request(target)         # Send HTTP request to server\n\t\ttry:\n\t\t\tf = urllib2.urlopen(req)          # Wait for response\n\t\texcept urllib2.HTTPError, e:          \n\t\t\treturn e.code == 404\n\n#--------------------------------------------------------------\n# Smart Char Guesser\n#--------------------------------------------------------------\nclass CharGuesser(object):\n\tdef __init__(self):\n\t\tself.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']\n\t\tself.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']\n\t\tself.otherCharsOrder = [' ','0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', ',', '!', '?', '&']\n\t\tself.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']\n\t\tself.charsUsed = []\n\n\n\tdef guessPrecedingChar(self, currentChar=None):\n\t\tif(currentChar):\n\t\t\t# Check common bigrams\n\t\t\tfor bigram in self.commonBigramsOrder:\n\t\t\t\tif bigram[1] == currentChar.lower():\n\t\t\t\t\tif not self.checkUsed(bigram[0]):\n\t\t\t\t\t\treturn self.setUsed(bigram[0])\n\t\t\t\t\tif not self.checkUsed(bigram[0].upper()):\n\t\t\t\t\t\treturn self.setUsed(bigram[0].upper())\n\n\t\t# Else check chars in order of probability\n\t\tfor char in self.letterFrequencyOrder:\n\t\t\tif not self.checkUsed(char):\n\t\t\t\treturn self.setUsed(char)\n\n\t\t# Else check uppercase chars in order of probability of first chars\n\t\tfor char in self.firstLetterFrequencyOrder:\n\t\t\tif not self.checkUsed(char):\n\t\t\t\treturn self.setUsed(char)\n\n\t\t# Else check common chars, puntcuation, numbers, etc\n\t\tfor char in self.otherCharsOrder:\n\t\t\tif not self.checkUsed(char):\n\t\t\t\treturn self.setUsed(char)\n\t\t\t\t\n\t\t# Else loop all ASCII from 0-255\n\t\tfor char in map(lambda x: chr(x), range(0,256)):\n\t\t\tif not self.checkUsed(char):\n\t\t\t\treturn self.setUsed(char)\t\n\t\t\n\t\t# When all else fails?\n\t\treturn None\n\n\tdef checkUsed(self,char):\n\t\treturn char in self.charsUsed\n\n\tdef setUsed(self,char):\n\t\tself.charsUsed.append(char)\n\t\treturn char\n\n\n\ndef main():\n\tcryptoText = \"f20bdba6ff29eed7b046d1df9fb7000058b1ffb4210a580f748b4ac714c001bd4a61044426fb515dad3f21f18aa577c0bdf302936266926ff37dbf7035d5eeb1\".decode('hex')\n\tblockSize = 16 # 128 bit AES\n\tcryptoBlocks  = splitCount(cryptoText, blockSize) # x 16 byte blocks, where block 0 is the IV\n\tmessageBlocks = splitCount((\"00\" * blockSize * (len(cryptoBlocks)-1)).decode('hex'),  blockSize) # init message blocks\n\t## iv = cryptoBlocks.pop(0) # First item is IV in CBC crypto\n\tlastChar = None\n\n\n\n\tpo = PaddingOracle()\n\n\t# m0 corresponds to c0, which has index 1 in cryptoBlocks. IV has index 0 in cryptoBlocks. \n\t# We start with the last block\n\tfor blockNum in reversed(range(0,len(cryptoBlocks))):\n\n\n\t\t# loop all 16 positions, last to first\n\t\tfor position in reversed(range(0, blockSize)):\n\t\t\tpaddingNum = blockSize - position\n\t\t\t# reinit the crypto block per position\n\t\t\tcryptoSourceBlock = cryptoBlocks[blockNum]\n\t\t\t\n\t\t\t# 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])\n\t\t\tfor pl in range(1, paddingNum): \n\t\t\t\tplPos = position + pl\n\t\t\t\tmessageValue = messageBlocks[blockNum][plPos]\n\t\t\t\tcryptoSourceBlock[plPos] ^= messageValue ^ paddingNum\n\n\t\t\t# init a ASCII char guesser for this position\n\t\t\tcharGuesser = CharGuesser()\n\n\t\t\tcounter = 0\n\t\t\twhile counter < 10:\n\t\t\t\t# reinit the crypto block per guess, with padding on correct pos\n\t\t\t\tcryptoSourceBlock_bak = cryptoSourceBlock\n\t\t\t\tguess = charGuesser.guessPrecedingChar(lastChar)\n\n\t\t\t\t# Safeguard\n\t\t\t\tif(guess == None):\n\t\t\t\t\tprint \"Nothing found\"\n\t\t\t\t\tbreak;\n\n\t\t\t\tprint guess\n\t\t\t\tprint paddingNum\n\t\t\t\tprint cryptoSourceBlock.encode('hex')\n\n\t\t\t\t# XOR the cryptoblock postion with the guess and the paddingnum\n\t\t\t\tcryptoSourceBlock[position] ^= ord(guess) ^ paddingNum\n\t\t\t\tcryptoGuess = buildCryptoString(cryptoText, (blockNum * blockSize), cryptoSourceBlock)\n\t\t\t\tif(po.query(cryptoGuess)):\n\t\t\t\t\tprint \"found char \", guess\n\t\t\t\t\tmessageBlocks[blockNum][position] = guess\n\t\t\t\t\tbreak;\n\n\t\t\t\tcounter += 1\n\n\n\n\t\t\t\n\t\t\t# print cryptoSourceBlock[blockSize - position].encode('hex') \n\t\t\t# cryptoSourceBlock[position] ^= guess ^ position\n\n\n\n\n\t\n\t# po = PaddingOracle()\n\t# print po.query() \n\t# lg = CharGuesser()\n\t# print lg.guessPrecedingChar('n')\n\t# print lg.guessPrecedingChar('n')\n\t# print lg.guessPrecedingChar('n')\n\t# print lg.guessPrecedingChar()\n\ndef splitCount(s, count):\n     return [''.join(x) for x in zip(*[list(s[z::count]) for z in range(count)])]\n\ndef buildCryptoString(cryptoText, position, newBlock):\n\treturn cryptoText[position]\n\n\nmain()"
  },
  {
    "path": "week4-problemset/question1.py",
    "content": "# Question 1\n# An attacker intercepts the following ciphertext (hex encoded): \n\n#    20814804c1767293b99f1d9cab3bc3e7 ac1e37bfb15599e5f40eef805488281d \n\n# He knows that the plaintext is the ASCII encoding of the message \"Pay Bob 100$\" (excluding the quotes). \n# He also knows that the cipher used is CBC encryption with a random IV using AES as the underlying block cipher. \n# Show that the attacker can change the ciphertext so that it will decrypt to \"Pay Bob 500$\". What is the resulting ciphertext (hex encoded)? \n# This shows that CBC provides no integrity.\n\nimport sys\n\ndef main():\n\t# input\n\tcypherText = \"20814804c1767293b99f1d9cab3bc3e7 ac1e37bfb15599e5f40eef805488281d\".split(' ')\n\t\n\t# set the CBC parts. The first part is the IV\n\tcypherTextIV = cypherText[0].decode('hex')\n\tcypherTextC0 = cypherText[1].decode('hex')\n\t\n\t# define plaintexts\n\tplainText = \"Pay Bob 100$\"\n\tplainTextTarget = \"Pay Bob 500$\"\n\n\t# define paddings\n\tpaddingNum1 = str(len(cypherTextC0) - len(plainText))\n\tpadding1 = \"\".join([paddingNum1] * int(paddingNum1))\n\n\tpaddingNum2 = str(len(cypherTextC0) - len(plainTextTarget))\n\tpadding2 = \"\".join([paddingNum2] * int(paddingNum2))\n\n\t# append to plaintext the paddings\n\tplainText += padding1\n\tplainTextTarget += padding2\n\n\t# XOR the plaintext to determine the value to XOR with\n\txorredPlainText = strxor(plainText, plainTextTarget)\n\n\t# Since the decription of c[0] is XORed with IV to retrieve the plaintext xor the IV with the desired mutation\n\tnewIV = strxor(xorredPlainText, cypherTextIV)\n\n\t# new CBC \n\tprint \"New CBC\\n\",newIV.encode('hex'), cypherText[1]\n\n\t# Output:\n\t# New CBC\n\t# 20814804c1767293bd9f1d9cab3bc3e7 ac1e37bfb15599e5f40eef805488281d\n\n\n# xor two strings of different lengths\ndef strxor(a, b):     \n    if len(a) > len(b):\n        return \"\".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a[:len(b)], b)])\n    else:\n        return \"\".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a, b[:len(a)])])\n\n\nmain()"
  }
]