silk.crypto.block_cipher.
Run any block cipher in the standard modes: ECB, CBC, CTR, CFB, CFB-8, CFB-1, and OFB.
When to use#
Use these modes with a cipher that conforms to BlockCipher, such as silk.crypto.sm4,
silk.crypto.aria, silk.crypto.camellia, or silk.crypto.des, when a format or a name such
as sm4-cbc or des-ede3-cfb8 in OpenSSL or Node.js asks for one. None of the modes detect
changes to the ciphertext. For new designs, use silk.crypto.aes_gcm or
silk.crypto.chacha20_poly1305. AES has its own faster mode types in silk.crypto.aes.
Details#
A cipher has a block of 8 or 16 bytes, and the IV of each mode is one block. Each mode takes the
cipher by value, so make the cipher first, for example with Sm4.make. Ecb and Cbc
buffer partial blocks and can add and remove PKCS #7 padding, with updateLength, update, and
finish as in silk.crypto.aes. Ctr, Cfb, Cfb8, Cfb1, and Ofb are stream
modes: apply writes one output byte for each input byte, and the output does not depend on how
the input was split. CTR counts with the whole block as one big-endian number, as OpenSSL does.
CFB-1 handles whole bytes, most significant bit first. Nothing allocates.
Errors#
The functions return a BlockCipherError. On an error the output does not change, and the
state does not change.
Gotchas#
Never use one key and IV for two messages in CTR, CFB, or OFB: the XOR of the ciphertexts gives away the XOR of the plaintexts. A wrong padding error from a CBC decryptor can act as an oracle, so authenticate the ciphertext first. The mode values hold key material and are not erased when they are dropped.
Examples#
Encrypt with SM4-CBC#
import silk.crypto.block_cipher { BlockCipherError, Cbc }
import silk.crypto.sm4 { Sm4 }
import silk.core.result { Result }
pub fn main() -> i32 {
let key: [u8; 16] = [1; 16]
let iv: [u8; 16] = [2; 16]
let cipher = match Sm4.make(&key) {
Result<Sm4, BlockCipherError>.Success { value } => move value
Result<Sm4, BlockCipherError>.Failure { error: _ } => {
return 1
}
}
let mut encryptor = match Cbc<Sm4>.encryptor(move cipher, &iv, true) {
Result<Cbc<Sm4>, BlockCipherError>.Success { value } => move value
Result<Cbc<Sm4>, BlockCipherError>.Failure { error: _ } => {
return 1
}
}
let mut ciphertext: [u8; 16] = [0; 16]
let written = match encryptor.update(b"hello", &mut ciphertext) {
Result<usize, BlockCipherError>.Success { value } => value
Result<usize, BlockCipherError>.Failure { error: _ } => {
return 1
}
}
// Five bytes are kept until `finish`, which pads them to one block.
if written != 0 {
return 1
}
let last = match encryptor.finish(&mut ciphertext) {
Result<usize, BlockCipherError>.Success { value } => value
Result<usize, BlockCipherError>.Failure { error: _ } => {
return 1
}
}
if last != 16 {
return 1
}
return 0
}Import as BlockCipher with import silk.crypto.block_cipher { BlockCipher }.
Public declarations: 9.
BlockCipher#
pub interface BlockCipherA block cipher that the modes of this module can run.
Details#
The block is 8 or 16 bytes. The functions take a 16-byte array and use only its first
blockLength bytes; the rest do not change.
Operation blockLength#
fn blockLength(self: &Self) -> usizeReturns the block length in bytes, 8 or 16.
Operation encryptBlock#
fn encryptBlock(self: &Self, block: &mut [u8; 16]) -> ()Encrypts the first blockLength bytes of block in place.
Operation decryptBlock#
fn decryptBlock(self: &Self, block: &mut [u8; 16]) -> ()Decrypts the first blockLength bytes of block in place.
BlockCipherError#
pub union BlockCipherErrorThe reason that a block cipher or mode function rejected a call. The output and the state do not change.
InvalidKeyLength#
InvalidKeyLengthThe key length is not one that the cipher takes.
InvalidIvLength#
InvalidIvLengthThe IV is not one block long.
OutputTooSmall#
OutputTooSmallThe output buffer is shorter than the bytes the call writes.
InvalidInputLength#
InvalidInputLengthWithout padding, the message is not a whole number of 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 BlockCipherError#
impl Debug for BlockCipherErrorOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant, such as InvalidKeyLength.
Ecb#
pub struct Ecb<C>A streaming ECB encryptor or decryptor over the cipher C, with or without PKCS #7 padding.
When to use#
Use it only when a format requires ECB, such as sm4-ecb or des-ede3-ecb. ECB encrypts equal
blocks to equal blocks, so it shows patterns in the data.
Details#
Make one with Ecb.encryptor or Ecb.decryptor, call Ecb.update for each part of the
input, then Ecb.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.
Implementation Ecb<C>#
impl<C: BlockCipher> Ecb<C>Associated function encryptor#
pub fn encryptor(cipher: C, padding: bool) -> Ecb<C>Returns an encryptor that owns cipher. With padding, Ecb.finish adds PKCS #7 padding,
so any message length is valid.
Associated function decryptor#
pub fn decryptor(cipher: C, padding: bool) -> Ecb<C>Returns a decryptor that owns cipher. With padding, Ecb.finish checks and removes
PKCS #7 padding.
Method updateLength#
pub fn updateLength(self: &Self, length: usize) -> usizeReturns the number of bytes that Ecb.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, BlockCipherError>Encrypts or decrypts the whole blocks of the kept bytes plus input into output, keeps the
rest, and returns the number of bytes written, which is Ecb.updateLength of
input.length. The bytes of output after it do not change. input and output must not
overlap.
Errors#
OutputTooSmallifoutputis shorter thanEcb.updateLength.
Method finish#
pub fn finish(self: Self, output: &mut [u8]) -> Result<usize, BlockCipherError>Ends the message, writes the last bytes to output, returns their number, and consumes the
state.
An encryptor with padding writes one block. A decryptor with padding writes 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.
Cbc#
pub struct Cbc<C>A streaming CBC encryptor or decryptor over the cipher C (NIST SP 800-38A), with or without
PKCS #7 padding.
When to use#
Use it when a format names CBC with this cipher, such as sm4-cbc, camellia-256-cbc, or
des-ede3-cbc.
Details#
Make one with Cbc.encryptor or Cbc.decryptor, call Cbc.update for each part of the
input, then Cbc.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
IV is one block.
Gotchas#
Use a new random IV for each message under the same key.
Implementation Cbc<C>#
impl<C: BlockCipher> Cbc<C>Associated function encryptor#
pub fn encryptor(cipher: C, iv: &[u8], padding: bool) -> Result<Cbc<C>, BlockCipherError>Returns an encryptor that owns cipher, for iv. With padding, Cbc.finish adds
PKCS #7 padding, so any message length is valid.
Errors#
InvalidIvLengthifivis not one block.
Associated function decryptor#
pub fn decryptor(cipher: C, iv: &[u8], padding: bool) -> Result<Cbc<C>, BlockCipherError>Returns a decryptor that owns cipher, for iv. With padding, Cbc.finish checks and
removes PKCS #7 padding.
Errors#
InvalidIvLengthifivis not one block.
Method updateLength#
pub fn updateLength(self: &Self, length: usize) -> usizeReturns the number of bytes that Cbc.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, BlockCipherError>Encrypts or decrypts the whole blocks of the kept bytes plus input into output, keeps the
rest, and returns the number of bytes written, which is Cbc.updateLength of
input.length. The bytes of output after it do not change. input and output must not
overlap.
Errors#
OutputTooSmallifoutputis shorter thanCbc.updateLength.
Method finish#
pub fn finish(self: Self, output: &mut [u8]) -> Result<usize, BlockCipherError>Ends the message, writes the last bytes to output, returns their number, and consumes the
state.
An encryptor with padding writes one block. A decryptor with padding writes 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.
Ctr#
pub struct Ctr<C>A CTR key stream over the cipher C (NIST SP 800-38A). The same call encrypts and decrypts.
When to use#
Use it when a format names CTR with this cipher, such as sm4-ctr or aria-128-ctr.
Details#
The IV is the first counter block. The counter is the whole block as one big-endian number and wraps to zero after all ones, as OpenSSL does.
Implementation Ctr<C>#
impl<C: BlockCipher> Ctr<C>Associated function make#
pub fn make(cipher: C, iv: &[u8]) -> Result<Ctr<C>, BlockCipherError>Returns a key stream that owns cipher, starting at the counter block iv.
Errors#
InvalidIvLengthifivis not one block.
Method apply#
pub fn apply(self: &mut Self, input: &[u8], output: &mut [u8]) -> Result<(), BlockCipherError>Writes input XOR the next input.length key stream bytes to the first input.length
bytes of output.
Errors#
OutputTooSmallifoutputis shorter thaninput.
Cfb#
pub struct Cfb<C>A CFB encryptor or decryptor with full-block feedback over the cipher C (NIST SP 800-38A).
When to use#
Use it when a format names CFB with this cipher, such as sm4-cfb or des-ede3-cfb, which is
CFB with feedback of one block.
Implementation Cfb<C>#
impl<C: BlockCipher> Cfb<C>Associated function encryptor#
pub fn encryptor(cipher: C, iv: &[u8]) -> Result<Cfb<C>, BlockCipherError>Returns an encryptor that owns cipher, for iv.
Errors#
InvalidIvLengthifivis not one block.
Associated function decryptor#
pub fn decryptor(cipher: C, iv: &[u8]) -> Result<Cfb<C>, BlockCipherError>Returns a decryptor that owns cipher, for iv.
Errors#
InvalidIvLengthifivis not one block.
Method apply#
pub fn apply(self: &mut Self, input: &[u8], output: &mut [u8]) -> Result<(), BlockCipherError>Encrypts or decrypts input into the first input.length bytes of output.
Errors#
OutputTooSmallifoutputis shorter thaninput.
Cfb8#
pub struct Cfb8<C>A CFB encryptor or decryptor with 8-bit feedback over the cipher C (NIST SP 800-38A).
When to use#
Use it when a format names CFB-8 with this cipher, such as aria-128-cfb8 or des-ede3-cfb8.
Details#
Each byte costs one block encryption.
Implementation Cfb8<C>#
impl<C: BlockCipher> Cfb8<C>Associated function encryptor#
pub fn encryptor(cipher: C, iv: &[u8]) -> Result<Cfb8<C>, BlockCipherError>Returns an encryptor that owns cipher, for iv.
Errors#
InvalidIvLengthifivis not one block.
Associated function decryptor#
pub fn decryptor(cipher: C, iv: &[u8]) -> Result<Cfb8<C>, BlockCipherError>Returns a decryptor that owns cipher, for iv.
Errors#
InvalidIvLengthifivis not one block.
Method apply#
pub fn apply(self: &mut Self, input: &[u8], output: &mut [u8]) -> Result<(), BlockCipherError>Encrypts or decrypts input into the first input.length bytes of output.
Errors#
OutputTooSmallifoutputis shorter thaninput.
Cfb1#
pub struct Cfb1<C>A CFB encryptor or decryptor with 1-bit feedback over the cipher C (NIST SP 800-38A).
When to use#
Use it when a format names CFB-1 with this cipher, such as camellia-128-cfb1 or
des-ede3-cfb1.
Details#
It handles whole bytes, most significant bit first, as OpenSSL does for a length in bytes. Each bit costs one block encryption.
Implementation Cfb1<C>#
impl<C: BlockCipher> Cfb1<C>Associated function encryptor#
pub fn encryptor(cipher: C, iv: &[u8]) -> Result<Cfb1<C>, BlockCipherError>Returns an encryptor that owns cipher, for iv.
Errors#
InvalidIvLengthifivis not one block.
Associated function decryptor#
pub fn decryptor(cipher: C, iv: &[u8]) -> Result<Cfb1<C>, BlockCipherError>Returns a decryptor that owns cipher, for iv.
Errors#
InvalidIvLengthifivis not one block.
Method apply#
pub fn apply(self: &mut Self, input: &[u8], output: &mut [u8]) -> Result<(), BlockCipherError>Encrypts or decrypts input into the first input.length bytes of output.
Errors#
OutputTooSmallifoutputis shorter thaninput.
Ofb#
pub struct Ofb<C>An OFB key stream over the cipher C (NIST SP 800-38A). The same call encrypts and decrypts.
When to use#
Use it when a format names OFB with this cipher, such as sm4-ofb or des-ede3-ofb.
Implementation Ofb<C>#
impl<C: BlockCipher> Ofb<C>Associated function make#
pub fn make(cipher: C, iv: &[u8]) -> Result<Ofb<C>, BlockCipherError>Returns a key stream that owns cipher, for iv.
Errors#
InvalidIvLengthifivis not one block.
Method apply#
pub fn apply(self: &mut Self, input: &[u8], output: &mut [u8]) -> Result<(), BlockCipherError>Writes input XOR the next input.length key stream bytes to the first input.length
bytes of output.
Errors#
OutputTooSmallifoutputis shorter thaninput.
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.