Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: cipher modes of operation #127

Merged
merged 20 commits into from
Jul 8, 2024
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ edition ="2021"
license ="Apache2.0 OR MIT"
name ="ronkathon"
repository ="https://github.com/thor314/ronkathon"
version = "0.1.0"
version ="0.1.0"

[dependencies]
rand ="0.8.5"
Expand All @@ -18,12 +18,15 @@ pretty_assertions ="1.4.0"
sha2 ="0.10.8"
ark-ff ={ version="^0.4.0", features=["std"] }
ark-crypto-primitives={ version="0.4.0", features=["sponge"] }
des = "0.8.1"
chacha20 = "0.9.1"
des ="0.8.1"
chacha20 ="0.9.1"

[patch.crates-io]
ark-ff ={ git="https://github.com/arkworks-rs/algebra/" }
ark-ec ={ git="https://github.com/arkworks-rs/algebra/" }
ark-poly ={ git="https://github.com/arkworks-rs/algebra/" }
ark-serialize={ git="https://github.com/arkworks-rs/algebra/" }
ark-std ={ git="https://github.com/arkworks-rs/std/" }

[[example]]
name="aes_chained_cbc"
72 changes: 72 additions & 0 deletions examples/aes_chained_cbc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
//! Demonstrating AES chained CBC mode of operation where last ciphertext of previous operation is
//! used as IV for next operation. This has advantage as it reduces the bandwidth to share a new IV
//! each time between the parties. But in CBC mode, IV should be unpredictable, this was formalised in [CWE-329](https://cwe.mitre.org/data/definitions/329.html).
//!
//! But this scheme is not Chosen-Plaintext Attack secure and any
//! attacker can detect which original message was used in the ciphertext which is shown here.
#![allow(incomplete_features)]
#![feature(generic_const_exprs)]
use rand::{thread_rng, Rng};
use ronkathon::encryption::symmetric::{
aes::{Block, Key, AES},
modes::cbc::CBC,
};

fn attacker_chosen_message() -> [&'static [u8]; 2] {
[b"You're gonna be pwned!", b"HAHA, You're gonna be dbl pwned!!"]
}

fn xor_blocks(a: &mut [u8], b: &[u8]) {
for (x, y) in a.iter_mut().zip(b) {
*x ^= *y;
}
}

fn attacker<'a>(key: &Key<128>, iv: &Block, ciphertext: Vec<u8>) -> &'a [u8] {
// Chose 2 random messages, {m_0, m_1}
let messages = attacker_chosen_message();

// first blocks' ciphertext
let c1 = &ciphertext[..16];

// select new IV as last blocks' ciphertext and intiate CBC with AES again with new IV
let new_iv: [u8; 16] = ciphertext[ciphertext.len() - 16..].try_into().unwrap();
let cbc2 = CBC::<AES<128>>::new(Block(new_iv));

// Now, attacker selects the new message m_4 = IV ⨁ m_0 ⨁ NEW_IV
let mut pwned_message = iv.0;
xor_blocks(&mut pwned_message, messages[0]);
xor_blocks(&mut pwned_message, &new_iv);

// attacker receives ciphertext from encryption oracle
let encrypted = cbc2.encrypt(key, &pwned_message);

// attacker has gained knowledge about initial message
if c1 == encrypted {
messages[0]
} else {
messages[1]
}
}

/// We simulate Chained CBC and show that attacker can know whether initial plaintext was message 1
/// or 2.
fn main() {
let mut rng = thread_rng();

// generate a random key and publicly known IV, and initiate CBC with AES cipher
let key = Key::<128>::new(rng.gen());
let iv = Block(rng.gen());
let cbc = CBC::<AES<128>>::new(iv);

// Chose 2 random messages, {m_0, m_1}
let messages = attacker_chosen_message();

// select a uniform bit b, and chose message m_b for encryption
let bit = rng.gen_range(0..=1);
let encrypted = cbc.encrypt(&key, messages[bit]);

let predicted_message = attacker(&key, &iv, encrypted);

assert_eq!(messages[bit], predicted_message);
}
36 changes: 30 additions & 6 deletions src/encryption/symmetric/aes/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,20 @@ Unlike DES, it does not use a Feistel network, and most AES calculations are don
## Algorithm

The core encryption algorithm consists of the following routines:
- [KeyExpansion](#KeyExpansion)
- [AddRoundKey](#AddRoundKey)

- [KeyExpansion][keyexp]
- [AddRoundKey][arc]
- [SubBytes](#SubBytes)
- [ShiftRows](#ShiftRows)
- [MixColumns](#MixColumns)

For decryption, we take the inverses of these routines:
For decryption, we take the inverses of these following routines:

- [InvSubBytes](#InvSubBytes)
- [InvShiftRows](#InvShiftRows)
- [InvMixColumns](#InvMixColumns)

TODO
Note that we do not need the inverses of [KeyExpansion][keyexp] or [AddRoundKey][arc], since for decryption we're simply using the round keys from the last to the first, and [AddRoundKey][arc] is its own inverse.

### Encryption

Expand Down Expand Up @@ -75,7 +80,7 @@ Substitutes each byte in the `State` with another byte according to a [substitut

#### ShiftRow

Shift i-th row of i positions, for i ranging from 0 to 3, eg. Row 0: no shift occurs, row 1: a left shift of 1 position occurs.
Do a **left** shift i-th row of i positions, for i ranging from 0 to 3, eg. Row 0: no shift occurs, row 1: a left shift of 1 position occurs.

#### MixColumns

Expand All @@ -87,7 +92,24 @@ More details can be found [here][mixcolumns].

### Decryption

TODO
For decryption, we use the inverses of some of the above routines to decrypt a ciphertext. To reiterate, we do not need the inverses of [KeyExpansion][keyexp] or [AddRoundKey][arc], since for decryption we're simply using the round keys from the last to the first, and [AddRoundKey][arc] is its own inverse.


#### InvSubBytes

Substitutes each byte in the `State` with another byte according to a [substitution box](#substitution-box). Note that the only difference here is that the substitution box used in decryption is derived differently from the version used in encryption.

#### InvShiftRows

Do a **right** shift i-th row of i positions, for i ranging from 0 to 3, eg. Row 0: no shift occurs, row 1: a right shift of 1 position occurs.

#### InvMixColumns

Each column of bytes is treated as a 4-term polynomial, multiplied modulo x^4 + 1 with the inverse of the fixed polynomial
a(x) = 3x^3 + x^2 + x + 2 found in the [MixColumns] step. The inverse of a(x) is a^-1(x) = 11x^3 + 13x^2 + 9x + 14. This multiplication is done using matrix multiplication.

More details can be found [here][mixcolumns].


## Substitution Box

Expand Down Expand Up @@ -117,6 +139,8 @@ In production-level AES code, fast AES software uses special techniques called t
[des]: ../des/README.md
[spn]: https://en.wikipedia.org/wiki/Substitution%E2%80%93permutation_network
[slide attacks]: https://en.wikipedia.org/wiki/Slide_attack
[keyexp]: #KeyExpansion
[arc]: #AddRoundKey
[mixcolumns]: https://en.wikipedia.org/wiki/Rijndael_MixColumns
[Rijndael ff]: https://en.wikipedia.org/wiki/Finite_field_arithmetic#Rijndael's_(AES)_finite_field
[fips197]: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.197-upd1.pdf
Expand Down
Loading
Loading