pretty_good/
s2k.rs

1use failure::Error;
2use nom::be_u8;
3use nom::{ErrorKind, IResult};
4use nom::Err as NomErr;
5
6use types::*;
7
8pub(crate) fn s2k_iv(inp: &[u8]) -> IResult<&[u8], [u8; 8]> {
9    let mut out = [0u8; 8];
10
11    let (remaining, slice) = match take!(inp, 8) {
12        IResult::Done(remaining, slice) => (remaining, slice),
13        IResult::Error(e) => return IResult::Error(e),
14        IResult::Incomplete(i) => return IResult::Incomplete(i),
15    };
16
17    out.copy_from_slice(&slice[..8]);
18
19    IResult::Done(remaining, out)
20}
21
22fn s2k_decode_count(c: u8) -> u32 {
23    let c = c as u32;
24    (16 + (c & 15)) << ((c >> 4) + 6)
25}
26
27named!(simple_s2k<StringToKey>,
28    do_parse!(
29        tag!(&[0u8]) >>
30        hash_algo: map!(be_u8, HashAlgorithm::from) >>
31        (StringToKey::Simple(hash_algo))
32    )
33);
34
35named!(salted_s2k<StringToKey>,
36    do_parse!(
37        tag!(&[1u8]) >>
38        hash_algo: map!(be_u8, HashAlgorithm::from) >>
39        iv: s2k_iv >>
40        (StringToKey::Salted(hash_algo, iv))
41    )
42);
43
44named!(iterated_salted_s2k<StringToKey>,
45    do_parse!(
46        tag!(&[3u8]) >>
47        hash_algo: map!(be_u8, HashAlgorithm::from) >>
48        iv: s2k_iv >>
49        count: map!(be_u8, s2k_decode_count) >>
50        (StringToKey::IteratedSalted(hash_algo, iv, count))
51    )
52);
53
54named!(pub s2k<StringToKey>, alt!(simple_s2k | salted_s2k | iterated_salted_s2k));
55
56#[derive(Clone, Copy, Debug)]
57pub enum StringToKey {
58    Simple(HashAlgorithm),
59    Salted(HashAlgorithm, [u8; 8]),
60    IteratedSalted(HashAlgorithm, [u8; 8], u32),
61}
62
63impl StringToKey {
64    pub fn from_bytes(bytes: &[u8]) -> Result<StringToKey, Error> {
65        let (_, string_to_key) = match s2k(bytes) {
66            IResult::Done(remaining, string_to_key) => (remaining, string_to_key),
67            IResult::Error(NomErr::Code(ErrorKind::Custom(e))) => {
68                let e = NomError::from(e);
69
70                bail!(S2kError::InvalidFormat {
71                    reason: format!("{:?}", e),
72                })
73            }
74            IResult::Error(e) => bail!(S2kError::InvalidFormat {
75                reason: format!("{}", e),
76            }),
77            IResult::Incomplete(i) => bail!(S2kError::InvalidFormat {
78                reason: format!("{:?}", i),
79            }),
80        };
81
82        Ok(string_to_key)
83    }
84}
85
86#[derive(Debug, Fail)]
87pub enum S2kError {
88    #[fail(display = "Invalid string to key specifier: {}", reason)]
89    InvalidFormat { reason: String },
90}