rustcrypto / block-ciphers Goto Github PK
View Code? Open in Web Editor NEWCollection of block cipher algorithms written in pure Rust
Collection of block cipher algorithms written in pure Rust
Similar to aesni
crate it would be nice to have hardware accelerated AES support for ARM using specialized instructions.
Tests can be found here. DES fails sets 5, 7 and 8.
Apache-2.0 requires license text to be shipped along with the sources. MIT does not, but there are tens of MIT variants, so please include it too..
Thanks!
My program sometimes fails, with the BlockModeError
and I have no clue why. The documentation and error message don't help either. I also can't find any code, that constructs a BlockModeError
in this repository?
What does cause a BlockModeError
? Which part of the input causes the error?
I think the documentation and the fmt::Display
should answer those questions.
I am using Aes128Cbc
(type Aes128Cbc = Cbc<Aes128, Pkcs7>
)
Hi,
I have push months ago the crate serpent
but as you can see here https://crates.io/crates/serpent the version is still 0.0.0
. Is a new cargo publish
required?
BlockCipher.encrypt
work in-place, and no allocate. So I need to calculate the buffer size manually.
my question :
block_size
method to BlockCipher
?use std::error;
use aes::block_cipher::{generic_array::typenum::Unsigned, BlockCipher};
use aes::Aes128;
use block_modes::{block_padding::Pkcs7, BlockMode, Cbc};
type Aes128Cbc = Cbc<Aes128, Pkcs7>;
type Byte = u8;
fn aes128_cbc_encrypt(
plaintext: &[Byte],
key: &[Byte],
iv: &[Byte],
) -> Result<Vec<Byte>, Box<dyn error::Error>> {
// pading只是做对齐, 但是这个对齐是in-place, 这个buf还是需要自己申请大小以满足条件
// pading just fill, no allocate
// =======================================
let block_size = <Aes128 as BlockCipher>::BlockSize::to_usize();
let padding_length = block_size - plaintext.len() % block_size;
// =======================================
let cipher = Aes128Cbc::new_var(&key, &iv)?;
let mut buffer = Vec::with_capacity(padding_length + plaintext.len());
buffer.resize(padding_length + plaintext.len(), 0u8);
// unsafe { buffer.set_len(padding_length+plaintext.len()); }
buffer[..plaintext.len()].copy_from_slice(plaintext);
//let ciphertext = cipher.encrypt(&mut buffer, plaintext.len())?;
cipher.encrypt(&mut buffer, plaintext.len())?;
Ok(buffer)
}
Cargo.toml
[dependencies]
block-modes="0.4.0"
aes="0.4.0
When building a project importing aes=0.3.2
with -Ctarget-feature=+aes,+sse2,+ssse3
compilation works ok, but cargo doc
fails with:
error: enable aes target feature, e.g. with RUSTFLAGS="-C target-feature=+aes" enviromental variable. For x86 target arch additionally enable sse2 target feature.
--> /home/adria/.cargo/registry/src/github.com-1ecc6299db9ec823/aesni-0.6.0/src/target_checks.rs:19:1
|
19 | / compile_error!(
20 | | "enable aes target feature, e.g. with \
21 | | RUSTFLAGS=\"-C target-feature=+aes\" enviromental variable. \
22 | | For x86 target arch additionally enable sse2 target feature."
23 | | );
| |__^
[package]
name = "test1"
version = "0.1.0"
edition = "2018"
[dependencies]
aes = { version = "0.3.2" }
# Enables the aes-ni instructions for RustCrypto dependency.
[target.x86_64-unknown-linux-gnu]
rustflags = ["-Ctarget-feature=+aes,+sse2,+ssse3"]
use aes::block_cipher_trait::generic_array::GenericArray;
use aes::block_cipher_trait::BlockCipher;
use aes::Aes128;
fn main() {
let key = GenericArray::from_slice(&[0u8; 16]);
let mut block = GenericArray::clone_from_slice(&[0u8; 16]);
let mut block8 = GenericArray::clone_from_slice(&[block; 8]);
// Initialize cipher
let cipher = Aes128::new(&key);
let block_copy = block.clone();
// Encrypt block in-place
cipher.encrypt_block(&mut block);
// And decrypt it back
cipher.decrypt_block(&mut block);
assert_eq!(block, block_copy);
// We can encrypt 8 blocks simultaneously using
// instruction-level parallelism
let block8_copy = block8.clone();
cipher.encrypt_blocks(&mut block8);
cipher.decrypt_blocks(&mut block8);
assert_eq!(block8, block8_copy);
}
cc/ https://github.com/openethereum/openethereum/issues/11596
Recently added Threefish is a tweakable block cipher, thus we need an appropriate trait for it.
Currently I am thinking of using this:
pub trait TweakableBlockCipher {
type BlockSize: ArrayLength<u8>;
type TweakSize: ArrayLength<u8>;
fn encrypt(&self, block: &mut Block<Self::BlockSize>, tweak: &Block<Self::TweakSize>);
fn decrypt(&self, block: &mut Block<Self::BlockSize>, tweak: &Block<Self::TweakSize>);
}
In addition to it I think tweakable ciphers should auto implement BlockCipher
using zero tweak.
8 was ostensibly chosen because this used to be the optimal number of AES-NI blocks to compute in parallel. From Shay Gueron's RWC 2013 talk [1]:
However on newer Intel architectures, equivalent performance can be had with 4 blocks [2], and the forthcoming vectorized AES-NI instructions ("VAES") will leverage AVX512 and operate on 4 AES blocks as well (4 x 128-bit = 512-bit) [3].
4 blocks is also the optimal number for a 64-bit fixsicing implementation (#180). For a 32-bit implementation, it's twice as many blocks as are necessary, but we can just double the 2-block implementation. Alternatively we could look at using ParBlocks = 2
on 32-bit architectures.
Should we reduce the number of parallel blocks to 4? It seems like it most closely aligns with various implementations. Would it make sense to make it smaller on 32-bit architectures, or would that be too much of a pain?
Hello I'm attempting to switch from OpenSSL to this module but it is returning BlockModeError when decrypting/encrypting in CFB mode with a non-multiple of block size. Example program:
extern crate aes;
extern crate block_modes;
use aes::block_cipher_trait::generic_array::GenericArray;
use aes::Aes128;
use block_modes::{BlockMode, BlockModeIv, Cfb};
use block_modes::block_padding::ZeroPadding;
type Aes128Cfb = Cfb<Aes128, ZeroPadding>;
const N: usize = 32;
fn main() {
let key = &[71, 174, 234, 93, 242, 208, 116, 243, 124, 41, 213, 92, 130, 106, 100, 61];
{
let mut cipher = Aes128Cfb::new_varkey(key, GenericArray::from_slice(key)).unwrap();
println!("enabling encryption with key={:?}", key);
println!("encrypting");
let mut data: [u8; N] = [42; N];
println!("data = {:?}", data);
//data.clone_from_slice(&buf);
cipher.encrypt_nopad(&mut data).expect("failed to encrypt");
println!("data = {:?}", data);
}
{
let mut cipher = Aes128Cfb::new_varkey(key, GenericArray::from_slice(key)).unwrap();
let mut data = [3, 183, 34, 56, 139, 222, 104, 78, 232, 246, 32, 183, 49, 151, 255, 163, 144, 145, 145, 75, 255, 63, 208, 64, 219, 243, 43, 234, 93, 187, 207, 138];
cipher.decrypt_nopad(&mut data).expect("failed to decrypt");
println!("decrypted = {:?}", data);
}
}
succeeds with N=32 but change to not a multiple, example N=1, fails:
enabling encryption with key=[71, 174, 234, 93, 242, 208, 116, 243, 124, 41, 213, 92, 130, 106, 100, 61]
encrypting
data = [42]
thread 'main' panicked at 'failed to encrypt: BlockModeError', libcore/result.rs:1009:5
block-ciphers/block-modes/src/cfb.rs
Line 51 in 00e542e
if buffer.len() % bs != 0 {
Err(BlockModeError)?
}
so multiples of block size will fail with all modes. This is of course expected with most of the modes, but with CFB, decrypting/encrypting any number of bits is allowed: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_Feedback_(CFB)
The Cipher Feedback (CFB) mode, a close relative of CBC, makes a block cipher into a self-synchronizing stream cipher.
and it works with OpenSSL. Any ideas of how to accomplish this using RustCrypto. It seems padding is mandatory with this module. Should CFB be implemented in https://github.com/RustCrypto/stream-ciphers?
Right now we have to define an empty enum and implement for it the Sbox
trait, which contains S-box value. It would be nice to replace it with struct Gost89<const SBOX: [[u8; 16]; 8]> { .. }
and perform expansion using const fn
.
This seems like a very silly error to me, but I have never encountered anything like this before. I wanted to test out aesni
and have the following code
extern crate aesni;
use aesni::{Aes128, BlockCipher};
fn main() {
let key = vec![0u8; 16];
let cipher = aesni::Aes128::new(&key);
}
And this in the Cargo.toml dependencies aesni = "0.3.1"
. When trying to build this I receive the following error:
error[E0432]: unresolved import `aesni::Aes128`
--> src/main.rs:3:13
|
3 | use aesni::{Aes128, BlockCipher};
| ^^^^^^ no `Aes128` in the root
error[E0432]: unresolved import `aesni::BlockCipher`
--> src/main.rs:3:21
|
3 | use aesni::{Aes128, BlockCipher};
| ^^^^^^^^^^^ no `BlockCipher` in the root
Building with stable and nightly yields the same result.
This is a re-post of RustCrypto/stream-ciphers#108 , as a bug in aesni
is likely the root cause
Hello,
I got an issue with current_pos
on Aes256Ctr
while compiling with the recommended flags from the README.
To reproduce:
use aes_ctr;
use aes_ctr::stream_cipher::{NewStreamCipher, SyncStreamCipherSeek};
fn main() {
let key = [0u8; 32];
let counter_block = [0u8; 16];
// Prepare the cipher for further operations
let mut cipher = aes_ctr::Aes256Ctr::new_var(&key, &counter_block).unwrap();
cipher.seek(16);
println!("{}", cipher.current_pos());
}
[dependencies]
aes-ctr = "0"
$ cargo version
cargo 1.42.0 (86334295e 2020-01-31)
Here's what I obtain:
$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.01s
Running `target/debug/test_aes`
16
$ cargo run --release
Finished release [optimized] target(s) in 0.01s
Running `target/release/test_aes`
16
$ RUSTFLAGS="-C target-feature=+aes,+ssse3" cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.01s
Running `target/debug/test_aes`
0
$ RUSTFLAGS="-C target-feature=+aes,+ssse3" cargo run --release
Finished release [optimized] target(s) in 0.01s
Running `target/release/test_aes`
0
Am I doing something wrong?
Instead of .seek
, I've also tried with:
let mut temp = [0u8; 0x1000];
cipher.encrypt(&mut temp);
println!("{}", cipher.current_pos());
Leading to the same incoherent result.
Regarding rustc flags:
+aes,+sse2
, +aes
, +ssse3
lead to correct results+aes,+ssse3
leads to the result aboveAs a side note, the encryption is still keeping its internal state correctly, ie:
fn main() {
let key = [0u8; 32];
let counter_block = [0u8; 16];
// Prepare the cipher for further operations
let mut cipher = aes_ctr::Aes256Ctr::new_var(&key, &counter_block).unwrap();
let mut temp = [0u8; 0x1000];
cipher.encrypt(&mut temp);
println!("{:?}", &temp[..32]);
let mut temp2 = [0u8; 0x1000];
cipher.encrypt(&mut temp2);
println!("{:?}", &temp2[..32]);
println!("{}", cipher.current_pos());
}
Returns, with flags:
[220, 149, 192, 120, 162, 64, 137, 137, 173, 72, 162, 20, 146, 132, 32, 135, 83, 15, 138, 251, 199, 69, 54, 185, 169, 99, 180, 241, 196, 203, 115, 139]
[199, 233, 210, 80, 153, 134, 50, 212, 68, 53, 98, 66, 239, 4, 5, 141, 76, 175, 60, 142, 190, 185, 242, 72, 214, 114, 3, 215, 138, 67, 126, 238]
0
I have the c# code as in this fiddle https://dotnetfiddle.net/5i95oJ
I wrote the following equivalent code using your library. But it does not produce the same result as c#. Both uses same cipher mode cbc and padding pckcs7. But the results are not same.
Can you help me in fixing the rust code to match the c# version so that i get the same result in rust.
use block_modes::block_padding::Pkcs7;
use block_modes::{BlockMode, Cbc};
use des::Des;
type DesCbc = Cbc<Des, Pkcs7>;
macro_rules! get_des_cipher_space {
($len:expr) => {{
(($len + 8) / 8) * 8 + ($len % 8)
}};
}
fn main() {
let key = b"12345678";
let iv = b"12345678";
let data = b"Balu";
let len = data.len();
let final_len = get_des_cipher_space!(len);
let mut buffer = Vec::with_capacity(final_len);
unsafe {
buffer.set_len(final_len);
}
buffer[..len].copy_from_slice(data);
let cipher = DesCbc::new_var(key, iv).unwrap();
let enc = base64::encode(&cipher.encrypt_vec(&buffer[..len]));
println!("{:?}", enc);
}
Could somebody provide a usage example for AES192, please~
I cannot work out a runnable example based on the existent AES128 example in https://docs.rs/aes-soft/0.3.3/aes_soft/#usage-example.
Really appreciate if someone can help~
I'm not sure on which repo to ask this, but is there any plans to implements GCM and other authenticated modes to the project? The original https://github.com/DaGenix/rust-crypto/ crate has already done it.
I need to do just one round of encryption, to replicate something like this:
var key = Aes.cipher(pwBytes, Aes.keyExpansion(pwBytes));
Afaik I currently cannot do that, since those are in a private module.
Hopefully I'm completely wrong and what I need is available in another RustCrypto
crate.
Hi,
Do you plan to implement the Serpent algorithm a few times? 😊
Best regards
Is there any performance measurements of AES128 (CBC) against other common packages, e.g. openssl
?
I've done a simple non-scientific performance measurement compared with openssl
, and the result showing it's about 7x slower than openssl
. I was surprised and wanted to check what others have seen.
my test: (AES128 CBC)
step 1. generates a random string of 50 chars (using rand
crate).
step 2. encrypt the plain string.
step 3. decrypt the encrypted.
step 4. assert the result is same as the plain string.
Repeat step 1-4 for 100 times.
block-ciphers
: 58ms total, openssl
8ms total.
As the title says, is it necessary to always create a new instance of the cipher, let's say blowfish as in my use case whenever i wanna do padded en/decryption? I'm asking this because the block_mode trait functions almost all take self instead of a mutable or immutable reference. This seems insanely inefficient to me and not something I'd be happy with to use tbh for something like blowfish.
A newly released paper describes how to apply a bitslicing-like technique called "fixslicing" to AES:
https://eprint.iacr.org/2020/1123
Fixslicing AES-like Ciphers: New bitsliced AES speed records on ARM-Cortex M and RISC-V
The fixslicing implementation strategy was originally introduced as a new representation for the hardware-oriented GIFT block cipher to achieve very efficient software constant-time implementations. In this article, we show that the fundamental idea underlying the fixslicing technique is not of interest only for GIFT, but can be applied to other ciphers as well. Especially, we study the benefits of fixslicing in the case of AES and show that it allows to reduce by 41% the amount of operations required by the linear layer when compared to the current fastest bitsliced implementation on 32-bit platforms. Overall, we report that fixsliced AES-128 allows to reach 83 and 99 cycles per byte on ARM Cortex-M and RISC-V respectively (assuming pre-computed round keys), improving the previous records on those platforms by 17% and 20%. In order to highlight that our work also directly improves masked implementations that rely on bitslicing, we report implementation results when integrating first-order masking that outperform by 12% the fastest results reported in the literature on ARM Cortex-M4. Finally, we demonstrate the genericity of the fixslicing technique for AES-like designs by applying it to the Skinny-128 tweakable block ciphers.
As part of the paper they've also posted portable C implementations we might consider translating:
https://github.com/aadomn/aes/tree/master/opt32/fixslicing
...along with optimized Cortex-M assembly we might consider integrating (optionally, behind a feature flag, possibly using the new inline ASM syntax):
https://github.com/aadomn/aes/tree/master/armcortexm/fixslicing
There are "wide" block ciphers with a run time configurable block size like AEZ, Lioness, and DJB's upcoming HHFHFH, so BlockCipher::BlockSize
should probably be replaced with an associated type, so that it can be configured at either compile time or run time according to the cipher.
I started to write a PR to just show how using #[target_feature]
would look like but I encountered too much undefined behavior in the process (fixing it was taking more time than actually dealing with target feature).
I've only taken a look at a tiny fraction of the aesni
crate, but it seems that references to uninitialized memory are created pretty much everywhere (all references must point to initialized memory [0]):
* https://github.com/RustCrypto/block-ciphers/blob/master/aes/aesni/src/aes128/expand.rs#L21
* https://github.com/RustCrypto/block-ciphers/blob/master/aes/aesni/src/aes128/expand.rs#L36
The way I fixed these was by using ptr::write
to write to uninitialized memory without creating a reference.
There are also reads memory out-of-bounds: https://github.com/RustCrypto/block-ciphers/blob/master/aes/aesni/src/aes192/expand.rs#L51
The way I fixed this was by creating a stack buffer of appropriate size in the mod.rs
file which I initialized with mem::uninitialized
, and then using ptr::write
to write the GenericArray
into the head of the buffer, so that the vector load never reads memory out of bounds - the memory read is only partially initialized though, and reading vector lanes with uninitialized memory should be done with care (so that no UB is introduced).
[0] &T as *const T
and &mut T as *mut T
might not end up being undefined behavior because they might end up being atomic operations in the memory model that create a raw pointer directly without creating a reference (so that no reference to uninitialized memory is ever created by these expressions, preventing them from invoking undefined behavior).
This example fails when compiled with target-cpu
"haswell" or more recent:
use aes_soft::{block_cipher_trait::BlockCipher, Aes128};
fn main() {
let plain = [127, 0, 0, 1, 174, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
let key = [0; 16];
let encrypted = [222, 157, 168, 71, 195, 237, 77, 237, 182, 194, 17, 235, 182, 214, 204, 80];
let output = encrypt(plain, key);
assert_eq!(output, encrypted);
println!("success");
}
fn encrypt(input: [u8; 16], key: [u8; 16]) -> [u8; 16] {
let key = key.into();
let mut block = input.into();
let cipher = Aes128::new(&key);
cipher.encrypt_block(&mut block);
block.into()
}
> RUSTFLAGS='-C target-cpu=ivybridge' cargo run --release
success
> RUSTFLAGS='-C target-cpu=haswell' cargo run --release
thread 'main' panicked at 'assertion failed: `(left == right)`
left: `[103, 175, 2, 16, 66, 180, 192, 20, 55, 121, 111, 21, 82, 184, 106, 59]`,
right: `[222, 157, 168, 71, 195, 237, 77, 237, 182, 194, 17, 235, 182, 214, 204, 80]`', src/main.rs:9:5
> RUSTFLAGS='-C target-cpu=broadwell' cargo run --release
thread 'main' panicked at 'assertion failed: `(left == right)`
left: `[103, 175, 2, 16, 66, 180, 192, 20, 55, 121, 111, 21, 82, 184, 106, 59]`,
right: `[222, 157, 168, 71, 195, 237, 77, 237, 182, 194, 17, 235, 182, 214, 204, 80]`', src/main.rs:9:5
> RUSTFLAGS='-C target-cpu=skylake' cargo run --release
thread 'main' panicked at 'assertion failed: `(left == right)`
left: `[103, 175, 2, 16, 66, 180, 192, 20, 55, 121, 111, 21, 82, 184, 106, 59]`,
right: `[222, 157, 168, 71, 195, 237, 77, 237, 182, 194, 17, 235, 182, 214, 204, 80]`', src/main.rs:9:5
I bumped into this when compiling with target-cpu=native
and assumed it was related to rust-lang/rust#54688, but after minimising the testcase I don't think it is. My next guess is an llvm bug but I thought I'd make an issue here in case anyone else bumps into it or wants to help investigate.
Occurs on stable:
rustc 1.37.0 (eae3437df 2019-08-13)
binary: rustc
commit-hash: eae3437dfe991621e8afdc82734f4a172d7ddf9b
commit-date: 2019-08-13
host: x86_64-apple-darwin
release: 1.37.0
LLVM version: 8.0
and nightly:
rustc 1.39.0-nightly (29a54035c 2019-08-19)
binary: rustc
commit-hash: 29a54035c77cb2ba7ea2c24b2437760d0495a2c8
commit-date: 2019-08-19
host: x86_64-apple-darwin
release: 1.39.0-nightly
LLVM version: 9.0
Tested on Broadwell (Intel(R) Xeon(R) CPU E5-2673 v3 @ 2.40GHz) and Skylake (Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz).
block-ciphers/block-modes/src/lib.rs
Lines 58 to 59 in bc219f9
In above, cipher
is immutable, but encrypt_vec
takes mutable self, see here:
block-ciphers/block-modes/src/traits.rs
Line 71 in bc219f9
I'm wondering how this works?
Please add some examples. For example, I need to know how to encrypt/decrypt a variable using the blowfish cipher. Thanks!
Any plans for implementing CTS mode? https://en.wikipedia.org/wiki/Ciphertext_stealing
In the current fixslice implementation there is some redundancy in the way keys are stored (2x for fixslice32, 4x for fixslice64). This enables the round keys to simply be XORed in for each round.
It is possible to store the round keys in a compact format and expand them in each round, which requires a few additional instructions (prototype code for fixslice64 puts this at 10% slower; the penalty will be smaller for fixslice32). The memory saving for the key storage is then: 50% i.e. 176/208/240 bytes for fixslice32 AES 128/192/256 respectively, or 75% i.e. 528/624/720 bytes for fixslice64.
Is there a standard cfg attribute for constrained memory devices, and/or should this project support a feature making smaller memory footprint a priority?
AES implementation should be chosen at runtime rather than compile time, otherwise it makes people very hard to ship products with this crate, because they cannot choose the environment a product would be run on.
hello, I have a question on AES CBC mode:
For large file, it's impossible to read the whole file and padding it one time, needs to read a small buffer (an integer multiple of aes_cbc block size) and encrypt it (without padding), repeat many times, finally, read the last part and padding, then encrypt it, done!
from the example, I found below codes, I guess the "cipher" will pad data automatically with Pkcs7 mode, it's not a problem for small file, but for a large file mentioned above, the first many rounds, I don't want to pad the data because the data is an integer multiple of aes_cbc block size, I just want to pad it at the last round, I don't know how to do that, can you please give some advice? Thanks in advance!
-------------code from example--------------------------
type Aes128Cbc = Cbc<Aes128, Pkcs7>;
let cipher = Aes128Cbc::new_var(key, &iv).unwrap();
...pass
let pos = plaintext.len();
buffer[..pos].copy_from_slice(plaintext);
let ciphertext = cipher.encrypt(&mut buffer, pos).unwrap();
-------------code from example--------------------------
The latest published version of block-mode does not seem to work with the latest published version of aes. The first example in the documentation does not compile.
[package]
name = "test-aes-cbc"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
block-modes = "0.3"
aes-soft = "0.4"
hex-literal = "0.2"
(taken from https://docs.rs/block-modes/latest/block_modes/index.html)
#[macro_use] extern crate hex_literal;
extern crate aes_soft as aes;
extern crate block_modes;
use block_modes::{BlockMode, Cbc};
use block_modes::block_padding::Pkcs7;
use aes::Aes128;
// create an alias for convinience
type Aes128Cbc = Cbc<Aes128, Pkcs7>;
fn main() {
let key = hex!("000102030405060708090a0b0c0d0e0f");
let iv = hex!("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff");
let plaintext = b"Hello world!";
let cipher = Aes128Cbc::new_var(&key, &iv).unwrap();
// buffer must have enough space for message+padding
let mut buffer = [0u8; 32];
// copy message to the buffer
let pos = plaintext.len();
buffer[..pos].copy_from_slice(plaintext);
let ciphertext = cipher.encrypt(&mut buffer, pos).unwrap();
assert_eq!(ciphertext, hex!("1b7a4c403124ae2fb52bedc534d82fa8"));
// re-create cipher mode instance
let cipher = Aes128Cbc::new_var(&key, &iv).unwrap();
let mut buf = ciphertext.to_vec();
let decrypted_ciphertext = cipher.decrypt(&mut buf).unwrap();
assert_eq!(decrypted_ciphertext, plaintext);
}
Compiling test-aes-cbc v0.1.0 (/tmp/test-aes-cbc)
error[E0599]: no function or associated item named `new_var` found for struct `block_modes::Cbc<aes::Aes128, block_modes::block_padding::Pkcs7>` in the current scope
--> src/main.rs:16:29
|
16 | let cipher = Aes128Cbc::new_var(&key, &iv).unwrap();
| ^^^^^^^ function or associated item not found in `block_modes::Cbc<aes::Aes128, block_modes::block_padding::Pkcs7>`
|
::: /home/ophir/.cargo/registry/src/github.com-1ecc6299db9ec823/block-modes-0.3.3/src/cbc.rs:12:1
|
12 | pub struct Cbc<C: BlockCipher, P: Padding> {
| ------------------------------------------ doesn't satisfy `_: block_modes::BlockMode<aes::Aes128, block_modes::block_padding::Pkcs7>`
|
::: /home/ophir/.cargo/registry/src/github.com-1ecc6299db9ec823/aes-soft-0.4.0/src/impls.rs:28:9
|
28 | pub struct $name {
| ---------------- doesn't satisfy `aes::Aes128: block_cipher_trait::BlockCipher`
|
= note: the method `new_var` exists but the following trait bounds were not satisfied:
`aes::Aes128: block_cipher_trait::BlockCipher`
which is required by `block_modes::Cbc<aes::Aes128, block_modes::block_padding::Pkcs7>: block_modes::BlockMode<aes::Aes128, block_modes::block_padding::Pkcs7>`
error[E0277]: the trait bound `aes::Aes128: block_cipher_trait::BlockCipher` is not satisfied
--> src/main.rs:16:18
|
16 | let cipher = Aes128Cbc::new_var(&key, &iv).unwrap();
| ^^^^^^^^^^^^^^^^^^ the trait `block_cipher_trait::BlockCipher` is not implemented for `aes::Aes128`
|
::: /home/ophir/.cargo/registry/src/github.com-1ecc6299db9ec823/block-modes-0.3.3/src/cbc.rs:12:19
|
12 | pub struct Cbc<C: BlockCipher, P: Padding> {
| ----------- required by this bound in `block_modes::Cbc`
error[E0599]: no function or associated item named `new_var` found for struct `block_modes::Cbc<aes::Aes128, block_modes::block_padding::Pkcs7>` in the current scope
--> src/main.rs:28:29
|
28 | let cipher = Aes128Cbc::new_var(&key, &iv).unwrap();
| ^^^^^^^ function or associated item not found in `block_modes::Cbc<aes::Aes128, block_modes::block_padding::Pkcs7>`
|
::: /home/ophir/.cargo/registry/src/github.com-1ecc6299db9ec823/block-modes-0.3.3/src/cbc.rs:12:1
|
12 | pub struct Cbc<C: BlockCipher, P: Padding> {
| ------------------------------------------ doesn't satisfy `_: block_modes::BlockMode<aes::Aes128, block_modes::block_padding::Pkcs7>`
|
::: /home/ophir/.cargo/registry/src/github.com-1ecc6299db9ec823/aes-soft-0.4.0/src/impls.rs:28:9
|
28 | pub struct $name {
| ---------------- doesn't satisfy `aes::Aes128: block_cipher_trait::BlockCipher`
|
= note: the method `new_var` exists but the following trait bounds were not satisfied:
`aes::Aes128: block_cipher_trait::BlockCipher`
which is required by `block_modes::Cbc<aes::Aes128, block_modes::block_padding::Pkcs7>: block_modes::BlockMode<aes::Aes128, block_modes::block_padding::Pkcs7>`
error[E0277]: the trait bound `aes::Aes128: block_cipher_trait::BlockCipher` is not satisfied
--> src/main.rs:28:18
|
28 | let cipher = Aes128Cbc::new_var(&key, &iv).unwrap();
| ^^^^^^^^^^^^^^^^^^ the trait `block_cipher_trait::BlockCipher` is not implemented for `aes::Aes128`
|
::: /home/ophir/.cargo/registry/src/github.com-1ecc6299db9ec823/block-modes-0.3.3/src/cbc.rs:12:19
|
12 | pub struct Cbc<C: BlockCipher, P: Padding> {
| ----------- required by this bound in `block_modes::Cbc`
warning: unused import: `BlockMode`
--> src/main.rs:5:19
|
5 | use block_modes::{BlockMode, Cbc};
| ^^^^^^^^^
|
= note: `#[warn(unused_imports)]` on by default
error: aborting due to 4 previous errors; 1 warning emitted
Some errors have detailed explanations: E0277, E0599.
For more information about an error, try `rustc --explain E0277`.
error: could not compile `test-aes-cbc`.
To learn more, run the command again with --verbose.
NCCGroup recently did a formal audit of RustCrypto's AES/GCM and ChaCha20Poly1305 for MobileCoin and published the report here:
https://research.nccgroup.com/2020/02/26/public-report-rustcrypto-aes-gcm-and-chacha20poly1305-implementation-review/
One of the issue was regarding the bitslicing implementation of the crate aes-soft
which could be made more efficient. This is regarding performance, it has no effect on the security of the implementation.
Currently, block cipher mode types in the block_modes
crate only provide methods that operate on slices. Those are good enough when you have the entire ciphertext in memory, but in some circumstances you cannot afford that. Right now I'm trying to decrypt a file about 10 GiB in size (and it may grow larger). Loading it into RAM is kind of out of the question (given that I'm developing on a 32-bit machine, it wouldn't even fit into the address space). So an alternative interface would be nice.
One such interface would be to provide types that implement std::io::Read
/ std::io::Write
, encrypt/decrypt it and pass along to another stream implementing the same trait. This would also make the crate easily composable with crates providing the same kind of interface, like flate2
. (In fact, the very next thing I'd want to do would be use flate2
to decompress what I just decrypted; with such wrapper types, it would be two lines of code.)
Hi. Thank you for your work on this crate.
Is it possible to implement std::fmt::Display
, std::error::Error
traits for errors, such as block_modes::BlockModeError
, block_modes::InvalidKeyIvLength
?
This way it will be straightforward for users to do impl From<BlockModeError> for MyLocalError
as described in https://doc.rust-lang.org/stable/rust-by-example/error/multiple_error_types/wrap_error.html.
Thanks.
Currently those methods are not tested. (although encrypt_blocks
was implicitly tested in aesni
through CTR tests)
Currently aes 0.3.0
depends on block-cipher-trait 0.6.0
, but block-modes 0.1.0
depends on block-cipher-trait 0.5.3
. This makes impossible to use aes 0.3.0
with block modes.
If you didn't know, there is a new audit that refers to some parts of this repository. Kudos!
@newpavlov reached out to me and requested I transfer ownership of the cipher crate. I'd be happy to do so. Before transferring, I wanted to confirm the request came from the github user.
@newpavlov can you confirm?
Hey,
I'm using this ecosystem as fallback for Aes256Cbc with IV = 0. I guess this means I'm using aes-soft.
The ciphertext I'm getting has underlying plaintext padded with zero bytes to length 64 (e.g. [49, 50, 51, 52, 0, ... 0]). The plaintext output is shortened as if it were a C string (e.g. [49, 50, 51, 52]). While this would be convenient for me, it's unexpected. Is it intended?
My code is more or less
let mut buffer = request.message.clone();
let zero_iv = [0u8; 16];
let cipher = Aes256Cbc::new_var(&symmetric_key, &zero_iv).unwrap();
let plaintext = cipher.decrypt(&mut buffer).unwrap();
Example data:
key = b'\xd3\xf8\xe5f\x94c\xc9\xba\xa4\x97\xee\xe4\x14\xdb$\xd6\x8f\xf7\xac\xbc\xb9\x8e\x19\xca_\x12\x0e#\xc1\xd3(\xd6'
iv = b'\0' * 16
ciphertext = b'u\x1a\nJ\x02\xccl\xb7|\x1f\x91\x16n\xe6}\xcf\x96\x91__\'N6\xee!\x83\xc3\x14d\xb3\xe3;\x7f&j\xd9\xcb\xa6\x95\x8f\xcdz\x84\xc1W\xa8Y\x03\xe4\x8d{\xa3\xc6\x85z\x81\xfa>TPWD\x1d\xe3'
Is there a reason for Blowfish using big-endian transformation for the integer part or would it be possible to implement a maybe? generic version of the Blowfish struct that would allow you to uses LittleEndian or BigEndian at the users will? Cause for my project I require it reading them in LittleEndian for the en/decryption to be valid.
I believe you're already working on this @newpavlov, but I'd like to track its progress and have some modes to contribute.
I've implemented:
My implementations are somewhat specialized to AES. With const-dependent types I think they could be truly generic.
If RustCrypto were to provide an upstream CTR implementation (perhaps more optimized than mine) that'd be great too.
The recently published lazy FPU switching vulnerability (OpenBSD patch, Intel advisory) might make it possible to leak the registers with the key used for AES-NI to other processes on the same machine.
Any plans for XTS?
See https://docs.rs/crate/aesni/0.3.1/builds/90564. This causes docs.rs to not display the documentation.
Currently only AES crates have been updated.
Probably RustCrypto/traits#25 should be finished first.
Disclaimer: I know this is the wrong repo, but I didn't find a good one to post this on the RustCrypto org.
I have an RSA implementation in pure rust under https://github.com/dignifiedquire/rust-rsa which I would like to publish to crates.io. But when doing so I found out that the rsa
crate name is reserved with an empty crate by RustCrypto. I would be happy to move it into this org, and continue my work on it here, but it would be great if I could use that crate name. Thank you.
cc @newpavlov
like title
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.