refactor: modularize middleware & crypto
This commit is contained in:
108
src/crypto.rs
108
src/crypto.rs
@@ -7,71 +7,59 @@ use cbc::{
|
||||
cipher::{BlockDecryptMut, BlockEncryptMut, KeyIvInit, block_padding::Pkcs7},
|
||||
};
|
||||
|
||||
type Aes128CbcEnc = Encryptor<Aes128>;
|
||||
type Aes128CbcDec = Decryptor<Aes128>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CryptoError {
|
||||
Base64(base64::DecodeError),
|
||||
Aes(cbc::cipher::InvalidLength),
|
||||
Unpad(cbc::cipher::block_padding::UnpadError),
|
||||
Pad(aes::cipher::inout::PadError),
|
||||
pub struct Cryptor {
|
||||
encryptor: Encryptor<Aes128>,
|
||||
decryptor: Decryptor<Aes128>,
|
||||
}
|
||||
|
||||
impl fmt::Display for CryptoError {
|
||||
impl Cryptor {
|
||||
pub fn new(key: &[u8], iv: &[u8]) -> Result<Self, cbc::cipher::InvalidLength> {
|
||||
Ok(Self {
|
||||
encryptor: Encryptor::new_from_slices(key, iv)?,
|
||||
decryptor: Decryptor::new_from_slices(key, iv)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn decrypt(&self, ciphertext: String) -> Result<String, DecryptError> {
|
||||
let mut ciphertext = STANDARD.decode(ciphertext).map_err(DecryptError::Base64)?;
|
||||
|
||||
let plaintext = self
|
||||
.decryptor
|
||||
.clone()
|
||||
.decrypt_padded_mut::<Pkcs7>(ciphertext.as_mut_slice())
|
||||
.map_err(DecryptError::Unpad)?;
|
||||
|
||||
Ok(String::from_utf8_lossy(plaintext).to_string())
|
||||
}
|
||||
|
||||
pub fn encrypt(&self, plaintext: String) -> String {
|
||||
// Allocate buffer with extra space for padding (AES block size is 16 bytes)
|
||||
let plaintext_bytes = plaintext.as_bytes();
|
||||
let mut buffer = vec![0u8; 16 * (plaintext_bytes.len() / 16 + 1)];
|
||||
buffer[..plaintext_bytes.len()].copy_from_slice(plaintext_bytes);
|
||||
let ciphertext = self
|
||||
.encryptor
|
||||
.clone()
|
||||
.encrypt_padded_mut::<Pkcs7>(&mut buffer, plaintext_bytes.len())
|
||||
.expect("enough space for encrypting is allocated");
|
||||
|
||||
STANDARD.encode(ciphertext)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum DecryptError {
|
||||
Base64(base64::DecodeError),
|
||||
Unpad(cbc::cipher::block_padding::UnpadError),
|
||||
}
|
||||
|
||||
impl fmt::Display for DecryptError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
CryptoError::Base64(e) => write!(f, "Base64 decode failed: {}", e),
|
||||
CryptoError::Aes(e) => write!(f, "AES decryption failed: {}", e),
|
||||
CryptoError::Unpad(e) => write!(f, "PKCS7 unpadding failed: {}", e),
|
||||
CryptoError::Pad(e) => write!(f, "PKCS7 padding failed: {}", e),
|
||||
DecryptError::Base64(e) => write!(f, "Base64 decode failed: {}", e),
|
||||
DecryptError::Unpad(e) => write!(f, "PKCS7 unpadding failed: {}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for CryptoError {}
|
||||
|
||||
pub fn decrypt(ciphertext_b64: &str, key: &str, iv: &str) -> Result<String, CryptoError> {
|
||||
// 1. Base64 decode the ciphertext
|
||||
let ciphertext = STANDARD
|
||||
.decode(ciphertext_b64)
|
||||
.map_err(CryptoError::Base64)?;
|
||||
|
||||
// 2. Initialize AES-128 in CBC mode
|
||||
let key_bytes = key.as_bytes();
|
||||
let iv_bytes = iv.as_bytes();
|
||||
let decryptor = Aes128CbcDec::new_from_slices(key_bytes, iv_bytes).map_err(CryptoError::Aes)?;
|
||||
|
||||
// 3. Decrypt the ciphertext, handling padding
|
||||
let decrypted_len = ciphertext.len();
|
||||
let mut plaintext = vec![0u8; decrypted_len];
|
||||
let copy_len = ciphertext.len();
|
||||
plaintext[..copy_len].copy_from_slice(&ciphertext);
|
||||
|
||||
let plaintext_slice = decryptor
|
||||
.decrypt_padded_mut::<Pkcs7>(&mut plaintext[..decrypted_len])
|
||||
.map_err(CryptoError::Unpad)?;
|
||||
|
||||
// 4. Convert plaintext to a UTF-8 string
|
||||
Ok(String::from_utf8_lossy(plaintext_slice).to_string())
|
||||
}
|
||||
|
||||
pub fn encrypt(plaintext: &str, key: &str, iv: &str) -> Result<String, CryptoError> {
|
||||
// 1. Initialize AES-128 in CBC mode
|
||||
let key_bytes = key.as_bytes();
|
||||
let iv_bytes = iv.as_bytes();
|
||||
let encryptor = Aes128CbcEnc::new_from_slices(key_bytes, iv_bytes).map_err(CryptoError::Aes)?;
|
||||
|
||||
// 2. Encrypt the plaintext with PKCS7 padding
|
||||
// Allocate buffer with extra space for padding (AES block size is 16 bytes)
|
||||
let plaintext_bytes = plaintext.as_bytes();
|
||||
let mut buffer = vec![0u8; plaintext_bytes.len() + 16];
|
||||
buffer[..plaintext_bytes.len()].copy_from_slice(plaintext_bytes);
|
||||
|
||||
let ciphertext = encryptor
|
||||
.encrypt_padded_mut::<Pkcs7>(&mut buffer, plaintext_bytes.len())
|
||||
.map_err(CryptoError::Pad)?;
|
||||
|
||||
// 3. Base64 encode the ciphertext
|
||||
Ok(STANDARD.encode(ciphertext))
|
||||
}
|
||||
impl std::error::Error for DecryptError {}
|
||||
|
||||
Reference in New Issue
Block a user