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}