Giter Site home page Giter Site logo

block-ciphers's People

Contributors

andelf avatar aticu avatar baloo avatar cheme avatar crodriguezvega avatar dependabot[bot] avatar ignatenkobrain avatar kamilaborowska avatar kanegreen avatar legionmammal978 avatar lovasoa avatar ltfschoen avatar luisbg avatar makavity avatar maximilianthorn avatar namedneon avatar newpavlov avatar peterdettman avatar roblabla avatar sorairolake avatar str4d avatar striezel avatar tarcieri avatar teythoon avatar theradioguy avatar tholop avatar trojan295 avatar veykril avatar wcampbell0x2a avatar zugzwang avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

block-ciphers's Issues

Document BlockModeError

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>)

feature request: add block_size method to BlockCipher

describe & question

BlockCipher.encrypt work in-place, and no allocate. So I need to calculate the buffer size manually.
my question :

  • Is there any way to get block-size easily? not the wordy one.
  • can we add block_size method to BlockCipher?

my code

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

Error building documentation when +sse2,+sse2,+ssse3 activated

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 | | );
   | |__^

Cargo.toml

[package]
name = "test1"
version = "0.1.0"
edition = "2018"

[dependencies]
aes = { version = "0.3.2" }

.cargo/config

# Enables the aes-ni instructions for RustCrypto dependency.
[target.x86_64-unknown-linux-gnu]
rustflags = ["-Ctarget-feature=+aes,+sse2,+ssse3"]

src/main.rs

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

Develop trait for tweakable block ciphers

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.

aes: reduce ParBlocks from 8 to 4 in next breaking release?

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]:

Screen Shot 2020-10-27 at 9 12 24 AM

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?

Using CFB as a stream cipher fails with BlockModeError

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

if buffer.len() % bs != 0 {
has this check:

        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?

Use const generics for magma S-boxes

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.

aesni - Cannot import Aes128 or BlockCipher

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.

`current_pos` wrong value on +aes,+ssse3

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 above

As 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

C# DES and Rust DES does not produce the same result

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);
}

Make `expand` and `encrypt` public.

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.

AES128 CBC mode performance compared with openssl

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.

Is it necessary to recreate the cipher after every use?

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.

Missing block ciphers

List of "would be nice to have" block ciphers:

  • ARIA (#340)
  • Camellia (#293)
  • CAST5 (#36)
  • CAST6 (#384)
  • DES (#2)
  • IDEA (#35)
  • Kalyna
  • Kuznyechik
  • Magma
  • RC2 (#4)
  • RC5 (#346)
  • RC6
  • Rijndael (additional key/block sizes beyond AES)
  • Serpent (#60)
  • Simon
  • Speck (#297)
  • Threefish (#5)
  • Twofish (#7)
  • XTEA

aes: implement fixslicing? (portable and ASM versions)

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

Runtime BlockSize

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.

Too much undefined behavior

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

Miscompilation under target-cpu >= haswell

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

Examples?

Please add some examples. For example, I need to know how to encrypt/decrypt a variable using the blowfish cipher. Thanks!

Optional compact round keys for AES fixslice

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?

Add BlowfishLE tests

#39 has added BlowfishLE variant, it's possible to generate tests, but I would like to use data from a real application to be sure.

@fzzr-
Can you convert your tests to using separate blocks? In other words ideally we need a list of triplets: key, plaintext block, ciphertext block.

CBC mode for large file

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

block-mode is not compatible with aes ( the following trait bounds were not satisfied: aes::Aes128: block_cipher_trait::BlockCipher)

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.

Cargo.toml

[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"

main.rs

(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);
}

Compilation result

   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.

std::io wrappers in the block_modes crate

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

Publish block-modes

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.

BlockMode::decrypt truncates output at first zero byte?

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'

Endianess of Blowfish

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.

Block cipher modes of operation

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.

RSA implementation

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

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.