最近一直在研究在rust里使用AES以及各种加密模式。然而,rust里目前的第三方库比较多,而且使用起来也并不容易上手。因此,本文记录rust里AES加密算法不同模式的基本实现方式。
AES CTR
Cargo.toml
hex-literal = "0.3.4"
aes = "0.8"
ctr = "0.9"
注意:
- ctr 是block-modes 下推荐的库:

本小节的代码也是参考ctr文档中的:
use aes::cipher::{KeyIvInit, StreamCipher, StreamCipherSeek};
use hex_literal::hex;
type Aes128Ctr64LE = ctr::Ctr64LE<aes::Aes128>;
fn main() {
let key = [0x42; 16];
let iv = [0x24; 16];
let plaintext = *b"hello world! this is my plaintext.";
let ciphertext = hex!("3357121ebb5a29468bd861467596ce3da59bdee42dcc0614dea955368d8a5dc0cad4");
// encrypt in-place
let mut buf = plaintext.to_vec();
let mut cipher = Aes128Ctr64LE::new(&key.into(), &iv.into());
cipher.apply_keystream(&mut buf); // 完成加密
assert_eq!(buf[..], ciphertext[..]);
// CTR mode can be used with streaming messages
let mut cipher = Aes128Ctr64LE::new(&key.into(), &iv.into());
for chunk in buf.chunks_mut(3) {
cipher.apply_keystream(chunk);
}
assert_eq!(buf[..], plaintext[..]);
// CTR mode supports seeking. The parameter is zero-based _bytes_ counter (not _blocks_).
cipher.seek(0u32);
// encrypt/decrypt from buffer to buffer
// buffer length must be equal to input length
let mut buf1 = [0u8; 34];
cipher.apply_keystream_b2b(&plaintext, &mut buf1).unwrap();
assert_eq!(buf1[..], ciphertext[..]);
let mut buf2 = [0u8; 34];
cipher.seek(0u32);
cipher.apply_keystream_b2b(&buf1, &mut buf2).unwrap();
assert_eq!(buf2[..], plaintext[..]);
}
AES ECB
在前面的block-modes中一直没有发现ECB模式,直到在其PR里看到相关的讨论:
直接使用aes::Aes128就是默认的ECB mode,还有一个关键问题就是padding的问题。
上面提到直接在encryption/decryption里指定方法,并且让我们参考cbc文档中的代码:
可以看到是在这里指定里padding的方式。
现在我们尝试写一个Aes ECB模式的样例代码,经过测试,需要引入如下crate和feature,才能够顺利使用Aes以及padding:
aes = "0.8"
ctr = "0.9"
cipher = {version = "0.4.3", features=["block-padding"]}
必须要指定
features=["block-padding"], 才能在源码里使用use aes::cipher::block_padding::*;
下面是最基础的一个版本:
use aes::{Aes128, Aes128Enc, Aes128Dec};
use aes::cipher::{
BlockCipher, BlockEncrypt, BlockDecrypt, KeyInit,
generic_array::GenericArray,
};
use aes::cipher::{BlockEncryptMut, BlockDecryptMut};
use aes::cipher::block_padding::Pkcs7;
fn main() {
// 注意key的类型
let key = GenericArray::from([0u8; 16]);
let plaintext = *b"hello world! this is my plaintext.";
let pt_len = plaintext.len();
let enc_cipher = Aes128Enc::new(&key);
let dec_cipher = Aes128Dec::new(&key);
// in-place
// 注意这里的长度是 ((pt_len + 15)/16) * 16
// 不然会panic
let mut ct_buf = [0u8; 48];
enc_cipher.encrypt_padded_b2b_mut::<Pkcs7>(&plaintext, &mut ct_buf).unwrap();
let mut dec_buf = [0u8; 48];
dec_cipher.decrypt_padded_b2b_mut::<Pkcs7>(&ct_buf, &mut dec_buf).unwrap();
assert_eq!(plaintext, dec_buf[..pt_len]);
}
版权声明:本文为fat_cai_niao原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。