├── .gitignore ├── README.md ├── hw1 ├── AESCtr.py ├── HW1GetStarted.docx.pdf └── test_AESCtr.py ├── hw2 ├── HW2LengthPreservingEncryptionScheme.pdf ├── MyFeistel.py └── test_MyFeistel.py ├── hw3 ├── HW3AttackingPaddingOracle.pdf ├── paddingoracle.py └── poattack.py ├── hw4 ├── HW4PasswordBasedAuthenticatedEncryption.pdf ├── pwfernet.py └── scrypt_backend.py ├── hw5 └── HW5TLSServerSetup.pdf ├── hw6 └── hw6.md └── slides ├── backdoors.pdf ├── censorship.pdf ├── cryptodev.pdf ├── ctr-blockcipher.pdf ├── ctr-mode.pdf ├── dh.pdf ├── digsigs.pdf ├── digsigs2.pdf ├── ecc.pdf ├── hash.pdf ├── hybrid.pdf ├── intro.pdf ├── msgauth.pdf ├── otp.pdf ├── padoracle.pdf ├── pwae.pdf ├── rng.pdf ├── rsa.pdf ├── symenc.pdf └── tls.pdf /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | __pycache__ 3 | .cache 4 | grading/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Syllabus for CS 5830 2 | 3 | Welcome to CS 5830, Cryptography. We will be studying cryptography and how to 4 | use it in practice. By the end of the course you should understand not only the 5 | basics of cryptography, but how to implement suitable cryptographic algorithms 6 | within broader projects. You'll also get a taste of modern theoretical 7 | cryptography here and there, but this course will not focus on theory and no 8 | higher-level mathematics will be needed. 9 | 10 | A key aspect of the course will be implementing cryptographic schemes, as well 11 | as showing how to break poorly designed or implemented schemes. Some homeworks 12 | will target feature requests in a widely used cryptography library, bonus points 13 | will be awarded for pull-worthy code. 14 | 15 | 16 | Instructor: Tom Ristenpart (https://rist.tech.cornell.edu) 17 | TA: Paul Grubbs (https://www.cs.cornell.edu/~paulgrubbs/) 18 | 19 | 20 | ### Pre-requisites 21 | 22 | Students should have programming experience (we will be focusing on Python), 23 | understand basic probability, know binary representations (ASCII), operations on 24 | bit strings (XOR), have some background on computer networking, file systems, 25 | etc. If in doubt shoot the instructor an email. 26 | 27 | 28 | 29 | ### Requirements 30 | 31 | The class will involve a combination of lectures, in-class group exercises, 32 | homeworks, a prelim, and a final. You'll be graded according to the following: 33 | 34 | * Participation: 10% 35 | * Homeworks: 50% (each homework will count an equal amount) 36 | * Prelim: 20% 37 | * Final: 20% 38 | 39 | There will be several opportunities for extra credit, as well. 40 | 41 | ### Background reading 42 | 43 | The following books should be helpful, but none are required if you don't want to spend the money: 44 | 45 | * [Cryptography 101 by Houtven](https://www.crypto101.io/). Free, but not complete. Feel free to send helpful feedback to the author. 46 | 47 | * [Cryptography Engineering by Ferguson, Schneier, and Kohno](https://www.schneier.com/books/cryptography_engineering/). A gentle 48 | introduction to cryptography. 49 | 50 | * [Modern Cryptography by Katz and Lindell](http://www.cs.umd.edu/~jkatz/imc.html). A formal treatment of cryptography. 51 | We will make reference to, but not go into detail on, topics they treat in 52 | more detail. 53 | 54 | 55 | ## Lecture schedule 56 | 57 | A very preliminary schedule is below to give a taste of the scope of 58 | what we're hoping to cover. Homeworks will be due on the due date by 59 | 11:59:59pm EST. You can use in total 3 late days throughout the semeseter. 60 | 61 | 62 | 63 | | Date | Topic | Note | 64 | |------|---------|--------| 65 | | Jan 26 | Intro & one-time-pads | [Slides](slides/intro.pdf) | 66 | | Jan 31 | OTP | [Slides](slides/otp.pdf) | 67 | | Feb 2 | CTR mode, computational indistinguishability & reductions | [Slides](slides/ctr-mode.pdf) | 68 | | Feb 7 | Block ciphers | [Slides](slides/ctr-blockcipher.pdf) | 69 | | Feb 9 | Class cancelled (snow day) | | 70 | | Feb 14 | Block cipher modes, CBC mode | [Slides](slides/symenc.pdf) | 71 | | Feb 16 | Padding oracle attacks | [Slides](slides/padoracle.pdf) | 72 | | Feb 21 | No Lecture (February break) | | 73 | | Feb 23 | Authenticated encryption, Message authentication | [Slides](slides/msgauth.pdf) | 74 | | Feb 28 | Hash functions, HMAC | [Slides](slides/hash.pdf) | 75 | | Mar 2 | Guest lecture: Paul Kehrer | | 76 | | Mar 7 | Password-based AEAD | [Slides](slides/pwae.pdf) | 77 | | Mar 9 | TLS & TLS record layer | [Slides](slides/tls.pdf) | 78 | | Mar 14 | Campus closed | | 79 | | Mar 16 | Overview of practice midterm | | 80 | | Mar 21 | In-class midterm | | 81 | | Mar 23 | Overview of midterm | | 82 | | Mar 28 | Paul's lecture on unit testing | | 83 | | Mar 30 | RSA | [Slides](slides/rsa.pdf) | 84 | | Apr 4 | No lecture (Spring break) | | 85 | | Apr 6 | No lecture (Spring break) | | 86 | | Apr 11 | Key exchange & Diffie-Hellman | [Slides](slides/dh.pdf) | 87 | | Apr 13 | Digital signatures & PKI | [Slides](slides/digsigs.pdf)| 88 | | Apr 18 | Discrete log based digital signatures | [Slides](slides/digsigs2.pdf) | 89 | | Apr 20 | ECC crypto | [Slides](slides/ecc.pdf) | 90 | | Apr 25 | Hybrid encryption & ElGamal | [Slides](slides/hybrid.pdf)| 91 | | Apr 27 | RNGs | [Slides](slides/rng.pdf) | 92 | | May 2 | Cryptographic backdoors | [Slides](slides/backdoors.pdf) | 93 | | May 4 | Summary & Internet Censorship | [Slides](slides/censorship.pdf) | 94 | | May 9 | (Tom traveling) | | 95 | 96 | -------------------------------------------------------------------------------- /hw1/AESCtr.py: -------------------------------------------------------------------------------- 1 | from cryptography.hazmat.primitives import hashes, padding 2 | from cryptography.hazmat.backends import default_backend 3 | from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes 4 | import base64 5 | import binascii 6 | import os 7 | 8 | 9 | class AESCtr: 10 | def __init__(self, key, backend=None): 11 | if backend is None: 12 | backend = default_backend() 13 | 14 | key = base64.urlsafe_b64decode(key) 15 | if len(key) != 16: 16 | raise ValueError("AES key must be 16 btyes long and url-safe base64-encoded." 17 | "Got: {} ({})".format(key, len(key))) 18 | self._encryption_key = key 19 | self._backend = backend 20 | self._block_size_bytes = algorithms.AES.block_size / 8 # in bytes 21 | self._nonce_size = self._block_size_bytes / 2 # in bytes 22 | 23 | def _nonced_counters(self, nonce, numblocks): 24 | """Returns the nonced 16 byte counter required for ctr mode""" 25 | for ctr in xrange(numblocks): 26 | yield nonce + struct.pack('>Q', ctr) 27 | 28 | def _encipher_one_block(self, data): 29 | encryptor = Cipher(algorithms.AES(self._encryption_key),modes.ECB(),self._backend).encryptor() 30 | return encryptor.update(data) + encryptor.finalize() 31 | 32 | def encrypt(self, data): 33 | """ This function takes a byte stream @data and outputs the ciphertext """ 34 | if not isinstance(data, bytes): 35 | raise TypeError("data must be bytes.") 36 | nonce = os.urandom(self._nonce_size) 37 | ctx = "" 38 | 39 | # TODO: Fill in this function 40 | 41 | return ctx 42 | 43 | def decrypt(self, ctx): 44 | """ This function decrypts a ciphertext encrypted using AES-CTR mode. """ 45 | data = "" 46 | 47 | # TODO: Fill in this function. 48 | 49 | return data 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /hw1/HW1GetStarted.docx.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cornelltech/CS5830-Spring2017/9fdb717cc7b0171a136f5658769f701767f9a2cc/hw1/HW1GetStarted.docx.pdf -------------------------------------------------------------------------------- /hw1/test_AESCtr.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | from AESCtr import AESCtr 4 | import pytest 5 | import base64 6 | import os 7 | 8 | def test_basic(): 9 | key = base64.urlsafe_b64encode(os.urandom(16)) 10 | 11 | aes = AESCtr(key) 12 | txt = b'A great Secret message'*12 # To make it larger than 128-bit 13 | ctx = aes.encrypt(txt) 14 | dtxt = aes.decrypt(ctx) 15 | assert dtxt==txt, "The decrypted text is not the same as the original text" 16 | 17 | # TODO: Fill in more tests of AESCtr 18 | 19 | -------------------------------------------------------------------------------- /hw2/HW2LengthPreservingEncryptionScheme.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cornelltech/CS5830-Spring2017/9fdb717cc7b0171a136f5658769f701767f9a2cc/hw2/HW2LengthPreservingEncryptionScheme.pdf -------------------------------------------------------------------------------- /hw2/MyFeistel.py: -------------------------------------------------------------------------------- 1 | # Homework 2 (CS5830) 2 | # Trying to implement a length preserving Encryption function. 3 | # 4 | 5 | from cryptography.hazmat.primitives import hashes, padding 6 | from cryptography.hazmat.backends import default_backend 7 | import base64 8 | import binascii 9 | 10 | def xor(a,b): 11 | """ 12 | xors two raw byte streams. 13 | """ 14 | assert len(a) == len(b), "Lengths of two strings are not same. a = {}, b = {}".format(len(a), len(b)) 15 | return ''.join(chr(ord(ai)^ord(bi)) for ai,bi in zip(a,b)) 16 | 17 | class MyFeistel: 18 | def __init__(self, key, num_rounds, backend=None): 19 | if backend is None: 20 | backend = default_backend() 21 | 22 | key = base64.urlsafe_b64decode(key) 23 | if len(key) != 16: 24 | raise ValueError( 25 | "Key must be 16 url-safe base64-encoded bytes. Got: {} ({})".format(key, len(key)) 26 | ) 27 | self._num_rounds = num_rounds 28 | self._encryption_key = key 29 | self._backend = backend 30 | self._round_keys = [self._encryption_key \ 31 | for _ in xrange(self._num_rounds)] 32 | for i in xrange(self._num_rounds): 33 | if i==0: continue 34 | self._round_keys[i] = self._SHA256hash(self._round_keys[i-1]) 35 | 36 | def _SHA256hash(self, data): 37 | h = hashes.Hash(hashes.SHA256(), self._backend) 38 | h.update(data) 39 | return h.finalize() 40 | 41 | def encrypt(self, data): 42 | assert len(data)%2 == 0, "Supports only balanced feistel at "\ 43 | "this moment. So provide even length messages." 44 | 45 | # TODO - Fill in 46 | return data 47 | 48 | def decrypt(self, ctx): 49 | assert len(ctx)%2 == 0, "Supports only balanced feistel at "\ 50 | "this moment. So provide even length ciphertext." 51 | #TODO - Fill in 52 | return ctx 53 | 54 | def _prf(self, key, data): 55 | """Set up secure round function F 56 | """ 57 | # TODO - set up round function using AES 58 | return data 59 | 60 | def _feistel_round_enc(self, data): 61 | """This function implements one round of Fiestel encryption block. 62 | """ 63 | # TODO - Implement this function 64 | return data 65 | 66 | def _feistel_round_dec(self, data): 67 | """This function implements one round of Fiestel decryption block. 68 | """ 69 | # TODO - Implement this function 70 | return data 71 | 72 | class LengthPreservingCipher(object): 73 | #'length' is in bytes here 74 | def __init__(self, key, length=6): 75 | self._length = 6 76 | #TODO 77 | 78 | def encrypt(self, data): 79 | # TODO 80 | return data 81 | 82 | def decrypt(self, data): 83 | # TODO 84 | return data 85 | 86 | # TODO - add other functions if required 87 | -------------------------------------------------------------------------------- /hw2/test_MyFeistel.py: -------------------------------------------------------------------------------- 1 | from MyFeistel import MyFeistel, LengthPreservingCipher 2 | import pytest 3 | import base64 4 | import os 5 | 6 | class TestMyFeistel: 7 | def test_Functionality(self): 8 | key = base64.urlsafe_b64encode(os.urandom(16)) 9 | feistel = MyFeistel(key, 10) 10 | 11 | # decrypt(encrypt(msg)) == msg 12 | for i in xrange(20): 13 | msg = os.urandom(6) 14 | assert feistel.decrypt(feistel.encrypt(msg)) == msg 15 | def test_OddLengthMessage(self): 16 | pass 17 | 18 | 19 | 20 | class TestLengthPreservingCipher: 21 | def test_Functionality(self): 22 | key = base64.urlsafe_b64encode(os.urandom(16)) 23 | lpc = LengthPreservingCipher(key, 10) 24 | 25 | # decrypt(encrypt(msg)) == msg 26 | for i in xrange(20): 27 | msg = os.urandom(6) 28 | assert lpc.decrypt(lpc.encrypt(msg)) == msg 29 | 30 | -------------------------------------------------------------------------------- /hw3/HW3AttackingPaddingOracle.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cornelltech/CS5830-Spring2017/9fdb717cc7b0171a136f5658769f701767f9a2cc/hw3/HW3AttackingPaddingOracle.pdf -------------------------------------------------------------------------------- /hw3/paddingoracle.py: -------------------------------------------------------------------------------- 1 | 2 | import os 3 | from cryptography.hazmat.primitives import hashes, padding, ciphers 4 | from cryptography.hazmat.backends import default_backend 5 | 6 | import base64 7 | import binascii 8 | 9 | def xor(a,b): 10 | """ 11 | xors two raw byte streams. 12 | """ 13 | assert len(a) == len(b), "Lengths of two strings are not same. a = {}, b = {}".format(len(a), len(b)) 14 | return ''.join(chr(ord(ai)^ord(bi)) for ai,bi in zip(a,b)) 15 | 16 | def split_into_blocks(msg, l): 17 | while msg: 18 | yield msg[:l] 19 | msg = msg[l:] 20 | 21 | class PaddingOracle(object): 22 | def __init__(self, msg_len=0): 23 | self._backend = default_backend() 24 | self._block_size_bytes = ciphers.algorithms.AES.block_size/8 25 | self._key = os.urandom(self._block_size_bytes) 26 | if msg_len>0: 27 | self._msg = os.urandom(msg_len) 28 | else: 29 | self._msg = "Top-secret message!!!!" 30 | self._ciphertext = '' 31 | 32 | def test(self, msg): 33 | """ 34 | Test whether your attack succceeded or not! 35 | """ 36 | return msg in [self._msg, self._padded_msg] 37 | 38 | def ciphertext(self): 39 | return self.setup() 40 | 41 | def setup(self): 42 | if not self._ciphertext: 43 | padder = padding.PKCS7(ciphers.algorithms.AES.block_size).padder() 44 | self._padded_msg = padded_msg = padder.update(self._msg) + padder.finalize() 45 | # print padded_msg.encode('hex') 46 | iv = os.urandom(self._block_size_bytes) 47 | encryptor = ciphers.Cipher(ciphers.algorithms.AES(self._key), 48 | ciphers.modes.CBC(iv), 49 | self._backend).encryptor() 50 | self._ciphertext = iv + encryptor.update(padded_msg) + encryptor.finalize() 51 | return self._ciphertext 52 | 53 | @property 54 | def block_length(self): 55 | return self._block_size_bytes 56 | 57 | def encrypt(self, msg): 58 | raise Exception("Encrypt is not allowed in this oracle!") 59 | 60 | def decrypt(self, ctx): 61 | iv, ctx = ctx[:self._block_size_bytes], ctx[self._block_size_bytes:] 62 | unpadder = padding.PKCS7(ciphers.algorithms.AES.block_size).unpadder() 63 | decryptor = ciphers.Cipher(ciphers.algorithms.AES(self._key), 64 | ciphers.modes.CBC(iv), 65 | self._backend).decryptor() 66 | padded_msg = decryptor.update(ctx) + decryptor.finalize() 67 | try: 68 | msg = unpadder.update(padded_msg) + unpadder.finalize() 69 | return True # Successful decryption 70 | except ValueError: 71 | return False # Error!! 72 | 73 | 74 | 75 | ################################################################################ 76 | ## The following code provides API to access padding oracle server. 77 | ################################################################################ 78 | 79 | from urllib2 import urlopen 80 | import json 81 | 82 | url = 'https://paddingoracle.herokuapp.com/' 83 | 84 | class PaddingOracleServer(object): 85 | def __init__(self, msg_len=0): 86 | self._backend = default_backend() 87 | self._block_size_bytes = ciphers.algorithms.AES.block_size/8 88 | pass 89 | 90 | @property 91 | def block_length(self): 92 | return self._block_size_bytes 93 | 94 | def decrypt(self, ctx): 95 | #print "In decrypt!!!" 96 | dec_url = url + "decrypt/{}".format(base64.urlsafe_b64encode(ctx)) 97 | ret = json.load(urlopen(dec_url)) 98 | return ret['return'] == 0 99 | 100 | def ciphertext(self): 101 | ctx_url = url + "ctx" 102 | ret = json.load(urlopen(ctx_url)) 103 | return base64.urlsafe_b64decode(str(ret['ctx'])) 104 | 105 | def test(self, msg): 106 | test_url = url + "test/{}".format(base64.urlsafe_b64encode(msg)) 107 | ret = json.load(urlopen(test_url)) 108 | return ret['return'] == 0 109 | 110 | def setup(self): 111 | return self.ciphertext() 112 | -------------------------------------------------------------------------------- /hw3/poattack.py: -------------------------------------------------------------------------------- 1 | from paddingoracle import PaddingOracle, PaddingOracleServer, xor 2 | 3 | def split_into_blocks(msg, l): 4 | while msg: 5 | yield msg[:l] 6 | msg = msg[l:] 7 | 8 | def po_attack_2blocks(po, ctx): 9 | """Given two blocks of cipher texts, it can recover the first block of 10 | the message. 11 | @po: an instance of padding oracle. 12 | @ctx: a ciphertext generated using po.setup() 13 | Don't unpad the message. 14 | """ 15 | assert len(ctx) == 2*po.block_length, "This function only accepts 2 block "\ 16 | "cipher texts. Got {} block(s)!".format(len(ctx)/po.block_length) 17 | c0, c1 = list(split_into_blocks(ctx, po.block_length)) 18 | msg = '' 19 | # TODO: Implement padding oracle attack for 2 blocks of messages. 20 | return msg 21 | 22 | def po_attack(po, ctx): 23 | """ 24 | Padding oracle attack that can decrpyt any arbitrary length messags. 25 | @po: an instance of padding oracle. 26 | @ctx: a ciphertext generated using po.setup() 27 | You don't have to unpad the message. 28 | """ 29 | ctx_blocks = list(split_into_blocks(ctx, po.block_length)) 30 | nblocks = len(ctx_blocks) 31 | # TODO: Implement padding oracle attack for arbitrary length message. 32 | 33 | 34 | 35 | ################################################################################ 36 | ##### Tests 37 | ################################################################################ 38 | 39 | def test_po_attack_2blocks(): 40 | for i in xrange(1, 16): 41 | po = PaddingOracle(msg_len=i) 42 | ctx = po.setup() 43 | msg = po_attack_2blocks(po, ctx) 44 | assert po.test(msg), "Failed 'po_attack_2blocks' for msg of length={}".format(i) 45 | 46 | def test_po_attack(): 47 | for i in xrange(1000): 48 | po = PaddingOracle(msg_len=i) 49 | ctx = po.setup() 50 | msg = po_attack(po, ctx) 51 | assert po.test(msg), "Failed 'po_attack' for msg of length={}".format(i) 52 | 53 | def test_poserver_attack(): 54 | # You may want to put some print statement in the code to see the 55 | # progress. This attack might 10.218.176.10take upto an hour to complete. 56 | 57 | po = PaddingOracleServer() 58 | ctx = po.ciphertext() 59 | msg = po_attack(po, ctx) 60 | print msg 61 | -------------------------------------------------------------------------------- /hw4/HW4PasswordBasedAuthenticatedEncryption.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cornelltech/CS5830-Spring2017/9fdb717cc7b0171a136f5658769f701767f9a2cc/hw4/HW4PasswordBasedAuthenticatedEncryption.pdf -------------------------------------------------------------------------------- /hw4/pwfernet.py: -------------------------------------------------------------------------------- 1 | import scrypt_backend 2 | 3 | 4 | # “Small” (byte 0x00): n=2^10, r=4, p=1 5 | # “Medium” (byte 0x01): n=2^10, r=6, p=1 6 | # “Large” (byte 0x02): n=2^11, r=8, p=1 7 | # “Extra large” (byte 0x03): n=2^12, r=8, p=2 8 | 9 | 10 | class Sizes: 11 | small = (2**10, 4, 1) 12 | medium = (2**10, 6, 1) 13 | large = (2**11, 8, 1) 14 | xlarge = (2**12, 8, 2) 15 | 16 | class PWFernet: 17 | def __init__(self, pw): 18 | self.password = pw 19 | self.backend = MultiBackend([NewScryptBackend(), default_backend()]) 20 | 21 | def encrypt(self, message): 22 | pass 23 | 24 | def decrypt(self, ciphertext): 25 | pass 26 | -------------------------------------------------------------------------------- /hw4/scrypt_backend.py: -------------------------------------------------------------------------------- 1 | import struct 2 | from cryptography.hazmat.primitives.kdf.scrypt import Scrypt 3 | from cryptography.hazmat.backends import default_backend,MultiBackend 4 | from cryptography.hazmat.primitives import hashes,hmac 5 | from cryptography.hazmat.backends.interfaces import ScryptBackend 6 | import functools 7 | import binascii 8 | 9 | #Actual python implementation of Scrypt taken from 10 | #https://github.com/ricmoo/pyscrypt. 11 | #Shim wrapper to make it a pyca backend written by 12 | #Paul Grubbs. 13 | 14 | 15 | # Python 2 16 | if bytes == str: 17 | def check_bytes(byte_array): 18 | return True 19 | 20 | def get_byte(c): 21 | 'Converts a 1-byte string to a byte' 22 | return ord(c) 23 | 24 | def chars_to_bytes(array): 25 | 'Converts an array of integers to an array of bytes.' 26 | return ''.join(chr(c) for c in array) 27 | 28 | # Python 3 29 | else: 30 | xrange = range 31 | 32 | def check_bytes(byte_array): 33 | return isinstance(byte_array, bytes) 34 | 35 | def get_byte(c): 36 | return c 37 | 38 | def chars_to_bytes(array): 39 | return bytes(array) 40 | 41 | 42 | def pbkdf2_single(password, salt, key_length, prf): 43 | '''Returns the result of the Password-Based Key Derivation Function 2 with 44 | a single iteration (i.e. count = 1). 45 | 46 | prf - a psuedorandom function 47 | 48 | See http://en.wikipedia.org/wiki/PBKDF2 49 | ''' 50 | 51 | block_number = 0 52 | result = b'' 53 | 54 | # The iterations 55 | while len(result) < key_length: 56 | block_number += 1 57 | result += prf(password, salt + struct.pack('>L', block_number)) 58 | 59 | return result[:key_length] 60 | 61 | 62 | def salsa20_8(B): 63 | '''Salsa 20/8 stream cypher; Used by BlockMix. See http://en.wikipedia.org/wiki/Salsa20''' 64 | 65 | # Create a working copy 66 | x = B[:] 67 | 68 | # Expanded form of this code. The expansion is significantly faster but 69 | # this is much easier to understand 70 | # ROUNDS = ( 71 | # (4, 0, 12, 7), (8, 4, 0, 9), (12, 8, 4, 13), (0, 12, 8, 18), 72 | # (9, 5, 1, 7), (13, 9, 5, 9), (1, 13, 9, 13), (5, 1, 13, 18), 73 | # (14, 10, 6, 7), (2, 14, 10, 9), (6, 2, 14, 13), (10, 6, 2, 18), 74 | # (3, 15, 11, 7), (7, 3, 15, 9), (11, 7, 3, 13), (15, 11, 7, 18), 75 | # (1, 0, 3, 7), (2, 1, 0, 9), (3, 2, 1, 13), (0, 3, 2, 18), 76 | # (6, 5, 4, 7), (7, 6, 5, 9), (4, 7, 6, 13), (5, 4, 7, 18), 77 | # (11, 10, 9, 7), (8, 11, 10, 9), (9, 8, 11, 13), (10, 9, 8, 18), 78 | # (12, 15, 14, 7), (13, 12, 15, 9), (14, 13, 12, 13), (15, 14, 13, 18), 79 | # ) 80 | # 81 | # for (destination, a1, a2, b) in ROUNDS: 82 | # a = (x[a1] + x[a2]) & 0xffffffff 83 | # x[destination] ^= ((a << b) | (a >> (32 - b))) & 0xffffffff 84 | for i in (8, 6, 4, 2): 85 | a = (x[0] + x[12]) & 0xffffffff 86 | x[4] ^= ((a << 7) | (a >> 25)) 87 | a = (x[4] + x[0]) & 0xffffffff 88 | x[8] ^= ((a << 9) | (a >> 23)) 89 | a = (x[8] + x[4]) & 0xffffffff 90 | x[12] ^= ((a << 13) | (a >> 19)) 91 | a = (x[12] + x[8]) & 0xffffffff 92 | x[0] ^= ((a << 18) | (a >> 14)) 93 | a = (x[5] + x[1]) & 0xffffffff 94 | x[9] ^= ((a << 7) | (a >> 25)) 95 | a = (x[9] + x[5]) & 0xffffffff 96 | x[13] ^= ((a << 9) | (a >> 23)) 97 | a = (x[13] + x[9]) & 0xffffffff 98 | x[1] ^= ((a << 13) | (a >> 19)) 99 | a = (x[1] + x[13]) & 0xffffffff 100 | x[5] ^= ((a << 18) | (a >> 14)) 101 | a = (x[10] + x[6]) & 0xffffffff 102 | x[14] ^= ((a << 7) | (a >> 25)) 103 | a = (x[14] + x[10]) & 0xffffffff 104 | x[2] ^= ((a << 9) | (a >> 23)) 105 | a = (x[2] + x[14]) & 0xffffffff 106 | x[6] ^= ((a << 13) | (a >> 19)) 107 | a = (x[6] + x[2]) & 0xffffffff 108 | x[10] ^= ((a << 18) | (a >> 14)) 109 | a = (x[15] + x[11]) & 0xffffffff 110 | x[3] ^= ((a << 7) | (a >> 25)) 111 | a = (x[3] + x[15]) & 0xffffffff 112 | x[7] ^= ((a << 9) | (a >> 23)) 113 | a = (x[7] + x[3]) & 0xffffffff 114 | x[11] ^= ((a << 13) | (a >> 19)) 115 | a = (x[11] + x[7]) & 0xffffffff 116 | x[15] ^= ((a << 18) | (a >> 14)) 117 | a = (x[0] + x[3]) & 0xffffffff 118 | x[1] ^= ((a << 7) | (a >> 25)) 119 | a = (x[1] + x[0]) & 0xffffffff 120 | x[2] ^= ((a << 9) | (a >> 23)) 121 | a = (x[2] + x[1]) & 0xffffffff 122 | x[3] ^= ((a << 13) | (a >> 19)) 123 | a = (x[3] + x[2]) & 0xffffffff 124 | x[0] ^= ((a << 18) | (a >> 14)) 125 | a = (x[5] + x[4]) & 0xffffffff 126 | x[6] ^= ((a << 7) | (a >> 25)) 127 | a = (x[6] + x[5]) & 0xffffffff 128 | x[7] ^= ((a << 9) | (a >> 23)) 129 | a = (x[7] + x[6]) & 0xffffffff 130 | x[4] ^= ((a << 13) | (a >> 19)) 131 | a = (x[4] + x[7]) & 0xffffffff 132 | x[5] ^= ((a << 18) | (a >> 14)) 133 | a = (x[10] + x[9]) & 0xffffffff 134 | x[11] ^= ((a << 7) | (a >> 25)) 135 | a = (x[11] + x[10]) & 0xffffffff 136 | x[8] ^= ((a << 9) | (a >> 23)) 137 | a = (x[8] + x[11]) & 0xffffffff 138 | x[9] ^= ((a << 13) | (a >> 19)) 139 | a = (x[9] + x[8]) & 0xffffffff 140 | x[10] ^= ((a << 18) | (a >> 14)) 141 | a = (x[15] + x[14]) & 0xffffffff 142 | x[12] ^= ((a << 7) | (a >> 25)) 143 | a = (x[12] + x[15]) & 0xffffffff 144 | x[13] ^= ((a << 9) | (a >> 23)) 145 | a = (x[13] + x[12]) & 0xffffffff 146 | x[14] ^= ((a << 13) | (a >> 19)) 147 | a = (x[14] + x[13]) & 0xffffffff 148 | x[15] ^= ((a << 18) | (a >> 14)) 149 | 150 | 151 | # Add the original values 152 | for i in xrange(0, 16): 153 | B[i] = (B[i] + x[i]) & 0xffffffff 154 | 155 | 156 | def blockmix_salsa8(BY, Yi, r): 157 | '''Blockmix; Used by SMix.''' 158 | 159 | start = (2 * r - 1) * 16 160 | X = BY[start:start + 16] # BlockMix - 1 161 | 162 | for i in xrange(0, 2 * r): # BlockMix - 2 163 | 164 | for xi in xrange(0, 16): # BlockMix - 3(inner) 165 | X[xi] ^= BY[i * 16 + xi] 166 | 167 | salsa20_8(X) # BlockMix - 3(outer) 168 | aod = Yi + i * 16 # BlockMix - 4 169 | BY[aod:aod + 16] = X[:16] 170 | 171 | for i in xrange(0, r): # BlockMix - 6 (and below) 172 | aos = Yi + i * 32 173 | aod = i * 16 174 | BY[aod:aod + 16] = BY[aos:aos + 16] 175 | 176 | for i in xrange(0, r): 177 | aos = Yi + (i * 2 + 1) * 16 178 | aod = (i + r) * 16 179 | BY[aod:aod + 16] = BY[aos:aos + 16] 180 | 181 | 182 | def smix(B, Bi, r, N, V, X): 183 | '''SMix; a specific case of ROMix. See scrypt.pdf in the links above.''' 184 | 185 | X[:32 * r] = B[Bi:Bi + 32 * r] # ROMix - 1 186 | 187 | for i in xrange(0, N): # ROMix - 2 188 | aod = i * 32 * r # ROMix - 3 189 | V[aod:aod + 32 * r] = X[:32 * r] 190 | blockmix_salsa8(X, 32 * r, r) # ROMix - 4 191 | 192 | for i in xrange(0, N): # ROMix - 6 193 | j = X[(2 * r - 1) * 16] & (N - 1) # ROMix - 7 194 | for xi in xrange(0, 32 * r): # ROMix - 8(inner) 195 | X[xi] ^= V[j * 32 * r + xi] 196 | 197 | blockmix_salsa8(X, 32 * r, r) # ROMix - 9(outer) 198 | 199 | B[Bi:Bi + 32 * r] = X[:32 * r] # ROMix - 10 200 | 201 | 202 | def hmac_prf(k, m, _backend): 203 | h = hmac.HMAC(k, hashes.SHA256(), _backend) 204 | h.update(m) 205 | return h.finalize() 206 | 207 | class NewScryptBackend(ScryptBackend): 208 | def __init__(self): 209 | self.backend = default_backend() 210 | 211 | 212 | #def hash(self, password, salt, N, r, p, dkLen): 213 | def derive_scrypt(self, key_material, salt, length, n, r, p): 214 | password = key_material 215 | dkLen = length 216 | N = n 217 | """Returns the result of the scrypt password-based key derivation function. 218 | 219 | Constraints: 220 | r * p < (2 ** 30) 221 | dkLen <= (((2 ** 32) - 1) * 32 222 | N must be a power of 2 greater than 1 (eg. 2, 4, 8, 16, 32...) 223 | N, r, p must be positive 224 | """ 225 | 226 | # This only matters to Python 3 227 | if not check_bytes(password): 228 | raise ValueError('password must be a byte array') 229 | 230 | if not check_bytes(salt): 231 | raise ValueError('salt must be a byte array') 232 | 233 | # Scrypt implementation. Significant thanks to https://github.com/wg/scrypt 234 | if N < 2 or (N & (N - 1)): raise ValueError('Scrypt N must be a power of 2 greater than 1') 235 | 236 | # A psuedorandom function 237 | #prf = lambda k, m: hmac.new(key = k, msg = m, digestmod = hashlib.sha256).digest() 238 | prf = functools.partial(hmac_prf, _backend=self.backend) 239 | # convert into integers 240 | B = [ get_byte(c) for c in pbkdf2_single(password, salt, p * 128 * r, prf) ] 241 | B = [ ((B[i + 3] << 24) | (B[i + 2] << 16) | (B[i + 1] << 8) | B[i + 0]) for i in xrange(0, len(B), 4)] 242 | 243 | XY = [ 0 ] * (64 * r) 244 | V = [ 0 ] * (32 * r * N) 245 | 246 | for i in xrange(0, p): 247 | smix(B, i * 32 * r, r, N, V, XY) 248 | 249 | # Convert back into bytes 250 | Bc = [ ] 251 | for i in B: 252 | Bc.append((i >> 0) & 0xff) 253 | Bc.append((i >> 8) & 0xff) 254 | Bc.append((i >> 16) & 0xff) 255 | Bc.append((i >> 24) & 0xff) 256 | 257 | return pbkdf2_single(password, chars_to_bytes(Bc), dkLen, prf) 258 | 259 | 260 | 261 | 262 | 263 | if __name__=='__main__': 264 | Tests = [ 265 | dict(password = b'password', salt = b'salt', N = 2, r = 1, p = 1, dkLen = 32, result = '6d1bb878eee9ce4a7b77d7a44103574d4cbfe3c15ae3940f0ffe75cd5e1e0afa'), 266 | dict(password = b'password', salt = b'salt', N = 32, r = 4, p = 15, dkLen = 128, result = '19f255f7dbcc4128e3467c78c795cb934a82bb813793d2634f6e3adbaee1f54b118fca8b067ab4aad3f6557c716b3734bb93a5cb40500b5e42dc96ccee260fc64d8e660b80e7aecd81c83fefedaf1319b6265e6ef37ca268247052f0b5cac91d14800c1b6f8cb23a28f4620aa0a8e12de88906ec5755a4a643917947a010b7bf'), 267 | dict(password = b'password', salt = b'salt', N = 128, r = 3, p = 3, dkLen = 45, result = 'bdbefc353d2145625af2d8f86dad13d6bd993daabbb39a740887ff985803a22675284ad4c3ab5f68a779d0b71a'), 268 | dict(password = b'password', salt = b'salt', N = 256, r = 6, p = 2, dkLen = 100, result = '08d4bd8bc6a0db2d3afb86e14bb3e219c7e067add953576ebc4678f86c85f5bc819de1fe22877c7d98c2ee11fef9f3a1ca0047a079b3ee35152c31d51b8db57f267050255065b933d65edfc65203e9b964c5c54507eba8b990c8c9106274fa105237550a'), 269 | dict(password = b"You're a master of Karate", salt = b'And friendship for Everyone', N = 1024, r = 1, p = 1, dkLen = 256, result = '3a3cbca04456f6ee5295460171a2a2b27e1c28163999f19ab1e2eeda01e355d904627c6baa185087f99f3fee33e4a9ccad1f4230681d77301d2b4f6543023e090faf6e86431a1071f64b693402ceb485469ef33308af104fb1f87b39ecaf733ebc3d73b184c0914fbc4e8eff90777c60172596de79070418f3c9998b6b60640f1d8f3019904b3e20f2920d26c21daf81d0652ffcaffccf734773e0730900204b56b5bebbfb8c3a31d543f6e3ac5f4e1431a864da87c239eefec8e462d458ee2d214646864e9207e15f66a3782b52bb5158152d757d0ca25d2062235ee76c431e5016b3a52cd5b575e3a26aba95654d5b9a991527f5a19d7275ac4f9889081ee9'), 270 | ] 271 | 272 | for test in Tests: 273 | multi_backend = MultiBackend([NewScryptBackend(), default_backend()]) 274 | kdf = Scrypt(salt=test['salt'],length=test['dkLen'],n=test['N'],r=test['r'],p=test['p'],backend=multi_backend) 275 | correct = test['result'] 276 | derived = kdf.derive(test['password']) 277 | print correct 278 | print binascii.hexlify(derived) 279 | print "\n\n" 280 | assert correct == binascii.hexlify(derived) 281 | -------------------------------------------------------------------------------- /hw5/HW5TLSServerSetup.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cornelltech/CS5830-Spring2017/9fdb717cc7b0171a136f5658769f701767f9a2cc/hw5/HW5TLSServerSetup.pdf -------------------------------------------------------------------------------- /hw6/hw6.md: -------------------------------------------------------------------------------- 1 | # Public-key encryption 2 | ```json 3 | Deadline: 23:59:59, May 17, 2017 4 | ``` 5 | We want to build an application layer public key encryption scheme that will allow users to send messages asynchronously with others without a pre-shared secret key. A typical way to do this is using a hybrid of public-key and symmetric-key encryption schemes. The symmetric encryption portion of this can utilize our existing Fernet2 encryption scheme. While for the public-key part of it, we shall use one or more asymmetric encryption schemes supported by the `cryptography` library. Let call this encryption scheme `PKFernet`. 6 | 7 | ### Functionality 8 | We expect the following basic functionalities from `PKFernet`. 9 | The scheme allows users to `encrypt` and `decrypt` messages. The `encryption` routine should first sign the message using the sender’s secret key for signing, and then encrypt the signed message using the public key for encryption of the recipient. The recipient should be able `decrypt` and verify the message using his private key for encryption and public for signing of the sender respectively. 10 | `PKFernet` should be cryptographically agile, i.e., it should be able to adapt to new cryptographic primitives. Users might choose to use different cryptographic primitives, and may or may not choose to be backward compatible. But the scheme should gracefully handle (process or reject) different versions of ciphertexts. 11 | 12 | ### Specification? 13 | As this encryption scheme explicitly attempts to enable a global communication of encrypted messages, we have to decide on a global protocol and specification. We shall assume that we already have a medium of communication, and only need to decide on the specification of the encryption scheme. However, remember that the specification should be without ambiguities, should be democratically selected, and every one must follow it. 14 | 15 | A draft specification will be made available on Slack. It is from last year’s class, and while it was pretty complete, it still had some problems. Please review the draft and make suggestions by adding comments. One way to do this is think about how you’ll implement the draft, and see where ambiguities come up --- any time you encounter an ambiguity leave a comment in the appropriate location of the draft. We can then refine the spec; *refinements will be made only until May 10th*. All discussion of the draft will be among the whole group; individuals should work on their own implementations and not share code. 16 | 17 | The final implementations will be cross-tested, that is an encrypted message 18 | from one person’s implementation will be decrypted using another person’s 19 | implementation. We will set up another shared Google spreadsheet for sample 20 | plaintext-ciphertexts pairs from each individual. 21 | 22 | 23 | 24 | ### Points breakdown 25 | Here is the (high-level) point breakup for the HW5: 26 | * Earn 30 points for helping refine the detailed specification for the encryption scheme and message format, and writing tests for your implementation. 27 | * You may get docked points for violating specifications that we decide collectively. 28 | * You will get 50 points for implementing the scheme that works with at least itself--it should pass the basic functionality tests. 29 | * Finally, 20 points will awarded if the scheme works with at least two other implementations (including the TA’s). 30 | * Extra credit: 10 points for supporting each additional cryptographic primitives capped at 50 points. For example, Encryption (key encapsulation part) if you can handle ECC based DH, and RSA, you will get 20 extra points. If you support ECDSA, DSA, and RSA-based signature schemes, you will get 20 extra points. If you can support different ECC curves (the ones supported by cryptography.io), and different hashing algorithms, you will earn 10 more marks. 31 | 32 | 33 | 34 | ### Shared documents 35 | * [Specification doc](https://docs.google.com/document/d/1DFQ70_JkO3vuxvjTK4A7mBQkdwQrgy_Kmbn9tjoFcb4/edit) 36 | Use this doc to discuss about the common specification for the encryption scheme. 37 | 38 | * TBA soon: spreadsheet for ciphertext compatibility checking 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /slides/backdoors.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cornelltech/CS5830-Spring2017/9fdb717cc7b0171a136f5658769f701767f9a2cc/slides/backdoors.pdf -------------------------------------------------------------------------------- /slides/censorship.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cornelltech/CS5830-Spring2017/9fdb717cc7b0171a136f5658769f701767f9a2cc/slides/censorship.pdf -------------------------------------------------------------------------------- /slides/cryptodev.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cornelltech/CS5830-Spring2017/9fdb717cc7b0171a136f5658769f701767f9a2cc/slides/cryptodev.pdf -------------------------------------------------------------------------------- /slides/ctr-blockcipher.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cornelltech/CS5830-Spring2017/9fdb717cc7b0171a136f5658769f701767f9a2cc/slides/ctr-blockcipher.pdf -------------------------------------------------------------------------------- /slides/ctr-mode.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cornelltech/CS5830-Spring2017/9fdb717cc7b0171a136f5658769f701767f9a2cc/slides/ctr-mode.pdf -------------------------------------------------------------------------------- /slides/dh.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cornelltech/CS5830-Spring2017/9fdb717cc7b0171a136f5658769f701767f9a2cc/slides/dh.pdf -------------------------------------------------------------------------------- /slides/digsigs.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cornelltech/CS5830-Spring2017/9fdb717cc7b0171a136f5658769f701767f9a2cc/slides/digsigs.pdf -------------------------------------------------------------------------------- /slides/digsigs2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cornelltech/CS5830-Spring2017/9fdb717cc7b0171a136f5658769f701767f9a2cc/slides/digsigs2.pdf -------------------------------------------------------------------------------- /slides/ecc.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cornelltech/CS5830-Spring2017/9fdb717cc7b0171a136f5658769f701767f9a2cc/slides/ecc.pdf -------------------------------------------------------------------------------- /slides/hash.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cornelltech/CS5830-Spring2017/9fdb717cc7b0171a136f5658769f701767f9a2cc/slides/hash.pdf -------------------------------------------------------------------------------- /slides/hybrid.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cornelltech/CS5830-Spring2017/9fdb717cc7b0171a136f5658769f701767f9a2cc/slides/hybrid.pdf -------------------------------------------------------------------------------- /slides/intro.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cornelltech/CS5830-Spring2017/9fdb717cc7b0171a136f5658769f701767f9a2cc/slides/intro.pdf -------------------------------------------------------------------------------- /slides/msgauth.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cornelltech/CS5830-Spring2017/9fdb717cc7b0171a136f5658769f701767f9a2cc/slides/msgauth.pdf -------------------------------------------------------------------------------- /slides/otp.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cornelltech/CS5830-Spring2017/9fdb717cc7b0171a136f5658769f701767f9a2cc/slides/otp.pdf -------------------------------------------------------------------------------- /slides/padoracle.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cornelltech/CS5830-Spring2017/9fdb717cc7b0171a136f5658769f701767f9a2cc/slides/padoracle.pdf -------------------------------------------------------------------------------- /slides/pwae.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cornelltech/CS5830-Spring2017/9fdb717cc7b0171a136f5658769f701767f9a2cc/slides/pwae.pdf -------------------------------------------------------------------------------- /slides/rng.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cornelltech/CS5830-Spring2017/9fdb717cc7b0171a136f5658769f701767f9a2cc/slides/rng.pdf -------------------------------------------------------------------------------- /slides/rsa.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cornelltech/CS5830-Spring2017/9fdb717cc7b0171a136f5658769f701767f9a2cc/slides/rsa.pdf -------------------------------------------------------------------------------- /slides/symenc.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cornelltech/CS5830-Spring2017/9fdb717cc7b0171a136f5658769f701767f9a2cc/slides/symenc.pdf -------------------------------------------------------------------------------- /slides/tls.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cornelltech/CS5830-Spring2017/9fdb717cc7b0171a136f5658769f701767f9a2cc/slides/tls.pdf --------------------------------------------------------------------------------