AES (Advanced Encryption Standard)
This algorithm is recommended
AES is considered secure6. Use AES with 128, 192 or 256 (pick the largest size feasible for your system) with GCM mode of operation. GCM provides authentication, which makes this an AEAD cipher.
A very good and fast alternative is ChaCha, which comes in less variations and there are fewer things that can be done wrong when implementing it. Also, ChaCha might be faster on certain hardware that does not provide AES hardware-acceleration (which most common chipsets, even embedded ones, provide).
Disclaimer: How to use recommendations from Cryptography Primer
The recommendations on Cryptography Primer are based on research on multiple sources that are freely available online, such as:
- Research papers available on e.g. arxiv.org1
- Recommendations of Cryptographic Library authors
- BSI technical guidelines4
- NIST publications5
- Blogs of reknown cryptographers or cybersecurity experts
- crypto.stackexchange.com2
- security.stackexchange.com3
- and occasionally other sources
As should always be the case, you should not take recommendations from a single source for granted, but instead find at least a second - or better, third - source that confirms this recommendation.
Also, if you are using recommendations for anything that will be used in a production setting or will be used by anyone that relies on it's cryptograhic properties, it is highly recommended to let your concept and implementation being reviewed by a reknown cybersecurity firm.
That being said, the author hopes that Cryptography Primer helps you find the correct algorithm to use for your scenario, and find the correct parameters and modes for a safe implementation.
On this page you will learn:
- What is AES, and features does it provide?
- How secure is AES?
- What can I use instead of AES?
- What modes of operation can I use with AES?
Quick Info
Advanced Encryption Standard | |
---|---|
Names | AES, Advanced Encryption Standard, Rijndael |
Attributes | Symmetric (Private Key), Block Cipher |
Features | Encryption, AEAD |
Block Size | 128 Bits (16 Bytes) |
Private Key Sizes | 128, 192, 256 |
First Published | 1998 |
AES in Practice
Hint
The key sizes 192 and 256 do not change the block size. The block size is always 128 Bits, even when larger keys are being used.
AES comes in multiple forms: AES-128, AES-192, AES-256. The number specifies the size of the private key that is being used. The higher the number, the higher the security (but also the slower the encryption and decryption speed). Even the smallest 128 Bit (16 Bytes) key size is currently considered secure6 and safe to use mid-term. With AES-256 you can even achieve quantum resistance from the current state of research (Januar 2022)78.
AES Key Generation
Private keys for AES do not have to follow a specific form - they just need to be (crypto-secure) random bits of the required size. Other algorithms, such as RSA or EC, require the values to conform to some mathematical requirements, but AES keys do not.
Private keys for AES do not have to follow a specific form - they just need to be (crypto-secure) random bits of the required size. Other algorithms, such as RSA or EC, require the values to conform to some mathematical requirements, but AES keys do not.
However, it is important to make sure that the key is generated properly, because otherwise the key generation can be an attack vector - and maybe even a very easy one to attack, if key generation is not "random enough".
Here are a few recommendations that you should keep in mind when implementing AES key generation:
- Use a CSPRNG (Cryptographically-secure Pseudo Random Number Generator) or HSM (Hardware Security Module), if possible
- Otherwise make sure that you seed your random number generator properly (don't only use the current timestamp)
- Always seed a key generator with new randomness - don't succinctly generate multiples keys from the same random number seed
- Generate keys where they will be ultimately needed and stored - e.g. don't generate keys server-side to use them on the client, but generate them client-side instead.
- Store private keys securely
- Avoid transferring private keys
- It is highly recommended to re-negotiate or rotate keys as often as possible. Don't see a Private Key as something "permanently" bound to a person or a node, but instead make it something ephemeral that can change on a frequent basis.
How to use passwords to encrypt/decrypt with AES
Usually you use AES in a manner that the key is derived from the password that a user has to enter to encrypt/decrypt the data. Because the key is of fixed length (either 128, 192 or 256 Bits - which are 16, 24 or 32 Bytes, respectively), you can not use the password as the key directly, because that would impose insecure and inpractical constraints on the password that the user has to choose.
Instead, a key derivation function is used to create an AES-compatible key from a password. PBKDF2 (Password Based Key Derivation Function 2) is a state of the art key derivation function.
See the code sample below.
Modes of operation
AES is a block-cipher, which means that it can only encrypt data with the exact block size of 128 Bits (16 Bytes). This means that it must be combined with a so-called "Mode of operation" in order to be able to encrypt arbitrary number of bytes.
There are modes that add authentication to the encryption, and there are modes that do not include authentication. You must absolutely authenticate your encrypted data, because this protects against CCA10. The easiest and safest choice is to use an authenticated mode of operation. Alternatively, you can implement Encryt-then-MAC12 yourself, but this can easily be done incorrectly.
"GCM" (Galois/Counter Mode) is highly recommended
GCM provides authentication, which prevents many different kinds of attacks, and is well studied and has proven to be very secure.
How to pick a mode if GCM is not available
You can decide your mode of operation using these few rules of thumb:
- If your platform provides GCM, then use GCM.
- If your platform does not provide GCM, use CCM, EAX or OCB modes (preference in this order, consider that OCB might require a license13).
- If your platform does not provide GCM, CCM, EAX or OCB, use CTR or CFB (preference in this order) and apply Encrypt-then-MAC12.
- If your platform also does not provide CTR or CFB, reconsider your platform.
- If you can not use a platform that provides better modes, use anything except ECB, do your own research on the security of the chosen mode, and apply Encrypt-then-MAC12.
Never ever use ECB.14
IV vs. nonce?
Neither an IV (initialization vector) nor a nonce are secret and are usually sent alongside the ciphertext.
What is an "Initialization Vector"?
The IV needs to be random (generated with a CSPRNG, as you can find in your crypto library). You must generate a new IV for each encrypted message.
What is a "Nonce"?
"Nonce" means "Number only used once". While this is also true for an IV, a nonce does not have the requirement to be random. You can safely use a steadily increasing number (a counter) as your nonce, but you must not re-use the same number for different encryptions. You must generate a new nonce for each encrypted message.
Modes with Authentication (AEAD)
Mode of Operation | Full Name | Description |
---|---|---|
GCM | Galois/Counter Mode | This mode is recommended The GCM mode uses a random initialization vector (IV) for better security. This means that the same encrypted plaintext does never result in the same ciphertext. See implementation notes for GCM. |
CCM | Counter with CBC-MAC | Considered secure This mode is considered secure and you can safely use it. It is somewhat slower than GCM, though. |
EAX | unknown | Not widely used This mode is not widely used and hence not widely studied, so it is unsure how secure it is. While it is rather easy to implement, it is also slower than other modes. |
OCB | Offset Codebook Mode | This mode is patented The OCB mode is very, very fast and considered secure. However, it is patented in the U.S. It is free to use in open source software. If you want to use it in a commercial product, you would need to require a license13 or permission to use. |
Implementation notes for GCM
GCM is by far the recommended mode of operation for AES, because:
- It uses a nonce, which strengthens confidentiallity, because the same plaintext will not be encrypted to the same ciphertext.
- It provides AEAD, which prevents CCA.
- It is well supported. For example, it is used in the Web Crypto API21 and is mandatory in TLS 1.322.
- It is fast (enough), even for high throughput demands.
However, it comes with one major caveat for implementers23. It supports a nonce of 96 Bits (12 Bytes), which is, depending on the field of application, not enough to use a random value and feel safe enough that it will be unique. After 281,474,976,710,656 messages, you have a 50% chance of re-using a nonce. In practical terms, cryptographers recommend not more than 4,294,967,296 (4 billion) messages with the same key and a random nonce. The fatal thing about this is that a nonce-reuse makes it relatively easy to recover the key and break the security completely (for future and potentially previous messages for this key).
So, if your field of application only encrypts a few thousands or hundred thousands of messages per key, and has a good CSPRNG, you should not face a problem here. For example, when used with TLS, which creates a new Private Key for each session, this is more than unlikely to occur. However, for e.g. password-based schemes, the same key will be used permanently, or at least for a very long time, which makes this more likely.
To prevent this problem that applies to usage of AES-GCM with long-term keys, it is recommended to either
- Implement a key rotation mechanism, if feasible. This minimizes other attack vectors, too, and might prevent the impact of a stolen or broken key.
- Implement a persistent storage and use a counter per Private Key as the nonce.
- Use AES-GCM-SIV24 instead, which uses larger nonces that are considered secure when generated at random.
Modes without Authentication
Warning
You should only use modes without authentication when you have reasons to not use a mode with authentication (listed above).
Unauthenticated modes are vulnerable to CCA (Chosen Ciphertext Attack), which authenticated modes are not.
You must apply Encrypt-then-MAC12 manually in your encryption scheme to prevent CCA-attacks if you are forced to use an unauthenticated mode.
Mode of Operation | Full Name | Description |
---|---|---|
CTR | Counter Mode | Use GCM or CCM instead, if possible Because this mode does not provide authentication, it is not recommended. However, of all the unauthenticated modes, it is the one with the strongest safety attributes and that is the least easy one to implement incorrectly. If taken care11, the IV can be a nonce and does not need to be produced by a CSPRNG, which could be an advantage. Can be parallelized. You must apply Encrypt-then-MAC12 manually when using an unauthenticated mode |
CFB | Cipher Feedback | Use GCM, CCM or CTR instead, if possible This mode is pretty similar to CBC, but chains the blocks in a different way. It is also always used with an Initialization Vector, and the IV is required to be produced by a CSPRNG. You must apply Encrypt-then-MAC12 manually when using an unauthenticated mode. |
CTS | Ciphertext Stealing | Not recommended Ciphertext stealing is a variation of ECB or CBC, but is in practice only used like CBC. The difference is that the last two blocks are chained differently. The security is not notably different from CBC. |
CBC | Cipher Block Chaining | Not recommended This mode requires padding, which makes it vulnerable to padding oracle attacks17. |
ECB | Electronic Code Book | Do not ever use this This method is not recommended, because it does not introduce diffusion into the ciphertext, which means that the same block is encrypted to the same ciphertext, effectively leaking patterns, which can easily be used to gain information that should be hidden. |
Security Recommendations
Recommended | Discouraged |
---|---|
|
|
Code Samples
AES key generation
This code sample shows how to securely generate a new AES key:
Warning
Do not use your regular "random" function for key generation, but use your crypto library's dedicated functions for this.
Info
This code sample requires the widely used pyca/cryptography
package.
Install it with pip install cryptography
or your favorite package manager.
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
# Generate a random 256 Bit private key:
key = AESGCM.generate_key(bit_length=256)
print(key.hex())
// TODO
// TODO
Key derivation from passwords
This code sample show how to securely derive an encryption key from a password:
Info
This code sample requires the widely used pyca/cryptography
package.
Install it with pip install cryptography
or your favorite package manager.
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
# Salts should be randomly generated and need to be accessible
# whenever a key is derived from a password. So basically,
# the salt is usually stored/transmitted alongside the encrypted data.
salt = bytes.fromhex('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa') # EXAMPLE VALUE - DO NOT USE THIS!
# derive
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32, # 32 Bytes = 256 Bits
salt=salt,
iterations=100000, # This should be the minimum. You can increase the iterations if your system can handle it
# to strengthen security.
)
key = kdf.derive(b"my great password")
print(key.hex())
# `key` can now be used with AES-256.
# When you use different key sizes (AES-128 or AES-192), you need to specify
# the corresponding length. 128 Bits = 16 Bytes, 192 Bits = 24 Bytes.
# Further processing can be done to use with AES-256-GCM (explanation and code samples coming soon...)
// TODO
// TODO
AES encryption and decryption
Here's a code sample on a simple use case to encrypt and decrypt data:
Info
This code sample requires the widely used pyca/cryptography
package.
Install it with pip install cryptography
or your favorite package manager.
import os
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
# The text to be encrypted:
plaintext = b"I am secret"
# Can be None, when no associated data is required:
authenticated_text= b"authenticated but unencrypted data"
# Generate a random private key for this example:
key = AESGCM.generate_key(bit_length=256)
# Create an object that can encrypt/decrypt with the following cipher:
# Algorithm: AES
# Key Size: 256
# Mode of Operation: GCM - an authenticated mode (see "AEAD")
aesgcm = AESGCM(key)
# Generate a "nonce" for this encryption session of size 96 Bits (12 Bytes).
# A nonce ensures that the same plaintext is not encrypted to the same ciphertext, which strenghtens security:
nonce = os.urandom(12)
# Notice: NEVER re-use the same nonce with the same key. Using a counter - if feasible - is an appropriate
# way to prevent this. Using a random number might have a realistic chance of reuse,
# depending on the number of messages that are being encrypted, the implementation of the random number generator
# and the available entropy in the system.
# Encrypt the data and add the authenticated (but not encrypted) data:
ciphertext = aesgcm.encrypt(nonce, plaintext, authenticated_text)
# The content of "ciphertext" can now be shared via an untrusted medium.
# The receiver also needs to know the "nonce" and the authenticated text (when used),
# which can also be shared via an untrusted medium.
# Decrypt the ciphertext back into the plaintext:
plaintxt = aesgcm.decrypt(nonce, ciphertext, authenticated_text)
print(plaintext)
# Result: "I am secret"
// TODO
// TODO
Security Level
"Security Level" explained
In cryptography, anything that lets you decrypt a message or extract the secret key with less effort than "brute force" is considered a "break" or a possible "attack". "Brute force" means testing out the key in the whole key space - for 128 Bits (like in AES-128) this means trying all 340,282,366,920,938,463,463,374,607,431,768,211,456 possible values that an 128 Bit (16 Bytes) value can have. For 256 Bits (like in ChaCha20 or AES-256), these are 115,792,089,237,316,195,423,570,985,008,687,907,853,269,984,665,640,564,039,457,584,007,913,129,639,936 possible values.
As you can imagine, not every "attack" is a real problem. Having an attacker have to try out for example 2127 values (instead of 2128) is not a risk in practice.
With the help of certain "attacks" it is possible to reduce the key space required to try out in order to break the encryption. The lowest key space that you can attain for a given cipher using one or a combination of attacks is considered the "security level".
In cryptography, a key space of 280 (this is a security level of 80 Bits) has long been considered secure. This might no longer be the case, depending on how strong your security needs to be. The BSI (German Institute of Cybersecurity) recommends a security level of at least 100 Bits and even 120 Bits for high security15 in 2022.
The security level of a cipher is not fix in time. It might become lower if attacks on the cipher have been found. That is why security recommendations are valid usually not more than one or two years into the future.
In 2022, AES is considered to have the following security levels:
What does it mean when a cipher is "broken"?
In cryptanalysis, which is the science of analysing and breaking cryptographic primitives, a cipher is "broken" if a way is found to decrypt the ciphertext or find the Private Key in less rounds than a brute force attack, which means trying all possible values in the Private Key's key space.
In practice, not every cipher that is "broken" by the definition of cryptanalysis is indeed insecure. For example, for AES a technique was found to reduce the theoretic maximum key space of 256 Bits down to 254 Bits. Because this reduced key space is still large enough for modern encryption requirements, AES is still very secure, although you might find statements that it has been "broken".
Variation | Security Level | Considered Secure? |
---|---|---|
AES-128 | 126.1 Bits | :fontawesome-solid-check-circle: |
AES-192 | 189.7 Bits | :fontawesome-solid-check-circle: |
AES-256 | 254.4 Bits | :fontawesome-solid-check-circle: |
The security level is lower than the raw key size, because there is an attack method that allows to lower the key space that is required to be searched in order to break an encryption. This attack is called the "Biclique attack"16.
Alternatives
Other Symmetric Encryption algorithms are:
Overview of encryption algorithms
Algorithm | Key Sizes | Type | Authentication? (AE or AEAD) |
Recommendation |
---|---|---|---|---|
AES | 128, 192 or 256 Bits | Symmetric 128 Bit Block Cipher |
✅ via GCM mode |
Recommended This algorithm is considered very secure and widely studied and deployed. GCM or CBC modes are recommended. |
ChaCha | 256 Bits | Symmetric Stream Cipher |
✅ via Poly1305 |
Recommended ChaCha20 is considered very secure and is widely studied and deployed. Use of Poly1305 is recommended. |
RSA | >= 1028 Bits | Asymmetric Block Cipher |
? | Recommended This algorithm is considered very secure. Usually used with an symmetric encryption algorithm, while RSA "only" encrypts the symmetric key. |
ECIES | 256 Bits | Asymmetric (Hybrid) Block Cipher or Stream Cipher possible |
? | Recommended (but can be hard to implement) This encryption scheme is considered very secure. It is not a precicse defined algorithm, but instead a framework to implement encryption when knowing the receiver's Elliptic Curve public key. It can be used with symmetric encryption algorithms (recommended: AES or ChaCha20). |
Camellia | 128, 192 or 256 Bits | Symmetric Block Cipher |
❌ | Considered secure This algorithm is considered secure, but is not as widely studied or deployed as AES or ChaCha20 |
3DES | 112 or 168 Bits | Symmetric 64 Bit Block Cipher |
❌ | Less secure than AES and ChaCha20 This algorithm is not inherently insecure, but it is less secure than AES or ChaCha20, and computationally more expensive. |
DES | 56 Bits | Symmetric 64 Bit Block Cipher |
❌ | Not recommended This algorithm is no longer considered secure |
Blowfish | 32-448 Bits | Symmetric 64 Bit Block Cipher | ❌ | Not recommended This algorithm is no longer considered secure |
ARC4 (aka "RC4") |
40-2048 Bits | Symmetric Stream Cipher | ❌ | Not recommended This algorithm is no longer considered secure |
IDEA | 128 Bits | Symmetric 64 Bit Block Cipher | ❌ | Not recommended This algorithm is no longer considered secure |
History
Year | Event |
---|---|
1998 | First published by Vincent Rijmen, Joan Daemen |
2001 | Standardized by the NIST as the Advanced Encryption Standard (AES) |
2003 | Endorsed by the U.S. Government to protect classified information |
References
-
BSI - Cryptography on bsi.bund.de ↩
-
NIST Computer Security Resource Center on nist.gov ↩
-
Is 128-bit security still considered strong in 2020, within the context of both ECC Asym & Sym ciphers on crypto.stackexchange.com. ↩↩
-
Is AES-256 a post-quantum secure cipher or not? on crypto.stackexchange.com. ↩
-
Post-quantum cryptography on Wikipedia ↩
-
Using Encryption and Authentication Correctly (for PHP developers) ↩
-
All the crypto code you’ve ever written is probably broken as blogged by Tony Arcieri. ↩
-
"Counter (CTR)" at "Block cipher mode of operation" on Wikipedia ↩
-
Free Licenses on www.cs.ucdavis.edu by Phillip Rogaway ↩↩
-
"Electronic codebook (ECB)" at "Block cipher mode of operation" on Wikipedia ↩
-
BSI - Technical Guide - Cryptographic Mechanisms: Recommendations and Key Lengths on bsi.bund.de ↩
-
Biclique attack on Wikipedia ↩
-
Padding oracle attack on Wikipedia ↩
-
Recommendation for Block Cipher Modes of Operation: Galois/Counter Mode (GCM) and GMAC on csrc.nist.gov ↩
-
Hardware Security Module on Wikipedia ↩
-
Cryptographically-secure pseudorandom number generator on Wikipedia ↩
-
Web Crypto API's "SubtleCrypto.encrypt()" at MDN on developer.mozilla.org ↩
-
RFC 8446: The Transport Layer Security (TLS) Protocol Version 1.3 on ietf.org ↩
-
Why AES-GCM Sucks on soatok.blog ↩
-
RFC 8452: AES-GCM-SIV: Nonce Misuse-Resistant Authenticated Encryption on ietf.org ↩