1 use openssl
::{symm
, sha
::sha256
};
6 UnableToDecodeBase64Key
,
11 pub enum EncryptError
{
13 UnsupportedVersion(u8),
18 pub enum DecryptError
{
21 UnsupportedVersion(u8),
23 UnableToDecodeBase64Message
,
25 UnableToDecodeMessageAsUTF8String
,
29 fn decode_key(key
: &str) -> Result
<Vec
<u8>, KeyError
> {
30 match base64
::decode(key
) {
31 Ok(k
) => if k
.len() != 16 { Err(KeyError
::WrongKeyLength
) } else { Ok(k
) },
32 Err(_e
) => Err(KeyError
::UnableToDecodeBase64Key
)
36 /// Return a random key encoded in base64.
37 pub fn generate_key() -> String
{
38 let key
= rand
::thread_rng().gen
::<[u8; 16]>();
42 /// Encrypt the given text with the given key (first version). The key length must be 128 bits encoded in base64.
44 /// * 'version' = 1: "1" + base_64(<IV> + hash(message) + aes(message))
45 /// * 'version' = 2: "2" + base_64(<IV> + aes(hash(message) + message))
46 /// IV: 16 bytes randomized.
48 pub fn encrypt(key
: &str, plain_text
: &str, version
: u8) -> Result
<String
, EncryptError
> {
49 let key_as_bytes
= decode_key(key
).map_err(EncryptError
::KeyError
)?
;
51 let text_as_bytes
= plain_text
.as_bytes();
52 let hash_text
= sha256(&text_as_bytes
);
53 let iv
= rand
::thread_rng().gen
::<[u8; 16]>();
57 symm
::encrypt(symm
::Cipher
::aes_128_cbc(), &key_as_bytes
, Some(&iv
), text_as_bytes
)
58 .map_err(|_e
| EncryptError
::UnableToEncrypt
)?
59 } else if version
== 2 {
60 symm
::encrypt(symm
::Cipher
::aes_128_cbc(), &key_as_bytes
, Some(&iv
), &[&hash_text
, text_as_bytes
].concat())
61 .map_err(|_e
| EncryptError
::UnableToEncrypt
)?
63 return Err(EncryptError
::UnsupportedVersion(version
))
66 let mut result
: Vec
<u8> = Vec
::new();
70 result
.extend(&hash_text
);
73 result
.extend(&cipher_text
);
75 Ok(version
.to_string() + &base64
::encode(&result
))
78 /// Decrypt the given text with the given key. The key length must be 128 bits encoded in base64.
80 /// * version 1: "1" + base_64(<IV> + hash(message) + aes(message))
81 /// * version 2: "2" + base_64(<IV> + aes(hash(message) + message))
82 pub fn decrypt(key
: &str, cipher_text
: &str) -> Result
<String
, DecryptError
> {
83 let key_as_bytes
= decode_key(key
).map_err(DecryptError
::KeyError
)?
;
85 // Can't decrypt a message with the wrong version.
86 let first_char
= &cipher_text
[..1];
87 let version
: u8 = first_char
.parse().map_err(|_e
| DecryptError
::UnableToParseVersion
)?
;
89 if version
!= 1 && version
!= 2 {
90 return Err(DecryptError
::UnsupportedVersion(version
))
93 let cipher_text_bytes
=
94 base64
::decode(&cipher_text
.as_bytes()[1..])
95 .map_err(|_e
| DecryptError
::UnableToDecodeBase64Message
)?
;
97 if cipher_text_bytes
.len() <= 48 { return Err(DecryptError
::MessageToShort
) }
99 let iv
= &cipher_text_bytes
[0..16];
101 let (plain_message_bytes
, hash
) =
103 let encrypted_message
= &cipher_text_bytes
[48..];
105 symm
::decrypt(symm
::Cipher
::aes_128_cbc(), &key_as_bytes
, Some(iv
), encrypted_message
)
106 .map_err(|_e
| DecryptError
::UnableToDecrypt
)?
,
107 cipher_text_bytes
[16..48].to_vec()
110 let encrypted_message
= &cipher_text_bytes
[16..];
112 symm
::decrypt(symm
::Cipher
::aes_128_cbc(), &key_as_bytes
, Some(iv
), encrypted_message
)
113 .map_err(|_e
| DecryptError
::UnableToDecrypt
)?
;
115 plain_text
[32..].to_vec(),
116 plain_text
[0..32].to_vec()
120 if sha256(&plain_message_bytes
) != hash
[..] { return Err(DecryptError
::HashMismatch
) }
123 String
::from_utf8(plain_message_bytes
)
124 .map_err(|_e
| DecryptError
::UnableToDecodeMessageAsUTF8String
)?
;