1use std::convert::TryFrom;
2
3use super::*;
4
5#[derive(Copy, Clone)]
15pub enum CryptoAlgorithm {
16 XC20P,
17 A256GCM,
18 A256CBC,
19}
20
21impl Cypher for CryptoAlgorithm {
22 fn encryptor(&self) -> SymmetricCypherMethod {
25 match self {
26 CryptoAlgorithm::XC20P => Box::new(
27 |nonce: &[u8], key: &[u8], message: &[u8], aad: &[u8]| -> Result<Vec<u8>, Error> {
28 check_nonce(nonce, 24)?;
29 use chacha20poly1305::{
30 aead::{Aead, KeyInit, Payload},
31 XChaCha20Poly1305, XNonce,
32 };
33 let nonce = XNonce::from_slice(nonce);
34 let aead = XChaCha20Poly1305::new(key.into());
35 aead.encrypt(nonce, Payload { msg: message, aad })
36 .map_err(|e| Error::Generic(e.to_string()))
37 },
38 ),
39 CryptoAlgorithm::A256GCM => Box::new(
40 |nonce: &[u8], key: &[u8], message: &[u8], aad: &[u8]| -> Result<Vec<u8>, Error> {
41 check_nonce(nonce, 12)?;
42 use aes_gcm::{
43 aead::{generic_array::GenericArray, Aead, KeyInit, Payload},
44 Aes256Gcm,
45 };
46 let nonce = GenericArray::from_slice(&nonce[..12]);
47 let aead = Aes256Gcm::new(GenericArray::from_slice(key));
48 aead.encrypt(nonce, Payload { msg: message, aad })
49 .map_err(|e| Error::Generic(e.to_string()))
50 },
51 ),
52 CryptoAlgorithm::A256CBC => Box::new(
53 |nonce: &[u8], key: &[u8], message: &[u8], _aad: &[u8]| -> Result<Vec<u8>, Error> {
54 if key.len() != 32 {
55 return Err(Error::InvalidKeySize(
56 "expected 256 bit (32 byte) key".into(),
57 ));
58 }
59 if nonce.len() != 16 {
60 return Err(Error::InvalidKeySize("expected 16 bytes nonce".into()));
61 }
62 use arrayref::array_ref;
63 use libaes::Cipher;
64 let aead = Cipher::new_256(array_ref!(key, 0, 32));
65 Ok(aead.cbc_encrypt(nonce, message))
66 },
67 ),
68 }
69 }
70
71 fn decrypter(&self) -> SymmetricCypherMethod {
74 match self {
75 CryptoAlgorithm::XC20P => Box::new(
76 |nonce: &[u8], key: &[u8], message: &[u8], aad: &[u8]| -> Result<Vec<u8>, Error> {
77 check_nonce(nonce, 24)?;
78 use chacha20poly1305::{
79 aead::{Aead, KeyInit, Payload},
80 XChaCha20Poly1305, XNonce,
81 };
82 let aead = XChaCha20Poly1305::new(key.into());
83 let nonce = XNonce::from_slice(nonce);
84 aead.decrypt(nonce, Payload { msg: message, aad })
85 .map_err(|e| Error::Generic(e.to_string()))
86 },
87 ),
88 CryptoAlgorithm::A256GCM => Box::new(
89 |nonce: &[u8], key: &[u8], message: &[u8], aad: &[u8]| -> Result<Vec<u8>, Error> {
90 check_nonce(nonce, 12)?;
91 use aes_gcm::{
92 aead::{generic_array::GenericArray, Aead, KeyInit, Payload},
93 Aes256Gcm,
94 };
95 let nonce = GenericArray::from_slice(&nonce[..12]);
96 let aead = Aes256Gcm::new(GenericArray::from_slice(key));
97 aead.decrypt(nonce, Payload { msg: message, aad })
98 .map_err(|e| Error::Generic(e.to_string()))
99 },
100 ),
101 CryptoAlgorithm::A256CBC => {
102 todo!()
103 }
104 }
105 }
106
107 fn asymmetric_encryptor(&self) -> AsymmetricCypherMethod {
109 match self {
110 CryptoAlgorithm::XC20P => {
111 todo!()
112 }
113 CryptoAlgorithm::A256GCM => {
114 todo!()
115 }
116 CryptoAlgorithm::A256CBC => {
117 todo!()
118 }
119 }
120 }
121}
122
123impl TryFrom<&String> for CryptoAlgorithm {
124 type Error = Error;
125 fn try_from(incoming: &String) -> Result<Self, Error> {
126 match &incoming[..] {
127 "ECDH-1PU+A256KW" => Ok(Self::A256GCM),
128 "ECDH-1PU+XC20PKW" => Ok(Self::XC20P),
129 _ => Err(Error::JweParseError),
130 }
131 }
132}
133
134fn check_nonce(nonce: &[u8], expected_len: usize) -> Result<(), Error> {
136 if nonce.len() < expected_len {
137 return Err(Error::PlugCryptoFailure);
138 }
139 Ok(())
140}
141
142#[cfg(test)]
143mod batteries_tests {
144 use super::*;
145 use crate::{Jwe, Message};
146
147 #[test]
148 fn xc20p_test() -> Result<(), Error> {
149 let payload = r#"{"test":"message's body - can be anything..."}"#;
151 let m = Message::new()
152 .as_jwe(&CryptoAlgorithm::XC20P, None) .body(payload)?;
154 let original_header = m.jwm_header.clone();
155 let key = b"super duper key 32 bytes long!!!";
156 let jwe_string_result = m.encrypt(CryptoAlgorithm::XC20P.encryptor(), key);
158 assert!(&jwe_string_result.is_ok());
159 let jwe_string = jwe_string_result?;
160 let jwe: Jwe = serde_json::from_str(&jwe_string)?;
161 assert!(&jwe.tag.is_some());
162 let s = Message::decrypt(
163 jwe_string.as_bytes(),
164 CryptoAlgorithm::XC20P.decrypter(),
165 key,
166 )?;
167 let received_payload = &s.get_body()?;
168 assert_eq!(s.jwm_header, original_header);
170 assert_eq!(payload, received_payload);
171 Ok(())
172 }
173
174 #[test]
175 fn a256gcm_test() -> Result<(), Error> {
176 let payload = r#"{"example":"message's body - can be anything..."}"#;
178 let m = Message::new()
179 .as_jwe(&CryptoAlgorithm::A256GCM, None) .body(payload)?;
181 let original_header = m.jwm_header.clone();
182 let key = b"super duper key 32 bytes long!!!";
183 let jwe = m.encrypt(CryptoAlgorithm::A256GCM.encryptor(), key);
185 assert!(&jwe.is_ok());
186 let s = Message::decrypt(
187 jwe.expect("failed to get JWE").as_bytes(),
188 CryptoAlgorithm::A256GCM.decrypter(),
189 key,
190 )?;
191 let received_payload = &s.get_body()?;
192 assert_eq!(s.jwm_header, original_header);
194 assert_eq!(payload, received_payload);
195 Ok(())
196 }
197}