use std::convert::TryFrom;
use super::*;
#[derive(Copy, Clone)]
pub enum CryptoAlgorithm {
XC20P,
A256GCM,
A256CBC,
}
impl Cypher for CryptoAlgorithm {
fn encryptor(&self) -> SymmetricCypherMethod {
match self {
CryptoAlgorithm::XC20P => Box::new(
|nonce: &[u8], key: &[u8], message: &[u8], aad: &[u8]| -> Result<Vec<u8>, Error> {
check_nonce(nonce, 24)?;
use chacha20poly1305::{
aead::{Aead, KeyInit, Payload},
XChaCha20Poly1305, XNonce,
};
let nonce = XNonce::from_slice(nonce);
let aead = XChaCha20Poly1305::new(key.into());
aead.encrypt(nonce, Payload { msg: message, aad })
.map_err(|e| Error::Generic(e.to_string()))
},
),
CryptoAlgorithm::A256GCM => Box::new(
|nonce: &[u8], key: &[u8], message: &[u8], aad: &[u8]| -> Result<Vec<u8>, Error> {
check_nonce(nonce, 12)?;
use aes_gcm::{
aead::{generic_array::GenericArray, Aead, KeyInit, Payload},
Aes256Gcm,
};
let nonce = GenericArray::from_slice(&nonce[..12]);
let aead = Aes256Gcm::new(GenericArray::from_slice(key));
aead.encrypt(nonce, Payload { msg: message, aad })
.map_err(|e| Error::Generic(e.to_string()))
},
),
CryptoAlgorithm::A256CBC => Box::new(
|nonce: &[u8], key: &[u8], message: &[u8], _aad: &[u8]| -> Result<Vec<u8>, Error> {
if key.len() != 32 {
return Err(Error::InvalidKeySize(
"expected 256 bit (32 byte) key".into(),
));
}
if nonce.len() != 16 {
return Err(Error::InvalidKeySize("expected 16 bytes nonce".into()));
}
use arrayref::array_ref;
use libaes::Cipher;
let aead = Cipher::new_256(array_ref!(key, 0, 32));
Ok(aead.cbc_encrypt(nonce, message))
},
),
}
}
fn decrypter(&self) -> SymmetricCypherMethod {
match self {
CryptoAlgorithm::XC20P => Box::new(
|nonce: &[u8], key: &[u8], message: &[u8], aad: &[u8]| -> Result<Vec<u8>, Error> {
check_nonce(nonce, 24)?;
use chacha20poly1305::{
aead::{Aead, KeyInit, Payload},
XChaCha20Poly1305, XNonce,
};
let aead = XChaCha20Poly1305::new(key.into());
let nonce = XNonce::from_slice(nonce);
aead.decrypt(nonce, Payload { msg: message, aad })
.map_err(|e| Error::Generic(e.to_string()))
},
),
CryptoAlgorithm::A256GCM => Box::new(
|nonce: &[u8], key: &[u8], message: &[u8], aad: &[u8]| -> Result<Vec<u8>, Error> {
check_nonce(nonce, 12)?;
use aes_gcm::{
aead::{generic_array::GenericArray, Aead, KeyInit, Payload},
Aes256Gcm,
};
let nonce = GenericArray::from_slice(&nonce[..12]);
let aead = Aes256Gcm::new(GenericArray::from_slice(key));
aead.decrypt(nonce, Payload { msg: message, aad })
.map_err(|e| Error::Generic(e.to_string()))
},
),
CryptoAlgorithm::A256CBC => {
todo!()
}
}
}
fn asymmetric_encryptor(&self) -> AsymmetricCypherMethod {
match self {
CryptoAlgorithm::XC20P => {
todo!()
}
CryptoAlgorithm::A256GCM => {
todo!()
}
CryptoAlgorithm::A256CBC => {
todo!()
}
}
}
}
impl TryFrom<&String> for CryptoAlgorithm {
type Error = Error;
fn try_from(incoming: &String) -> Result<Self, Error> {
match &incoming[..] {
"ECDH-1PU+A256KW" => Ok(Self::A256GCM),
"ECDH-1PU+XC20PKW" => Ok(Self::XC20P),
_ => Err(Error::JweParseError),
}
}
}
fn check_nonce(nonce: &[u8], expected_len: usize) -> Result<(), Error> {
if nonce.len() < expected_len {
return Err(Error::PlugCryptoFailure);
}
Ok(())
}
#[cfg(test)]
mod batteries_tests {
use super::*;
use crate::{Jwe, Message};
#[test]
fn xc20p_test() -> Result<(), Error> {
let payload = r#"{"test":"message's body - can be anything..."}"#;
let m = Message::new()
.as_jwe(&CryptoAlgorithm::XC20P, None) .body(payload)?;
let original_header = m.jwm_header.clone();
let key = b"super duper key 32 bytes long!!!";
let jwe_string_result = m.encrypt(CryptoAlgorithm::XC20P.encryptor(), key);
assert!(&jwe_string_result.is_ok());
let jwe_string = jwe_string_result?;
let jwe: Jwe = serde_json::from_str(&jwe_string)?;
assert!(&jwe.tag.is_some());
let s = Message::decrypt(
jwe_string.as_bytes(),
CryptoAlgorithm::XC20P.decrypter(),
key,
)?;
let received_payload = &s.get_body()?;
assert_eq!(s.jwm_header, original_header);
assert_eq!(payload, received_payload);
Ok(())
}
#[test]
fn a256gcm_test() -> Result<(), Error> {
let payload = r#"{"example":"message's body - can be anything..."}"#;
let m = Message::new()
.as_jwe(&CryptoAlgorithm::A256GCM, None) .body(payload)?;
let original_header = m.jwm_header.clone();
let key = b"super duper key 32 bytes long!!!";
let jwe = m.encrypt(CryptoAlgorithm::A256GCM.encryptor(), key);
assert!(&jwe.is_ok());
let s = Message::decrypt(
jwe.expect("failed to get JWE").as_bytes(),
CryptoAlgorithm::A256GCM.decrypter(),
key,
)?;
let received_payload = &s.get_body()?;
assert_eq!(s.jwm_header, original_header);
assert_eq!(payload, received_payload);
Ok(())
}
}