hashes, ecaps2, jingle_ft: Make the algorithm a proper enum.

This commit is contained in:
Emmanuel Gil Peyrot 2017-05-18 23:09:29 +01:00
parent 4ec92b16ac
commit b22acff15e
3 changed files with 116 additions and 61 deletions

View file

@ -8,7 +8,7 @@ use std::convert::TryFrom;
use disco::{Feature, Identity, Disco}; use disco::{Feature, Identity, Disco};
use data_forms::DataForm; use data_forms::DataForm;
use hashes::Hash; use hashes::{Hash, Algo};
use minidom::Element; use minidom::Element;
use error::Error; use error::Error;
@ -118,49 +118,52 @@ pub fn compute_disco(disco: &Disco) -> Vec<u8> {
final_string final_string
} }
// TODO: make algo into an enum. pub fn hash_ecaps2(data: &[u8], algo: Algo) -> Result<Hash, String> {
pub fn hash_ecaps2(data: &[u8], algo: &str) -> String { Ok(Hash {
match algo { algo: algo.clone(),
"sha-256" => { hash: match algo {
Algo::Sha_256 => {
let mut hasher = Sha256::default(); let mut hasher = Sha256::default();
hasher.input(data); hasher.input(data);
let hash = hasher.result(); let hash = hasher.result();
base64::encode(&hash.as_slice()) base64::encode(&hash.as_slice())
}, },
"sha-512" => { Algo::Sha_512 => {
let mut hasher = Sha512::default(); let mut hasher = Sha512::default();
hasher.input(data); hasher.input(data);
let hash = hasher.result(); let hash = hasher.result();
base64::encode(&hash.as_slice()) base64::encode(&hash.as_slice())
}, },
"sha3-256" => { Algo::Sha3_256 => {
let mut hasher = Sha3_256::default(); let mut hasher = Sha3_256::default();
hasher.input(data); hasher.input(data);
let hash = hasher.result(); let hash = hasher.result();
base64::encode(&hash.as_slice()) base64::encode(&hash.as_slice())
}, },
"sha3-512" => { Algo::Sha3_512 => {
let mut hasher = Sha3_512::default(); let mut hasher = Sha3_512::default();
hasher.input(data); hasher.input(data);
let hash = hasher.result(); let hash = hasher.result();
base64::encode(&hash.as_slice()) base64::encode(&hash.as_slice())
}, },
"blake2b-256" => { Algo::Blake2b_256 => {
let mut hasher = Blake2b::default(); let mut hasher = Blake2b::default();
hasher.input(data); hasher.input(data);
let mut buf: [u8; 32] = [0; 32]; let mut buf: [u8; 32] = [0; 32];
let hash = hasher.variable_result(&mut buf).unwrap(); let hash = hasher.variable_result(&mut buf).unwrap();
base64::encode(hash) base64::encode(hash)
}, },
"blake2b-512" => { Algo::Blake2b_512 => {
let mut hasher = Blake2b::default(); let mut hasher = Blake2b::default();
hasher.input(data); hasher.input(data);
let mut buf: [u8; 64] = [0; 64]; let mut buf: [u8; 64] = [0; 64];
let hash = hasher.variable_result(&mut buf).unwrap(); let hash = hasher.variable_result(&mut buf).unwrap();
base64::encode(hash) base64::encode(hash)
}, },
_ => panic!(), Algo::Sha_1 => return Err(String::from("Disabled algorithm sha-1: unsafe.")),
} Algo::Unknown(algo) => return Err(format!("Unknown algorithm: {}.", algo)),
},
})
} }
#[cfg(test)] #[cfg(test)]
@ -174,9 +177,9 @@ mod tests {
let elem: Element = "<c xmlns='urn:xmpp:caps'><hash xmlns='urn:xmpp:hashes:2' algo='sha-256'>K1Njy3HZBThlo4moOD5gBGhn0U0oK7/CbfLlIUDi6o4=</hash><hash xmlns='urn:xmpp:hashes:2' algo='sha3-256'>+sDTQqBmX6iG/X3zjt06fjZMBBqL/723knFIyRf0sg8=</hash></c>".parse().unwrap(); let elem: Element = "<c xmlns='urn:xmpp:caps'><hash xmlns='urn:xmpp:hashes:2' algo='sha-256'>K1Njy3HZBThlo4moOD5gBGhn0U0oK7/CbfLlIUDi6o4=</hash><hash xmlns='urn:xmpp:hashes:2' algo='sha3-256'>+sDTQqBmX6iG/X3zjt06fjZMBBqL/723knFIyRf0sg8=</hash></c>".parse().unwrap();
let ecaps2 = ECaps2::try_from(&elem).unwrap(); let ecaps2 = ECaps2::try_from(&elem).unwrap();
assert_eq!(ecaps2.hashes.len(), 2); assert_eq!(ecaps2.hashes.len(), 2);
assert_eq!(ecaps2.hashes[0].algo, "sha-256"); assert_eq!(ecaps2.hashes[0].algo, Algo::Sha_256);
assert_eq!(ecaps2.hashes[0].hash, "K1Njy3HZBThlo4moOD5gBGhn0U0oK7/CbfLlIUDi6o4="); assert_eq!(ecaps2.hashes[0].hash, "K1Njy3HZBThlo4moOD5gBGhn0U0oK7/CbfLlIUDi6o4=");
assert_eq!(ecaps2.hashes[1].algo, "sha3-256"); assert_eq!(ecaps2.hashes[1].algo, Algo::Sha3_256);
assert_eq!(ecaps2.hashes[1].hash, "+sDTQqBmX6iG/X3zjt06fjZMBBqL/723knFIyRf0sg8="); assert_eq!(ecaps2.hashes[1].hash, "+sDTQqBmX6iG/X3zjt06fjZMBBqL/723knFIyRf0sg8=");
} }
@ -262,10 +265,10 @@ mod tests {
assert_eq!(ecaps2.len(), 0x1d9); assert_eq!(ecaps2.len(), 0x1d9);
assert_eq!(ecaps2, expected); assert_eq!(ecaps2, expected);
let sha_256 = ecaps2::hash_ecaps2(&ecaps2, "sha-256"); let sha_256 = ecaps2::hash_ecaps2(&ecaps2, Algo::Sha_256).unwrap();
assert_eq!(sha_256, "kzBZbkqJ3ADrj7v08reD1qcWUwNGHaidNUgD7nHpiw8="); assert_eq!(sha_256.hash, "kzBZbkqJ3ADrj7v08reD1qcWUwNGHaidNUgD7nHpiw8=");
let sha3_256 = ecaps2::hash_ecaps2(&ecaps2, "sha3-256"); let sha3_256 = ecaps2::hash_ecaps2(&ecaps2, Algo::Sha3_256).unwrap();
assert_eq!(sha3_256, "79mdYAfU9rEdTOcWDO7UEAt6E56SUzk/g6TnqUeuD9Q="); assert_eq!(sha3_256.hash, "79mdYAfU9rEdTOcWDO7UEAt6E56SUzk/g6TnqUeuD9Q=");
} }
#[test] #[test]
@ -434,15 +437,15 @@ mod tests {
assert_eq!(ecaps2.len(), 0x543); assert_eq!(ecaps2.len(), 0x543);
assert_eq!(ecaps2, expected); assert_eq!(ecaps2, expected);
let sha_256 = ecaps2::hash_ecaps2(&ecaps2, "sha-256"); let sha_256 = ecaps2::hash_ecaps2(&ecaps2, Algo::Sha_256).unwrap();
assert_eq!(sha_256, "u79ZroNJbdSWhdSp311mddz44oHHPsEBntQ5b1jqBSY="); assert_eq!(sha_256.hash, "u79ZroNJbdSWhdSp311mddz44oHHPsEBntQ5b1jqBSY=");
let sha3_256 = ecaps2::hash_ecaps2(&ecaps2, "sha3-256"); let sha3_256 = ecaps2::hash_ecaps2(&ecaps2, Algo::Sha3_256).unwrap();
assert_eq!(sha3_256, "XpUJzLAc93258sMECZ3FJpebkzuyNXDzRNwQog8eycg="); assert_eq!(sha3_256.hash, "XpUJzLAc93258sMECZ3FJpebkzuyNXDzRNwQog8eycg=");
} }
#[test] #[test]
fn test_blake2b_512() { fn test_blake2b_512() {
let hash = ecaps2::hash_ecaps2("abc".as_bytes(), "blake2b-512"); let hash = ecaps2::hash_ecaps2("abc".as_bytes(), Algo::Blake2b_512).unwrap();
let known_hash: Vec<u8> = vec!( let known_hash: Vec<u8> = vec!(
0xBA, 0x80, 0xA5, 0x3F, 0x98, 0x1C, 0x4D, 0x0D, 0x6A, 0x27, 0x97, 0xB6, 0x9F, 0x12, 0xF6, 0xE9, 0xBA, 0x80, 0xA5, 0x3F, 0x98, 0x1C, 0x4D, 0x0D, 0x6A, 0x27, 0x97, 0xB6, 0x9F, 0x12, 0xF6, 0xE9,
0x4C, 0x21, 0x2F, 0x14, 0x68, 0x5A, 0xC4, 0xB7, 0x4B, 0x12, 0xBB, 0x6F, 0xDB, 0xFF, 0xA2, 0xD1, 0x4C, 0x21, 0x2F, 0x14, 0x68, 0x5A, 0xC4, 0xB7, 0x4B, 0x12, 0xBB, 0x6F, 0xDB, 0xFF, 0xA2, 0xD1,
@ -450,6 +453,6 @@ mod tests {
0x18, 0xD3, 0x8A, 0xA8, 0xDB, 0xF1, 0x92, 0x5A, 0xB9, 0x23, 0x86, 0xED, 0xD4, 0x00, 0x99, 0x23, 0x18, 0xD3, 0x8A, 0xA8, 0xDB, 0xF1, 0x92, 0x5A, 0xB9, 0x23, 0x86, 0xED, 0xD4, 0x00, 0x99, 0x23,
); );
let known_hash = base64::encode(&known_hash); let known_hash = base64::encode(&known_hash);
assert_eq!(hash, known_hash); assert_eq!(hash.hash, known_hash);
} }
} }

View file

@ -5,16 +5,64 @@
// file, You can obtain one at http://mozilla.org/MPL/2.0/. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
use std::convert::TryFrom; use std::convert::TryFrom;
use std::str::FromStr;
use minidom::Element; use minidom::{Element, IntoAttributeValue};
use error::Error; use error::Error;
use ns; use ns;
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, PartialEq)]
pub enum Algo {
Sha_1,
Sha_256,
Sha_512,
Sha3_256,
Sha3_512,
Blake2b_256,
Blake2b_512,
Unknown(String),
}
impl FromStr for Algo {
type Err = Error;
fn from_str(s: &str) -> Result<Algo, Error> {
Ok(match s {
"" => return Err(Error::ParseError("'algo' argument cant be empty.")),
"sha-1" => Algo::Sha_1,
"sha-256" => Algo::Sha_256,
"sha-512" => Algo::Sha_512,
"sha3-256" => Algo::Sha3_256,
"sha3-512" => Algo::Sha3_512,
"blake2b-256" => Algo::Blake2b_256,
"blake2b-512" => Algo::Blake2b_512,
value => Algo::Unknown(value.to_owned()),
})
}
}
impl IntoAttributeValue for Algo {
fn into_attribute_value(self) -> Option<String> {
Some(String::from(match self {
Algo::Sha_1 => "sha-1",
Algo::Sha_256 => "sha-256",
Algo::Sha_512 => "sha-512",
Algo::Sha3_256 => "sha3-256",
Algo::Sha3_512 => "sha3-512",
Algo::Blake2b_256 => "blake2b-256",
Algo::Blake2b_512 => "blake2b-512",
Algo::Unknown(text) => return Some(text),
}))
}
}
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct Hash { pub struct Hash {
pub algo: String, pub algo: Algo,
pub hash: String, pub hash: String,
} }
@ -28,7 +76,10 @@ impl<'a> TryFrom<&'a Element> for Hash {
for _ in elem.children() { for _ in elem.children() {
return Err(Error::ParseError("Unknown child in hash element.")); return Err(Error::ParseError("Unknown child in hash element."));
} }
let algo = elem.attr("algo").ok_or(Error::ParseError("Mandatory argument 'algo' not present in hash element."))?.to_owned(); let algo = match elem.attr("algo") {
None => Err(Error::ParseError("Mandatory argument 'algo' not present in hash element.")),
Some(text) => Algo::from_str(text),
}?;
let hash = match elem.text().as_ref() { let hash = match elem.text().as_ref() {
"" => return Err(Error::ParseError("Hash element shouldnt be empty.")), "" => return Err(Error::ParseError("Hash element shouldnt be empty.")),
text => text.to_owned(), text => text.to_owned(),
@ -58,7 +109,7 @@ mod tests {
fn test_simple() { fn test_simple() {
let elem: Element = "<hash xmlns='urn:xmpp:hashes:2' algo='sha-256'>2XarmwTlNxDAMkvymloX3S5+VbylNrJt/l5QyPa+YoU=</hash>".parse().unwrap(); let elem: Element = "<hash xmlns='urn:xmpp:hashes:2' algo='sha-256'>2XarmwTlNxDAMkvymloX3S5+VbylNrJt/l5QyPa+YoU=</hash>".parse().unwrap();
let hash = Hash::try_from(&elem).unwrap(); let hash = Hash::try_from(&elem).unwrap();
assert_eq!(hash.algo, "sha-256"); assert_eq!(hash.algo, Algo::Sha_256);
assert_eq!(hash.hash, "2XarmwTlNxDAMkvymloX3S5+VbylNrJt/l5QyPa+YoU="); assert_eq!(hash.hash, "2XarmwTlNxDAMkvymloX3S5+VbylNrJt/l5QyPa+YoU=");
} }

View file

@ -238,6 +238,7 @@ impl<'a> Into<Element> for &'a Description {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use hashes::Algo;
#[test] #[test]
fn test_description() { fn test_description() {
@ -261,7 +262,7 @@ mod tests {
assert_eq!(desc.file.date, Some(String::from("2015-07-26T21:46:00"))); assert_eq!(desc.file.date, Some(String::from("2015-07-26T21:46:00")));
assert_eq!(desc.file.size, Some(6144u64)); assert_eq!(desc.file.size, Some(6144u64));
assert_eq!(desc.file.range, None); assert_eq!(desc.file.range, None);
assert_eq!(desc.file.hashes[0].algo, "sha-1"); assert_eq!(desc.file.hashes[0].algo, Algo::Sha_1);
assert_eq!(desc.file.hashes[0].hash, "w0mcJylzCn+AfvuGdqkty2+KP48="); assert_eq!(desc.file.hashes[0].hash, "w0mcJylzCn+AfvuGdqkty2+KP48=");
} }
@ -283,7 +284,7 @@ mod tests {
assert_eq!(desc.file.date, None); assert_eq!(desc.file.date, None);
assert_eq!(desc.file.size, None); assert_eq!(desc.file.size, None);
assert_eq!(desc.file.range, None); assert_eq!(desc.file.range, None);
assert_eq!(desc.file.hashes[0].algo, "sha-1"); assert_eq!(desc.file.hashes[0].algo, Algo::Sha_1);
assert_eq!(desc.file.hashes[0].hash, "w0mcJylzCn+AfvuGdqkty2+KP48="); assert_eq!(desc.file.hashes[0].hash, "w0mcJylzCn+AfvuGdqkty2+KP48=");
} }
} }