silk.crypto.aes.
Encrypt data with the AES block cipher (FIPS 197) in ECB, CBC, CTR, CFB, or OFB mode (NIST SP 800-38A).
When to use#
Use this module when a protocol or file format names AES-CBC, AES-CTR, AES-ECB, AES-CFB, or
AES-OFB, or when it needs the raw AES block function. These modes do not detect changes to the
ciphertext. To encrypt new data, prefer silk.crypto.aes_gcm or
silk.crypto.chacha20_poly1305, which also authenticate it.
Details#
Aes holds an expanded 16-byte (AES-128), 24-byte (AES-192), or 32-byte (AES-256) key and
encrypts or decrypts one 16-byte block. AesCbc and AesEcb encrypt a message that
arrives in parts: call update for each part and finish at the end. With padding on, they add
and remove PKCS #7 padding, as OpenSSL does. AesCtr XORs a key stream into the data, so the
same call encrypts and decrypts. The counter is the whole 16-byte block, incremented as one
big-endian number. AesCfb, AesCfb8, and AesCfb1 are cipher feedback with 128, 8, and
1-bit segments, and AesOfb is output feedback. Nothing allocates.
The other AES modes have their own modules: silk.crypto.aes_gcm, silk.crypto.aes_ccm, and
silk.crypto.aes_ocb authenticate, silk.crypto.aes_xts encrypts storage sectors, and
silk.crypto.aes_wrap wraps keys.
When the build targets x86-64 or AArch64 with the aes CPU feature, each round is one AES
instruction. A default x86-64 build checks at run time for AES-NI and SSSE3 and uses them when
the machine has them, with CBC decryption, ECB and CTR running eight blocks at a time. Otherwise
the rounds use portable code that computes the S-box instead of reading a table, so the time
does not depend on the key or the data on any target.
Errors#
The functions return an AesError. Every check comes before the first write, and on an error
the output buffers do not change.
Gotchas#
CBC and CTR need a new IV for each message under the same key. With CTR, the same key and IV used twice give away the XOR of the two plaintexts. ECB encrypts equal blocks to equal blocks, so it shows patterns in the data. A wrong padding error from CBC decryption can act as an oracle that lets an attacker decrypt the message, so authenticate the ciphertext before you decrypt it. The values do not erase their copies of the key.
Examples#
Encrypt and decrypt with AES-128-CBC#
import silk.crypto.aes { AesCbc, AesError }
import silk.core.result { Result }
pub fn main() -> i32 {
let key: [u8; 16] = [0; 16]
let iv: [u8; 16] = [0; 16]
let mut encryptor = match AesCbc.encryptor(&key, &iv, true) {
Result<AesCbc, AesError>.Success { value } => move value
Result<AesCbc, AesError>.Failure { error: _ } => {
return 1
}
}
// Five bytes of plaintext become one padded block of ciphertext.
let mut ciphertext: [u8; 16] = [0; 16]
let mut written: usize = 0
if let Result.Success { value } = encryptor.update(b"hello", &mut ciphertext) {
written = value
}
if let Result.Success { value } = encryptor.finish(&mut ciphertext) {
written = written + value
}
if written != 16 {
return 1
}
let mut decryptor = match AesCbc.decryptor(&key, &iv, true) {
Result<AesCbc, AesError>.Success { value } => move value
Result<AesCbc, AesError>.Failure { error: _ } => {
return 1
}
}
let mut plaintext: [u8; 16] = [0; 16]
if let Result.Success { value } = decryptor.update(&ciphertext, &mut plaintext) {
if value != 0 {
return 1
}
}
return match decryptor.finish(&mut plaintext) {
Result<usize, AesError>.Success { value } => {
if value != 5 || plaintext[0] != 104 {
return 1
}
return 0
}
Result<usize, AesError>.Failure { error: _ } => 1
}
}Encrypt with AES-256-CTR#
import silk.crypto.aes { AesCtr, AesError }
import silk.core.result { Result }
pub fn main() -> i32 {
let key: [u8; 32] = [1; 32]
let iv: [u8; 16] = [0; 16]
let mut stream = match AesCtr.make(&key, &iv) {
Result<AesCtr, AesError>.Success { value } => move value
Result<AesCtr, AesError>.Failure { error: _ } => {
return 1
}
}
let mut ciphertext: [u8; 5] = [0; 5]
if let Result.Failure { error: _ } = stream.apply(b"hello", &mut ciphertext) {
return 1
}
// A new stream with the same key and IV decrypts.
let mut again = match AesCtr.make(&key, &iv) {
Result<AesCtr, AesError>.Success { value } => move value
Result<AesCtr, AesError>.Failure { error: _ } => {
return 1
}
}
let mut plaintext: [u8; 5] = [0; 5]
if let Result.Failure { error: _ } = again.apply(&ciphertext, &mut plaintext) {
return 1
}
if plaintext[0] != 104 || plaintext[4] != 111 {
return 1
}
return 0
}Import as Aes with import silk.crypto.aes { Aes }.
Public declarations: 11.
AesError#
pub union AesErrorThe reason that an AES function rejected a call. The output buffers do not change.
InvalidKeyLength#
InvalidKeyLengthThe key is not 16, 24, or 32 bytes.
InvalidIvLength#
InvalidIvLengthThe IV is not 16 bytes.
OutputTooSmall#
OutputTooSmallThe output buffer is shorter than the bytes the call writes.
InvalidInputLength#
InvalidInputLengthWithout padding, the message is not a whole number of 16-byte blocks. With padding, the ciphertext given to a decryptor is not a whole number of blocks.
InvalidPadding#
InvalidPaddingThe last decrypted block does not end in valid PKCS #7 padding. The key or IV is wrong, or the ciphertext was changed.
Implementation Debug for AesError#
impl Debug for AesErrorOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> ()
! WriterError
? &mut WriterWrites the name of the variant, such as InvalidKeyLength.
Aes#
pub struct AesAn expanded AES key (FIPS 197) that encrypts and decrypts single 16-byte blocks.
When to use#
Use it to build a block cipher mode that this module does not offer. For CBC, CTR, or ECB, use
AesCbc, AesCtr, or AesEcb. For new designs, use silk.crypto.aes_gcm.
Details#
Aes.make takes a 16-byte (AES-128), 24-byte (AES-192), or 32-byte (AES-256) key and expands
the encryption and decryption round keys once. The value is fixed-size and does not allocate.
With the aes CPU feature on x86-64 or AArch64, or with AES-NI found at run time on x86-64,
each round is one instruction. Otherwise the portable rounds compute the S-box instead of reading
a table, so the time does not depend on the key or the data.
Gotchas#
Encrypting blocks one by one with the same key is ECB mode, which shows equal blocks. The value holds key material and is not erased when it is dropped.
Implementation Aes#
impl AesAssociated function make#
pub fn make(key: &[u8]) -> Result<Aes, AesError>Expands key into an AES key.
The key is 16 bytes (AES-128, 10 rounds), 24 bytes (AES-192, 12 rounds), or 32 bytes (AES-256,
14 rounds). The value copies what it needs and does not borrow key.
Errors#
InvalidKeyLengthifkeyis not 16, 24, or 32 bytes.
Method encryptBlock#
pub fn encryptBlock(self: &Self, block: &[u8; 16]) -> [u8; 16]Returns the encryption of the 16-byte block block.
The time does not depend on the key or the data.
Method decryptBlock#
pub fn decryptBlock(self: &Self, block: &[u8; 16]) -> [u8; 16]Returns the decryption of the 16-byte block block.
The time does not depend on the key or the data.
encryptState#
pub fn encryptState(key: &Aes, state: simd<u8, 16>) -> simd<u8, 16>Encrypts the 16-byte state state with key.
Use it to build a block cipher mode on SIMD states without converting to and from arrays. The lanes hold the block bytes in order. The time does not depend on the key or the data.
decryptState#
pub fn decryptState(key: &Aes, state: simd<u8, 16>) -> simd<u8, 16>Decrypts the 16-byte state state with key.
Use it to build a block cipher mode on SIMD states without converting to and from arrays. The lanes hold the block bytes in order. The time does not depend on the key or the data.
AesCbc#
pub struct AesCbcA streaming AES-CBC encryptor or decryptor (NIST SP 800-38A), with or without PKCS #7 padding.
When to use#
Use it when a protocol or file format names AES-CBC, such as aes-256-cbc in OpenSSL or
Node.js. CBC does not detect changes to the ciphertext. For new designs, use
silk.crypto.aes_gcm.
Details#
Make one with AesCbc.encryptor or AesCbc.decryptor, call AesCbc.update for each part
of the input, then AesCbc.finish. update writes whole blocks and keeps the rest, so the
output of all calls together does not depend on how the input was split. With padding on, a
decryptor keeps the last whole block until finish, which checks and removes the padding. The
key is 16, 24, or 32 bytes and the IV is 16 bytes. Nothing allocates.
Gotchas#
Use a new random IV for each message under the same key. A wrong padding error can act as an oracle that decrypts the message for an attacker, so authenticate the ciphertext first. The value holds key material and is not erased when it is dropped.
Implementation AesCbc#
impl AesCbcAssociated function encryptor#
pub fn encryptor(key: &[u8], iv: &[u8], padding: bool) -> Result<AesCbc, AesError>Returns an encryptor for key and iv. With padding, AesCbc.finish adds PKCS #7
padding, so any message length is valid.
Errors#
InvalidKeyLengthifkeyis not 16, 24, or 32 bytes.InvalidIvLengthifivis not 16 bytes.
Associated function decryptor#
pub fn decryptor(key: &[u8], iv: &[u8], padding: bool) -> Result<AesCbc, AesError>Returns a decryptor for key and iv. With padding, AesCbc.finish checks and removes
PKCS #7 padding.
Errors#
InvalidKeyLengthifkeyis not 16, 24, or 32 bytes.InvalidIvLengthifivis not 16 bytes.
Method updateLength#
pub fn updateLength(self: &Self, length: usize) -> usizeReturns the number of bytes that AesCbc.update writes for length more input bytes.
It is the number of whole blocks in the kept bytes plus the input. A decryptor with padding keeps back its last whole block.
Method update#
pub fn update(self: &mut Self, input: &[u8], output: &mut [u8]) -> Result<usize, AesError>Encrypts or decrypts the whole blocks of the kept bytes plus input into output, keeps the
rest, and returns the number of bytes written.
The count is AesCbc.updateLength of input.length, a multiple of 16. The bytes of
output after it do not change. input and output must not overlap.
Errors#
OutputTooSmallifoutputis shorter thanAesCbc.updateLength. The state does not change.
Method finish#
pub fn finish(self: Self, output: &mut [u8]) -> Result<usize, AesError>Ends the message, writes the last bytes to output, returns their number, and consumes the
state.
An encryptor with padding writes one 16-byte block. A decryptor with padding writes 0 to 15 bytes, the last block without its padding. Without padding, it writes nothing.
Errors#
InvalidInputLengthwithout padding if the message is not a whole number of blocks, or for a decryptor with padding if the ciphertext is not a whole number of blocks.InvalidPaddingfor a decryptor with padding if the last block does not end in valid PKCS #7 padding.OutputTooSmallifoutputis shorter than the bytes to write.
AesEcb#
pub struct AesEcbA streaming AES-ECB encryptor or decryptor (NIST SP 800-38A), with or without PKCS #7 padding.
When to use#
Use it only when a protocol or file format requires AES-ECB, such as aes-128-ecb in OpenSSL or
Node.js. ECB encrypts equal blocks to equal blocks, so it shows patterns in the data. For new
designs, use silk.crypto.aes_gcm.
Details#
Make one with AesEcb.encryptor or AesEcb.decryptor, call AesEcb.update for each part
of the input, then AesEcb.finish. update writes whole blocks and keeps the rest. With
padding on, a decryptor keeps the last whole block until finish, which checks and removes the
padding. The key is 16, 24, or 32 bytes. There is no IV. Nothing allocates.
Gotchas#
The value holds key material and is not erased when it is dropped.
Implementation AesEcb#
impl AesEcbAssociated function encryptor#
pub fn encryptor(key: &[u8], padding: bool) -> Result<AesEcb, AesError>Returns an encryptor for key. With padding, AesEcb.finish adds PKCS #7 padding.
Errors#
InvalidKeyLengthifkeyis not 16, 24, or 32 bytes.
Associated function decryptor#
pub fn decryptor(key: &[u8], padding: bool) -> Result<AesEcb, AesError>Returns a decryptor for key. With padding, AesEcb.finish checks and removes PKCS #7
padding.
Errors#
InvalidKeyLengthifkeyis not 16, 24, or 32 bytes.
Method updateLength#
pub fn updateLength(self: &Self, length: usize) -> usizeReturns the number of bytes that AesEcb.update writes for length more input bytes.
It is the number of whole blocks in the kept bytes plus the input. A decryptor with padding keeps back its last whole block.
Method update#
pub fn update(self: &mut Self, input: &[u8], output: &mut [u8]) -> Result<usize, AesError>Encrypts or decrypts the whole blocks of the kept bytes plus input into output, keeps the
rest, and returns the number of bytes written.
The count is AesEcb.updateLength of input.length, a multiple of 16. The bytes of
output after it do not change. input and output must not overlap.
Errors#
OutputTooSmallifoutputis shorter thanAesEcb.updateLength. The state does not change.
Method finish#
pub fn finish(self: Self, output: &mut [u8]) -> Result<usize, AesError>Ends the message, writes the last bytes to output, returns their number, and consumes the
state.
An encryptor with padding writes one 16-byte block. A decryptor with padding writes 0 to 15 bytes, the last block without its padding. Without padding, it writes nothing.
Errors#
InvalidInputLengthwithout padding if the message is not a whole number of blocks, or for a decryptor with padding if the ciphertext is not a whole number of blocks.InvalidPaddingfor a decryptor with padding if the last block does not end in valid PKCS #7 padding.OutputTooSmallifoutputis shorter than the bytes to write.
AesCtr#
pub struct AesCtrA streaming AES-CTR key stream (NIST SP 800-38A) that encrypts and decrypts.
When to use#
Use it when a protocol or file format names AES-CTR, such as aes-128-ctr in OpenSSL or
Node.js. CTR does not detect changes to the ciphertext. For new designs, use
silk.crypto.aes_gcm.
Details#
The 16-byte IV is the first counter block. Each block of key stream is the encryption of the
counter, which then grows by one as a 128-bit big-endian number and wraps to zero after all
ones, as OpenSSL does. AesCtr.apply XORs the key stream into the data, so the same call
encrypts and decrypts, and the result does not depend on how the data is split. Nothing
allocates.
Gotchas#
The same key and IV must never encrypt two messages. If they do, the XOR of the two ciphertexts is the XOR of the two plaintexts. The value holds key material and is not erased when it is dropped.
Implementation AesCtr#
impl AesCtrAssociated function make#
pub fn make(key: &[u8], iv: &[u8]) -> Result<AesCtr, AesError>Returns a key stream for key that starts at the counter block iv.
Errors#
InvalidKeyLengthifkeyis not 16, 24, or 32 bytes.InvalidIvLengthifivis not 16 bytes.
Method apply#
pub fn apply(self: &mut Self, input: &[u8], output: &mut [u8]) -> Result<(), AesError>XORs the next input.length bytes of key stream with input into output.
It writes input.length bytes. The bytes of output after them do not change. input and
output must not overlap.
Errors#
OutputTooSmallifoutputis shorter thaninput. The state does not change.
AesCfb#
pub struct AesCfbAES in full-block cipher feedback mode, CFB-128 (NIST SP 800-38A section 6.3).
When to use#
Use it where a protocol names AES-CFB, such as Node's aes-256-cfb. It does not detect changes
to the ciphertext. For new designs, use silk.crypto.aes_gcm.
Details#
The 16-byte IV is the first input block. Each key stream block is the encryption of the
previous 16 ciphertext bytes, so encryption and decryption differ: make the value with
AesCfb.encryptor or AesCfb.decryptor. AesCfb.apply takes the data in any split and
gives the same result. Nothing allocates.
Gotchas#
The same key and IV must never encrypt two messages. The value holds key material and is not erased when it is dropped.
Implementation AesCfb#
impl AesCfbAssociated function encryptor#
pub fn encryptor(key: &[u8], iv: &[u8]) -> Result<AesCfb, AesError>Returns a CFB-128 encryptor for key and iv.
Errors#
InvalidKeyLengthifkeyis not 16, 24, or 32 bytes.InvalidIvLengthifivis not 16 bytes.
Associated function decryptor#
pub fn decryptor(key: &[u8], iv: &[u8]) -> Result<AesCfb, AesError>Returns a CFB-128 decryptor for key and iv.
Errors#
InvalidKeyLengthifkeyis not 16, 24, or 32 bytes.InvalidIvLengthifivis not 16 bytes.
Method apply#
pub fn apply(self: &mut Self, input: &[u8], output: &mut [u8]) -> Result<(), AesError>Encrypts or decrypts input into the first input.length bytes of output.
The bytes of output after them do not change. input and output must not overlap.
Errors#
OutputTooSmallifoutputis shorter thaninput. The state does not change.
AesCfb8#
pub struct AesCfb8AES in 8-bit cipher feedback mode, CFB-8 (NIST SP 800-38A section 6.3).
When to use#
Use it where a protocol names AES-CFB8, such as Node's aes-128-cfb8. It does not detect
changes to the ciphertext, and it runs one block encryption per byte.
Details#
The 16-byte IV is the first shift register. For each byte, the first byte of the encrypted
register is the key stream byte, and the register shifts left by one byte and takes the
ciphertext byte. Make the value with AesCfb8.encryptor or AesCfb8.decryptor. Nothing
allocates.
Gotchas#
The same key and IV must never encrypt two messages. The value holds key material and is not erased when it is dropped.
Implementation AesCfb8#
impl AesCfb8Associated function encryptor#
pub fn encryptor(key: &[u8], iv: &[u8]) -> Result<AesCfb8, AesError>Returns a CFB-8 encryptor for key and iv.
Errors#
InvalidKeyLengthifkeyis not 16, 24, or 32 bytes.InvalidIvLengthifivis not 16 bytes.
Associated function decryptor#
pub fn decryptor(key: &[u8], iv: &[u8]) -> Result<AesCfb8, AesError>Returns a CFB-8 decryptor for key and iv.
Errors#
InvalidKeyLengthifkeyis not 16, 24, or 32 bytes.InvalidIvLengthifivis not 16 bytes.
Method apply#
pub fn apply(self: &mut Self, input: &[u8], output: &mut [u8]) -> Result<(), AesError>Encrypts or decrypts input into the first input.length bytes of output.
The bytes of output after them do not change. input and output must not overlap.
Errors#
OutputTooSmallifoutputis shorter thaninput. The state does not change.
AesCfb1#
pub struct AesCfb1AES in 1-bit cipher feedback mode, CFB-1 (NIST SP 800-38A section 6.3).
When to use#
Use it where a protocol names AES-CFB1, such as Node's aes-128-cfb1. It does not detect
changes to the ciphertext, and it runs one block encryption per bit, so it is slow.
Details#
The 16-byte IV is the first shift register. Each byte is taken as eight bits, most significant
first, as OpenSSL does for byte input. For each bit, the top bit of the encrypted register is
the key stream bit, and the register shifts left by one bit and takes the ciphertext bit. Make
the value with AesCfb1.encryptor or AesCfb1.decryptor. Nothing allocates.
Gotchas#
The same key and IV must never encrypt two messages. The value holds key material and is not erased when it is dropped.
Implementation AesCfb1#
impl AesCfb1Associated function encryptor#
pub fn encryptor(key: &[u8], iv: &[u8]) -> Result<AesCfb1, AesError>Returns a CFB-1 encryptor for key and iv.
Errors#
InvalidKeyLengthifkeyis not 16, 24, or 32 bytes.InvalidIvLengthifivis not 16 bytes.
Associated function decryptor#
pub fn decryptor(key: &[u8], iv: &[u8]) -> Result<AesCfb1, AesError>Returns a CFB-1 decryptor for key and iv.
Errors#
InvalidKeyLengthifkeyis not 16, 24, or 32 bytes.InvalidIvLengthifivis not 16 bytes.
Method apply#
pub fn apply(self: &mut Self, input: &[u8], output: &mut [u8]) -> Result<(), AesError>Encrypts or decrypts input into the first input.length bytes of output.
The bytes of output after them do not change. input and output must not overlap.
Errors#
OutputTooSmallifoutputis shorter thaninput. The state does not change.
AesOfb#
pub struct AesOfbAES in output feedback mode, OFB (NIST SP 800-38A section 6.4).
When to use#
Use it where a protocol names AES-OFB, such as Node's aes-256-ofb. It does not detect changes
to the ciphertext. For new designs, use silk.crypto.aes_gcm.
Details#
The 16-byte IV is encrypted again and again to give the key stream, so it does not depend on the
data and AesOfb.apply both encrypts and decrypts. The result does not depend on how the data
is split. Nothing allocates.
Gotchas#
The same key and IV must never encrypt two messages. If they do, the XOR of the two ciphertexts is the XOR of the two plaintexts. The value holds key material and is not erased when it is dropped.
Implementation AesOfb#
impl AesOfbAssociated function make#
pub fn make(key: &[u8], iv: &[u8]) -> Result<AesOfb, AesError>Returns an OFB key stream for key and iv.
Errors#
InvalidKeyLengthifkeyis not 16, 24, or 32 bytes.InvalidIvLengthifivis not 16 bytes.
Method apply#
pub fn apply(self: &mut Self, input: &[u8], output: &mut [u8]) -> Result<(), AesError>XORs the next input.length bytes of key stream with input into output.
The bytes of output after them do not change. input and output must not overlap.
Errors#
OutputTooSmallifoutputis shorter thaninput. The state does not change.
Category: Cryptography.
Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, wasm32-wasip1, wasm32-wasip2, x86_64-pc-windows-msvc, wasm64-unknown-unknown.