Skip to content

Commit

Permalink
fixup! fixup! fixup! fixup! Support cryptography module
Browse files Browse the repository at this point in the history
  • Loading branch information
InfoHunter committed May 30, 2024
1 parent e891ec7 commit 39ed4ab
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 44 deletions.
4 changes: 3 additions & 1 deletion src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ pub enum RvError {
ErrCryptoCipherNotInited,
#[error("Cipher operation not supported.")]
ErrCryptoCipherOPNotSupported,
#[error("Cipher operation not supported.")]
#[error("AEAD Cipher tag is missing.")]
ErrCryptoCipherNoTag,
#[error("AEAD Cipher tag should not be present.")]
ErrCryptoCipherAEADTagPresent,
#[error("Config path is invalid.")]
ErrConfigPathInvalid,
#[error("Config load failed.")]
Expand Down
94 changes: 51 additions & 43 deletions src/modules/crypto/crypto_adaptors/openssl_adaptor.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
//! This is the OpenSSL adaptor.

use crate::errors::RvError;
use crate::modules::crypto::{AEADCipher, AESKeySize, BlockCipher, CipherMode, AES, SM4};
use crate::modules::crypto::{AEADCipher, AESKeySize, BlockCipher, CipherMode, AES};
use openssl::symm::{Cipher, Crypter, Mode, encrypt, encrypt_aead, decrypt, decrypt_aead};
use openssl::rand::rand_priv_bytes;

pub struct AdaptorCTX {
ctx: Crypter,
tag_set: bool,
aad_set: bool,
}

impl AES {
fn new(
pub fn new(
keygen: bool,
size: Option<AESKeySize>,
mode: Option<CipherMode>,
Expand Down Expand Up @@ -127,14 +129,24 @@ impl BlockCipher for AES {
&self.key,
Some(&self.iv)
).unwrap();
let adaptor_ctx = AdaptorCTX { ctx: encrypter };
let adaptor_ctx = AdaptorCTX { ctx: encrypter, tag_set: false, aad_set: false };

self.ctx = Some(adaptor_ctx);
}

// set additional authenticated data before doing real jobs.
if self.ctx.as_mut().unwrap().aad_set == false {
if let Some(aad) = &self.aad {
self.ctx.as_mut().unwrap().ctx.aad_update(aad).unwrap();
self.ctx.as_mut().unwrap().aad_set = true;
}
}

// do real jobs.
// this Crypter::update returns a Result<usize, ErrorStack>, we simply ignore the detailed
// error information by unwrapping it.
// we also can't use the question mark operatior since the error codes are differently
// defined in RustyVault and underlying adaptor, such as rust-openssl.
let count = self.ctx.as_mut().unwrap().ctx.update(&plaintext, &mut ciphertext).unwrap();
Ok(count)
}
Expand All @@ -147,6 +159,18 @@ impl BlockCipher for AES {
}

let count = self.ctx.as_mut().unwrap().ctx.finalize(&mut ciphertext).unwrap();

// set tag for caller to obtain.
if let Some(_) = self.tag {
// tag should not be set before encrypt_final() is called.
return Err(RvError::ErrCryptoCipherAEADTagPresent);
}

// 32-byte long is enough for all types of AEAD cipher tag.
let mut tag: Vec<u8> = vec![0; 32];
self.ctx.as_mut().unwrap().ctx.get_tag(&mut tag).unwrap();
self.tag = Some(tag);

Ok(count)
}

Expand All @@ -162,22 +186,21 @@ impl BlockCipher for AES {
}
(AESKeySize::AES128, CipherMode::GCM) => {
// aes_128_gcm's tag is 16-bytes long.
let tag: &mut [u8] = &mut [0; 16];
let plaintext = decrypt_aead(
Cipher::aes_128_gcm(),
&self.key,
Some(&self.iv),
&self.aad.clone().unwrap(),
&ciphertext,
tag
&self.tag.clone().unwrap()
).unwrap();
self.tag = Some(tag.to_vec());
return Ok(plaintext.to_vec());
}
_ => Err(RvError::ErrCryptoCipherOPNotSupported),
}

}

fn decrypt_update(&mut self, ciphertext: Vec<u8>, mut plaintext: Vec<u8>
) -> Result<usize, RvError> {
let cipher;
Expand All @@ -200,14 +223,35 @@ impl BlockCipher for AES {
&self.key,
Some(&self.iv)
).unwrap();
let adaptor_ctx = AdaptorCTX { ctx: encrypter };
let adaptor_ctx = AdaptorCTX { ctx: encrypter, tag_set: false, aad_set: false };

self.ctx = Some(adaptor_ctx);
}

// set additional authenticated data before doing real jobs.
if self.ctx.as_mut().unwrap().aad_set == false {
if let Some(aad) = &self.aad {
self.ctx.as_mut().unwrap().ctx.aad_update(aad).unwrap();
self.ctx.as_mut().unwrap().aad_set = true;
}
}

// set tag before doing real jobs.
if self.ctx.as_mut().unwrap().tag_set == false {
if let Some(tag) = &self.tag {
self.ctx.as_mut().unwrap().ctx.set_tag(tag).unwrap();
self.ctx.as_mut().unwrap().tag_set = true;
} else {
// if tag is missing, then return an error.
return Err(RvError::ErrCryptoCipherNoTag);
}
}

// do real jobs.
// this Crypter::update returns a Result<usize, ErrorStack>, we simply ignore the detailed
// error information by unwrapping it.
let count = self.ctx.as_mut().unwrap().ctx.update(&ciphertext, &mut plaintext).unwrap();

Ok(count)
}

Expand Down Expand Up @@ -240,40 +284,4 @@ impl AEADCipher for AES {
}
}

impl SM4 {
fn new(
keygen: bool,
mode: Option<CipherMode>,
key: Option<Vec<u8>>,
iv: Option<Vec<u8>>,
) -> Result<Self, RvError> {
let ret = SM4 { mode: mode.unwrap(), key: key.unwrap(), iv: iv.unwrap(), aad: None, ctx: None };

Ok(ret)
}
}

impl BlockCipher for SM4 {
fn encrypt(&mut self, plain: Vec<u8>) -> Result<Vec<u8>, RvError> {
Err(RvError::ErrCryptoCipherOPNotSupported)
}
fn encrypt_update(&mut self, plaintext: Vec<u8>, mut ciphertext: Vec<u8>
) -> Result<usize, RvError> {
Err(RvError::ErrCryptoCipherOPNotSupported)
}
fn encrypt_final(&mut self, mut ciphertext: Vec<u8>
) -> Result<usize, RvError> {
Err(RvError::ErrCryptoCipherOPNotSupported)
}
fn decrypt(&mut self, plain: Vec<u8>) -> Result<Vec<u8>, RvError> {
Err(RvError::ErrCryptoCipherOPNotSupported)
}
fn decrypt_update(&mut self, ciphertext: Vec<u8>, mut plaintext: Vec<u8>
) -> Result<usize, RvError> {
Err(RvError::ErrCryptoCipherOPNotSupported)
}
fn decrypt_final(&mut self, mut plaintext: Vec<u8>
) -> Result<usize, RvError> {
Err(RvError::ErrCryptoCipherOPNotSupported)
}
}
38 changes: 38 additions & 0 deletions src/modules/crypto/crypto_adaptors/tongsuo_adaptor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,41 @@ use openssl::symm::{Cipher, Crypter, Mode};
pub struct AdaptorCTX {
ctx: Crypter,
}

impl SM4 {
fn new(
keygen: bool,
mode: Option<CipherMode>,
key: Option<Vec<u8>>,
iv: Option<Vec<u8>>,
) -> Result<Self, RvError> {
let ret = SM4 { mode: mode.unwrap(), key: key.unwrap(), iv: iv.unwrap(), aad: None, ctx: None };

Ok(ret)
}
}

impl BlockCipher for SM4 {
fn encrypt(&mut self, plain: Vec<u8>) -> Result<Vec<u8>, RvError> {
Err(RvError::ErrCryptoCipherOPNotSupported)
}
fn encrypt_update(&mut self, plaintext: Vec<u8>, mut ciphertext: Vec<u8>
) -> Result<usize, RvError> {
Err(RvError::ErrCryptoCipherOPNotSupported)
}
fn encrypt_final(&mut self, mut ciphertext: Vec<u8>
) -> Result<usize, RvError> {
Err(RvError::ErrCryptoCipherOPNotSupported)
}
fn decrypt(&mut self, plain: Vec<u8>) -> Result<Vec<u8>, RvError> {
Err(RvError::ErrCryptoCipherOPNotSupported)
}
fn decrypt_update(&mut self, ciphertext: Vec<u8>, mut plaintext: Vec<u8>
) -> Result<usize, RvError> {
Err(RvError::ErrCryptoCipherOPNotSupported)
}
fn decrypt_final(&mut self, mut plaintext: Vec<u8>
) -> Result<usize, RvError> {
Err(RvError::ErrCryptoCipherOPNotSupported)
}
}
43 changes: 43 additions & 0 deletions src/modules/crypto/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ pub enum AESKeySize {
// All structs are defined here. Every struct represents a type of cryptography algorithm.

/// The AES block cipher structure.
// we add this lint here because it's not guaranteed all underlying adaptors support this
// algorithm. And it's logical to suppress warnings when building the code.
#[allow(dead_code)]
pub struct AES {
alg: (AESKeySize, CipherMode),
key: Vec<u8>,
Expand All @@ -38,6 +41,7 @@ pub struct AES {
}

/// The SM4 block cipher structure.
#[allow(dead_code)]
pub struct SM4 {
mode: CipherMode,
key: Vec<u8>,
Expand All @@ -51,23 +55,62 @@ pub struct SM4 {
/// real algorithms.
pub trait BlockCipher {
/// One-shot encryption.
///
/// This function performs a "one-shot' style encryption. The data to be encrypted is fed by
/// the `plaintext` parameter, while the ciphertext is returned in another `Vec<u8>`.
fn encrypt(&mut self, plaintext: Vec<u8>) -> Result<Vec<u8>, RvError>;

/// Stream encryption - update phase.
///
/// The ciphertext (encrypted data) is returned via the `ciphertext` parameter. The bytes that
/// has been encrypted is returned in the return value of this function.
///
/// Plaintext is fed by the `plaintext` parameter.
fn encrypt_update(&mut self, plaintext: Vec<u8>, ciphertext: Vec<u8>) -> Result<usize, RvError>;

/// Stream encryption - final phase.
///
/// This function finishes the encryption. Residual ciphertext is returned in the `ciphertext`
/// parameter. `encrypt_update()` function should not be called after this function calling.
fn encrypt_final(&mut self, ciphertext: Vec<u8>) -> Result<usize, RvError>;

/// One-shot decryption.
///
/// This function performs a "one-shot' style decryption. The data to be decrypted is fed by
/// the `ciphertext` parameter, while the plaintext is returned in another `Vec<u8>`.
fn decrypt(&mut self, ciphertext: Vec<u8>) -> Result<Vec<u8>, RvError>;

/// Stream decryption - update phase.
///
/// The plaintext (decrypted data) is returned via the `plaintext` parameter. The bytes that
/// has been decrypted is returned in the return value of this function.
///
/// Ciphertext is fed by the `ciphertext` parameter.
fn decrypt_update(&mut self, ciphertext: Vec<u8>, plaintext: Vec<u8>) -> Result<usize, RvError>;

/// Stream decryption - final phase.
///
/// This function finishes the decryption. Residual plaintext is returned in the `plaintext`
/// parameter. `decrypt_update()` function should not be called after this function calling.
fn decrypt_final(&mut self, plaintext: Vec<u8>) -> Result<usize, RvError>;
}

/// AEADCipher defines a block cipher in AEAD mode, such as GCM or CCM.
/// This trait is an extention of BlockCipher for some additional functions.
pub trait AEADCipher: BlockCipher {
/// Set additional authenticated data (AAD) into AEAD cipher.
///
/// This must be set both at encryption and decryption. This function must be called before the
/// updates functions like `encrypt_update()` and `decrypt_update()`.
fn set_aad(&mut self, aad: Vec<u8>) -> Result<(), RvError>;

/// Get the authentication tag in AEAD ciphers.
///
/// This must be called after `encrypt_final()`. Tag value is returned in a `Vec<u8>`.
fn get_tag(&mut self) -> Result<Vec<u8>, RvError>;

/// Set the authentication tag to authenticate the ciphertext in AEAD decryption procedure.
///
/// This function must be called before the `decrypt_final()` function.
fn set_tag(&mut self, tag: Vec<u8>) -> Result<(), RvError>;
}

0 comments on commit 39ed4ab

Please sign in to comment.