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(ciphers): AES encryption #102

Merged
merged 37 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
4d7a820
feat(ciphers): AES encryption
eightfilms Jun 20, 2024
7ca5c8f
cleanup `BlockCipher` trait
eightfilms Jun 27, 2024
99ed9fb
feat: impl for 192-bit and 256-bit keys
eightfilms Jun 27, 2024
8fa05c5
doc: frontpages
eightfilms Jun 27, 2024
3720215
test: remove mix column test
eightfilms Jun 27, 2024
f2d5536
feat(key): use `KEY_LEN_BYTES` for assertions
eightfilms Jun 27, 2024
3d17aa9
feat(key): impl Deref and use
eightfilms Jun 27, 2024
30fb784
remove unused Key128 type
eightfilms Jun 27, 2024
f0c09dc
define and use `ExpandedKey` to represent expanded key
eightfilms Jun 27, 2024
20a2c18
docs: AES doc comment
eightfilms Jun 27, 2024
1b4181f
docs: Sbox derivation doc comment
eightfilms Jun 27, 2024
a04aefa
docs: more sbox doc changes
eightfilms Jun 27, 2024
7cc2262
clippy
eightfilms Jun 27, 2024
8ec79f3
remove redundant `BLOCK_LEN`
eightfilms Jun 27, 2024
399566e
relocate test vectors comment in tests
eightfilms Jun 27, 2024
dbbe0f2
docs: add link to source
eightfilms Jun 27, 2024
7cd117b
shift around comments
eightfilms Jun 27, 2024
b5cbc80
use same fn for all encryption of different bits
eightfilms Jun 27, 2024
d93a822
move AES work to encryption crate
eightfilms Jun 28, 2024
c7e50b5
docs: doc for Word
eightfilms Jun 28, 2024
9665d74
cleanup
eightfilms Jun 28, 2024
126b88c
split tests:
eightfilms Jun 28, 2024
7bb965a
don't use pretty_assertions
eightfilms Jun 28, 2024
103e9f3
use remainder
eightfilms Jun 28, 2024
8e9e2d5
docs: README skeleton
eightfilms Jun 28, 2024
cdf9ed0
update example
eightfilms Jun 28, 2024
add5456
README
eightfilms Jun 29, 2024
e4908da
doc: fix links
eightfilms Jun 29, 2024
c54a7c7
remove ExpandedKey
eightfilms Jun 29, 2024
3a5022b
clippy
eightfilms Jun 29, 2024
1ee1209
cleanup
eightfilms Jun 29, 2024
ed9d66a
SBOX cleanup
eightfilms Jun 29, 2024
c3b924a
replace unimplemented with more explicit panic
eightfilms Jun 29, 2024
6469574
doc comment for key expansion
eightfilms Jun 29, 2024
a59cab2
fix des link
eightfilms Jun 29, 2024
c1d200b
better mix columns docs
eightfilms Jun 29, 2024
f0e38d6
rename expanded key
eightfilms Jun 29, 2024
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
123 changes: 123 additions & 0 deletions src/encryption/symmetric/aes/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# AES encryption

[Advanced Encryption Standard][aes] (AES) is a symmetric-key algorithm and is a variant of the Rijndael (pronounced 'rain-dull') block cipher. AES supersedes the [Data Encryption Standard][des] (DES).

## Overview

AES supports a block size of 128 bits, and three different key lengths: 128, 192, and 256 bits. It manipulates _bytes_ instead of _individual bits_ or _64-bit words_, and views a 16-byte plaintext as a 2D column-major grid of bytes.

AES uses [Substitution-Permutation Network (SPN)][spn] which makes use of two main properties: _confusion_ and _diffusion_. Confusion means that the input undergoes complex transformations, and diffusion means that these transformations depend equally on all bits of the input.

Unlike DES, it does not use a Feistel network, and most AES calculations are done in a particular finite field.


## Algorithm

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

For decryption, we take the inverses of these routines:

TODO
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Complete or add more detail.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yeah, was thinking to leave decryption for a followup PR - apologies for not being clear about that, but I could also complete it within the same PR (if that's preferable)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine either way

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Filed an issue for decryption: #119


### Encryption

Encryption consists of rounds of the above routines, with the number of rounds being determined by the size of the key. Keys of length 128/192/256 bits require 10/12/14 rounds respectively.

Round *1* is always just *AddRoundKey*. For rounds *2* to *N-1*, the algorithm uses a mix of *SubBytes*, *ShiftRows*, *MixColumns*, and *AddRoundKey*, and the last round is the same except without *MixColumns*.

#### KeyExpansion

The **KeyExpansion** algorithm takes a 128/192/156-bit key and turns it into 11/13/15 round keys respectively of 16 bytes each. The main trick to key expansion is the fact that if 1 bit of the encryption key is changed, it should affect the round keys for several rounds.

Using different keys for each round protects against _[slide attacks]_.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we link a resource on slide attacks? Would be nice to write a test for them at some point if it's not too crazy

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes i 100% agree. An example of this would be amazing!

If you don't do it in this PR (which, by no means, do you have to) can you make an issue?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Filed an issue: #120 (comment)


To generate more round keys out of the original key, we do a series of word rotation and/or substitution XOR'd with round constants, depending on the round number that we are in.

For round **i**, if i is a multiple of the length of the key (in words):

```rust
Self::rotate_word(&mut last);
word = (u32::from_le_bytes(Self::sub_word(last))
^ u32::from_le_bytes(ROUND_CONSTANTS[(i / key_len) - 1]))
.to_le_bytes();
```

if i + 4 is a multiple of 8:

```rust
word = Self::sub_word(last)
```

The final step is always to XOR previous round's round key with the *(i - key_len)*-th round key:

```rust
let round_key = expanded_key[i - key_len]
.iter()
.zip(last.iter())
.map(|(w, l)| w ^ l)
.collect_vec()
.try_into()
.unwrap();
```

#### AddRoundKey

XORs a round key to the internal state.

#### SubBytes

Substitutes each byte in the `State` with another byte according to a [substitution box](#substitution-box).

#### 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.

#### MixColumns

Each column of bytes is treated as a 4-term polynomial, multiplied modulo x^4 + 1 with a fixed polynomial
a(x) = 3x^3 + x^2 + x + 2. This is done using matrix multiplication.

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


### Decryption

TODO
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either address the todo or elaborate in a comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Filed an issue for decryption: #119


## Substitution Box

A substitution box is a basic component of symmetric key algorithms
performs substitution. It is used to obscure the relationship
the key and the ciphertext as part of the *confusion* property.

During substitution, a byte is interpreted as a polynomial and
mapped to its multiplicative inverse in [Rijndael's finite field][Rijndael ff]: GF(2^8) = GF(2)[x]/(x^8 + x^4 + x^3 + x + 1).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome!


The inverse is then transformed using an affine transformation which is the sum of multiple rotations of the byte as a vector, where addition is the XOR operation. The result is an 8-bit output array which is used to substitute the original byte.

## Security

Fundamentally, AES is secure because all output bits depend on all input bits in some complex, pseudorandom way. The biggest threat to block ciphers is in their modes of operation, not their core algorithms.

## Practical implementations

In production-level AES code, fast AES software uses special techniques called table-based implementations which replaces the *SubBytes-ShiftRows-MixColumns* sequence with a combination of XORs and lookups in hardcoded tables loaded in memory during execution time.

## References

- [FIPS197](fips197)
- [Serious Cryptography - A Practical Introduction to Modern Cryptography](seriouscrypto)

[aes]: https://en.wikipedia.org/wiki/Advanced_Encryption_Standard
[des]: ../des/README.md
[spn]: https://en.wikipedia.org/wiki/Substitution%E2%80%93permutation_network
[slide attacks]: https://en.wikipedia.org/wiki/Slide_attack
[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
[seriouscrypto]:https://nostarch.com/seriouscrypto
Loading
Loading