diff --git a/syllabus/1-Cryptography/materials/aes-modes-activity/Cargo.lock b/syllabus/1-Cryptography/materials/aes-modes-activity/Cargo.lock index 67d465cb3..85a91da36 100644 --- a/syllabus/1-Cryptography/materials/aes-modes-activity/Cargo.lock +++ b/syllabus/1-Cryptography/materials/aes-modes-activity/Cargo.lock @@ -1,93 +1,2 @@ -# This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 - -[[package]] -name = "aes" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfe0133578c0986e1fe3dfcd4af1cc5b2dd6c3dbf534d69916ce16a2701d40ba" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - -[[package]] -name = "aes-modes" -version = "0.1.0" -dependencies = [ - "aes", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "cipher" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1873270f8f7942c191139cb8a40fd228da6c3fd2fc376d7e92d47aa14aeb59e" -dependencies = [ - "crypto-common", - "inout", -] - -[[package]] -name = "cpufeatures" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" -dependencies = [ - "libc", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "generic-array" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "inout" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" -dependencies = [ - "generic-array", -] - -[[package]] -name = "libc" -version = "0.2.126" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" - -[[package]] -name = "typenum" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" diff --git a/syllabus/1-Cryptography/materials/aes-modes-activity/Cargo.toml b/syllabus/1-Cryptography/materials/aes-modes-activity/Cargo.toml deleted file mode 100644 index 96cb85ca3..000000000 --- a/syllabus/1-Cryptography/materials/aes-modes-activity/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "aes-modes" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -aes = "0.8.1" \ No newline at end of file diff --git a/syllabus/1-Cryptography/materials/aes-modes-activity/src/main.rs b/syllabus/1-Cryptography/materials/aes-modes-activity/src/main.rs deleted file mode 100644 index 25111df66..000000000 --- a/syllabus/1-Cryptography/materials/aes-modes-activity/src/main.rs +++ /dev/null @@ -1,167 +0,0 @@ -//! In Module 1, we discussed Block ciphers like AES. Block ciphers have a fixed length input. -//! Real wold data that we wish to encrypt _may_ be exactly the right length, but is probably not. -//! When your data is too short, you can simply pad it up to the correct length. -//! When your data is too long, you have some options. -//! -//! In this exercise, we will explore a few of the common ways that large pieces of data can be -//! broken up and combined in order to encrypt it with a fixed-length block cipher. -//! -//! WARNING: ECB MODE IS NOT SECURE. -//! Seriously, ECB is NOT secure. Don't use it irl. We are implementing it here to understand _why_ -//! it is not secure and make the point that the most straight-forward approach isn't always the -//! best, and can sometimes be trivially broken. - -use aes::{ - cipher::{generic_array::GenericArray, BlockCipher, BlockDecrypt, BlockEncrypt, KeyInit}, - Aes128, -}; - -///We're using AES 128 which has 16-byte (128 bit) blocks. -const BLOCK_SIZE: usize = 16; - -fn main() { - todo!("Maybe this should be a library crate. TBD"); -} - -/// Simple AES encryption -/// Helper function to make the core AES block cipher easier to understand. -fn aes_encrypt(data: [u8; BLOCK_SIZE], key: &[u8; BLOCK_SIZE]) -> [u8; BLOCK_SIZE] { - // Convert the inputs to the necessary data type - let mut block = GenericArray::from(data); - let key = GenericArray::from(*key); - - let cipher = Aes128::new(&key); - - cipher.encrypt_block(&mut block); - - block.into() -} - -/// Simple AES encryption -/// Helper function to make the core AES block cipher easier to understand. -fn aes_decrypt(data: [u8; BLOCK_SIZE], key: &[u8; BLOCK_SIZE]) -> [u8; BLOCK_SIZE] { - // Convert the inputs to the necessary data type - let mut block = GenericArray::from(data); - let key = GenericArray::from(*key); - - let cipher = Aes128::new(&key); - - cipher.decrypt_block(&mut block); - - block.into() -} - -/// Before we can begin encrypting our raw data, we need it to be a multiple of the -/// block length which is 16 bytes (128 bits) in AES128. -/// -/// The padding algorithm here is actually not trivial. The trouble is that if we just -/// naively throw a bunch of zeros on the end, there is no way to know, later, whether -/// those zeros are padding, or part of the message, or some of each. -/// -/// The scheme works like this. If the data is not a multiple of the block length, we -/// compute how many pad bytes we need, and then write that number into the last several bytes. -/// Later we look at the last byte, and remove that number of bytes. -/// -/// But if the data _is_ a multiple of the block length, then we have a problem. We don't want -/// to later look at the last byte and remove part of the data. Instead, in this case, we add -/// another entire block containing the block length in each byte. In our case, -/// [16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16] -fn pad(mut data: Vec) -> Vec { - // When twe have a multiple the second term is 0 - let number_pad_bytes = BLOCK_SIZE - data.len() % BLOCK_SIZE; - - for _ in 0..number_pad_bytes { - data.push(number_pad_bytes as u8); - } - - data -} - -/// Groups the data into BLOCK_SIZE blocks. Assumes the data is already -/// a multiple of the block size. If this is not the case, call `pad` first. -fn group(data: Vec) -> Vec<[u8; BLOCK_SIZE]> { - let mut blocks = Vec::new(); - let mut i = 0; - while i < data.len() { - let mut block: [u8; BLOCK_SIZE] = Default::default(); - block.copy_from_slice(&data[i..i + BLOCK_SIZE]); - blocks.push(block); - - i += BLOCK_SIZE; - } - - blocks -} - -/// Does the opposite of the group function -fn un_group(blocks: Vec<[u8; BLOCK_SIZE]>) -> Vec { - todo!() -} - -/// Does the opposite of the pad function. -fn un_pad(data: Vec) -> Vec { - todo!() -} - -/// The first mode we will implement is the Electronic Code Book, or ECB mode. -/// Warning: THIS MODE IS NOT SECURE!!!! -/// -/// This is probably the first thing you think of when considering how to encrypt -/// large data. In this mode we simply encrypt each block of data under the same key. -/// One good thing about this mode is that it is parallelizable. But to see why it is -/// insecure look at: https://www.ubiqsecurity.com/wp-content/uploads/2022/02/ECB2.png -fn ecb_encrypt(plain_text: Vec, key: [u8; 16]) -> Vec { - todo!() -} - -/// Opposite of ecb_encrypt. -fn ecb_decrypt(cipher_text: Vec, key: [u8; BLOCK_SIZE]) -> Vec { - todo!() -} - -/// The next mode, which you can implement on your own is cipherblock chaining. -/// This mode actually is secure, and it often used in real world applications. -/// -/// In this mode, the ciphertext from the first block is XORed with the -/// plaintext of the next block before it is encrypted. -/// -/// For more information, and a very clear diagram, -/// see https://de.wikipedia.org/wiki/Cipher_Block_Chaining_Mode -/// -/// You will need to generate a random initialization vector (IV) to encrypt the -/// very first block because it doesn't have a previous block. Typically this IV -/// is inserted as the first block of ciphertext. -fn cbc_encrypt(plain_text: Vec, key: [u8; BLOCK_SIZE]) -> Vec { - // Remember to generate a random initialization vector for the first block. - - todo!() -} - -fn cbc_decrypt(cipher_text: Vec, key: [u8; BLOCK_SIZE]) -> Vec { - todo!() -} - -/// Another mode which you can implement on your own is counter mode. -/// This mode is secure as well, and is used in real world applications. -/// It allows parallelized encryption and decryption, as well as random read access when decrypting. -/// -/// In this mode, there is an index for each block being encrypted (the "counter"), as well as a random nonce. -/// For a 128-bit cipher, the nonce is 64 bits long. -/// -/// For the ith block, the 128-bit value V of `nonce | counter` is constructed, where | denotes -/// concatenation. Then, V is encrypted with the key using ECB mode. Finally, the encrypted V is -/// XOR'd with the plaintext to produce the ciphertext. -/// -/// A very clear diagram is present here: -/// https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_(CTR) -/// -/// Once again, you will need to generate a random nonce which is 64 bits long. This should be -/// inserted as the first block of the ciphertext. -fn ctr_encrypt(plain_text: Vec, key: [u8; BLOCK_SIZE]) -> Vec { - // Remember to generate a random nonce - todo!() -} - -fn ctr_decrypt(cipher_text: Vec, key: [u8; BLOCK_SIZE]) -> Vec { - todo!() -} diff --git a/syllabus/1-Cryptography/materials/merkle-tree-activity/Cargo.lock b/syllabus/1-Cryptography/materials/merkle-tree-activity/Cargo.lock deleted file mode 100644 index 189b63183..000000000 --- a/syllabus/1-Cryptography/materials/merkle-tree-activity/Cargo.lock +++ /dev/null @@ -1,7 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "merkle-tree" -version = "0.1.0" diff --git a/syllabus/1-Cryptography/materials/merkle-tree-activity/Cargo.toml b/syllabus/1-Cryptography/materials/merkle-tree-activity/Cargo.toml deleted file mode 100644 index bbba1ff10..000000000 --- a/syllabus/1-Cryptography/materials/merkle-tree-activity/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "merkle-tree" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/syllabus/1-Cryptography/materials/merkle-tree-activity/src/main.rs b/syllabus/1-Cryptography/materials/merkle-tree-activity/src/main.rs deleted file mode 100644 index 0f89ac54d..000000000 --- a/syllabus/1-Cryptography/materials/merkle-tree-activity/src/main.rs +++ /dev/null @@ -1,83 +0,0 @@ -//! This is minimal Merkle tree implementation with proof checking - -use std::{ - collections::hash_map::DefaultHasher, - hash::{Hash, Hasher}, -}; - -fn main() { - let s = ""; - let h = hash(&s); - println!("{}", h); -} - -/// We'll use Rust's built-in hashing which returns a u64 type. -/// This alias just helps us understand when we're treating the number as a hash -type HashValue = u64; - -/// Helper function that makes the hashing interface easier to understand. -fn hash(t: &T) -> HashValue { - let mut s = DefaultHasher::new(); - t.hash(&mut s); - s.finish() -} - -/// Given a vector of data blocks this function adds padding blocks to the end -/// until the length is a power of two which is needed for Merkle trees. -fn pad_base_layer(blocks: &mut Vec<&str>) { - todo!() -} - -/// Helper function to combine two hashes and compute the hash of the combination. -/// This will be useful when building the intermediate nodes in the Merkle tree. -/// -/// There are many correct ways to do this, but the easiest one and the one that I recommend -/// is to convert the hashes to strings and concatenate them. -fn concatenate_hash_values(left: HashValue, right: HashValue) -> HashValue { - todo!() -} - -/// Calculates the Merkle root of a sentence. We consider each word in the sentence to -/// be one block. Words are separated by one or more spaces. -/// -/// Example: -/// Sentence: "Trust me, bro!" -/// "Trust", "me," "bro!" -/// Notice that the punctuation like the comma and exclamation point are included in the words -/// but the spaces are not. -fn calculate_merkle_root(sentence: &str) -> HashValue { - todo!() -} - -/// A representation of a sibling node along the Merkle path from the data -/// to the root. It is necessary to specify which side the sibling is on -/// so that the hash values can be combined in the same order. -enum SiblingNode { - Left(HashValue), - Right(HashValue), -} - -/// Generates a Merkle proof that one particular word is contained -/// in the given sentence. You provide the sentence and the index of the word -/// which you want a proof. -/// -/// Panics if the index is beyond the length of the word. -/// -/// Example: I want to prove that the word "Trust" is in the sentence "Trust me, bro!" -/// So I call generate_proof("Trust me, bro!", 0) -/// And I get back the merkle root and list of intermediate nodes from which the -/// root can be reconstructed. -fn generate_proof(sentence: &str, index: usize) -> (HashValue, Vec) { - todo!() -} - -/// Checks whether the given word is contained in a sentence, without knowing the whole sentence. -/// Rather we only know the merkle root of the sentence and a proof. -fn validate_proof(root: &str, word: &str, proof: Vec) -> bool { - todo!() -} - -#[test] -fn we_should_probably_have_some_tests() { - todo!() -}