1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
use crate::errors::*;
use sodiumoxide::crypto::secretbox::{self, Key, Nonce};
use std::iter;

pub fn key_trunc_pad(mut key: &[u8], len: usize, pad: u8) -> Vec<u8> {
    if key.len() > len {
        key = &key[..len];
    }

    let mut key = key.to_vec();
    key.extend(iter::repeat(pad).take(len - key.len()));
    key
}

pub fn sodium_secretbox_open(encrypted: &[u8], key: &[u8]) -> Result<Vec<u8>> {
    if encrypted.len() <= secretbox::NONCEBYTES {
        bail!("Encrypted message is too short");
    }

    let key = Key::from_slice(key).ok_or_else(|| format_err!("Key has wrong length"))?;
    let nonce = Nonce::from_slice(&encrypted[..secretbox::NONCEBYTES])
        .ok_or_else(|| format_err!("Nonce has wrong length"))?;
    let ciphertext = &encrypted[secretbox::NONCEBYTES..];
    let plain = secretbox::open(ciphertext, &nonce, &key)
        .map_err(|_| format_err!("Failed to decrypt secretbox"))?;
    Ok(plain)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_key_equal() {
        let key = key_trunc_pad(&[1, 2, 3, 4, 5], 5, 0);
        assert_eq!(key, &[1, 2, 3, 4, 5]);
    }

    #[test]
    fn test_key_trunc() {
        let key = key_trunc_pad(&[1, 2, 3, 4, 5, 6, 7, 8, 9], 5, 0);
        assert_eq!(key, &[1, 2, 3, 4, 5]);
    }

    #[test]
    fn test_key_pad() {
        let key = key_trunc_pad(&[1, 2, 3], 5, 0);
        assert_eq!(key, &[1, 2, 3, 0, 0]);
    }
}