@@ -8,7 +8,7 @@ use std::convert::TryFrom;
use disco::{Feature, Identity, Disco};
use data_forms::DataForm;
-use hashes::Hash;
+use hashes::{Hash, Algo};
use minidom::Element;
use error::Error;
@@ -118,49 +118,52 @@ pub fn compute_disco(disco: &Disco) -> Vec<u8> {
final_string
}
-// TODO: make algo into an enum.
-pub fn hash_ecaps2(data: &[u8], algo: &str) -> String {
- match algo {
- "sha-256" => {
- let mut hasher = Sha256::default();
- hasher.input(data);
- let hash = hasher.result();
- base64::encode(&hash.as_slice())
+pub fn hash_ecaps2(data: &[u8], algo: Algo) -> Result<Hash, String> {
+ Ok(Hash {
+ algo: algo.clone(),
+ hash: match algo {
+ Algo::Sha_256 => {
+ let mut hasher = Sha256::default();
+ hasher.input(data);
+ let hash = hasher.result();
+ base64::encode(&hash.as_slice())
+ },
+ Algo::Sha_512 => {
+ let mut hasher = Sha512::default();
+ hasher.input(data);
+ let hash = hasher.result();
+ base64::encode(&hash.as_slice())
+ },
+ Algo::Sha3_256 => {
+ let mut hasher = Sha3_256::default();
+ hasher.input(data);
+ let hash = hasher.result();
+ base64::encode(&hash.as_slice())
+ },
+ Algo::Sha3_512 => {
+ let mut hasher = Sha3_512::default();
+ hasher.input(data);
+ let hash = hasher.result();
+ base64::encode(&hash.as_slice())
+ },
+ Algo::Blake2b_256 => {
+ let mut hasher = Blake2b::default();
+ hasher.input(data);
+ let mut buf: [u8; 32] = [0; 32];
+ let hash = hasher.variable_result(&mut buf).unwrap();
+ base64::encode(hash)
+ },
+ Algo::Blake2b_512 => {
+ let mut hasher = Blake2b::default();
+ hasher.input(data);
+ let mut buf: [u8; 64] = [0; 64];
+ let hash = hasher.variable_result(&mut buf).unwrap();
+ base64::encode(hash)
+ },
+ Algo::Sha_1 => return Err(String::from("Disabled algorithm sha-1: unsafe.")),
+ Algo::Unknown(algo) => return Err(format!("Unknown algorithm: {}.", algo)),
},
- "sha-512" => {
- let mut hasher = Sha512::default();
- hasher.input(data);
- let hash = hasher.result();
- base64::encode(&hash.as_slice())
- },
- "sha3-256" => {
- let mut hasher = Sha3_256::default();
- hasher.input(data);
- let hash = hasher.result();
- base64::encode(&hash.as_slice())
- },
- "sha3-512" => {
- let mut hasher = Sha3_512::default();
- hasher.input(data);
- let hash = hasher.result();
- base64::encode(&hash.as_slice())
- },
- "blake2b-256" => {
- let mut hasher = Blake2b::default();
- hasher.input(data);
- let mut buf: [u8; 32] = [0; 32];
- let hash = hasher.variable_result(&mut buf).unwrap();
- base64::encode(hash)
- },
- "blake2b-512" => {
- let mut hasher = Blake2b::default();
- hasher.input(data);
- let mut buf: [u8; 64] = [0; 64];
- let hash = hasher.variable_result(&mut buf).unwrap();
- base64::encode(hash)
- },
- _ => panic!(),
- }
+ })
}
#[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 ecaps2 = ECaps2::try_from(&elem).unwrap();
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[1].algo, "sha3-256");
+ assert_eq!(ecaps2.hashes[1].algo, Algo::Sha3_256);
assert_eq!(ecaps2.hashes[1].hash, "+sDTQqBmX6iG/X3zjt06fjZMBBqL/723knFIyRf0sg8=");
}
@@ -262,10 +265,10 @@ mod tests {
assert_eq!(ecaps2.len(), 0x1d9);
assert_eq!(ecaps2, expected);
- let sha_256 = ecaps2::hash_ecaps2(&ecaps2, "sha-256");
- assert_eq!(sha_256, "kzBZbkqJ3ADrj7v08reD1qcWUwNGHaidNUgD7nHpiw8=");
- let sha3_256 = ecaps2::hash_ecaps2(&ecaps2, "sha3-256");
- assert_eq!(sha3_256, "79mdYAfU9rEdTOcWDO7UEAt6E56SUzk/g6TnqUeuD9Q=");
+ let sha_256 = ecaps2::hash_ecaps2(&ecaps2, Algo::Sha_256).unwrap();
+ assert_eq!(sha_256.hash, "kzBZbkqJ3ADrj7v08reD1qcWUwNGHaidNUgD7nHpiw8=");
+ let sha3_256 = ecaps2::hash_ecaps2(&ecaps2, Algo::Sha3_256).unwrap();
+ assert_eq!(sha3_256.hash, "79mdYAfU9rEdTOcWDO7UEAt6E56SUzk/g6TnqUeuD9Q=");
}
#[test]
@@ -434,15 +437,15 @@ mod tests {
assert_eq!(ecaps2.len(), 0x543);
assert_eq!(ecaps2, expected);
- let sha_256 = ecaps2::hash_ecaps2(&ecaps2, "sha-256");
- assert_eq!(sha_256, "u79ZroNJbdSWhdSp311mddz44oHHPsEBntQ5b1jqBSY=");
- let sha3_256 = ecaps2::hash_ecaps2(&ecaps2, "sha3-256");
- assert_eq!(sha3_256, "XpUJzLAc93258sMECZ3FJpebkzuyNXDzRNwQog8eycg=");
+ let sha_256 = ecaps2::hash_ecaps2(&ecaps2, Algo::Sha_256).unwrap();
+ assert_eq!(sha_256.hash, "u79ZroNJbdSWhdSp311mddz44oHHPsEBntQ5b1jqBSY=");
+ let sha3_256 = ecaps2::hash_ecaps2(&ecaps2, Algo::Sha3_256).unwrap();
+ assert_eq!(sha3_256.hash, "XpUJzLAc93258sMECZ3FJpebkzuyNXDzRNwQog8eycg=");
}
#[test]
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!(
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,
@@ -450,6 +453,6 @@ mod tests {
0x18, 0xD3, 0x8A, 0xA8, 0xDB, 0xF1, 0x92, 0x5A, 0xB9, 0x23, 0x86, 0xED, 0xD4, 0x00, 0x99, 0x23,
);
let known_hash = base64::encode(&known_hash);
- assert_eq!(hash, known_hash);
+ assert_eq!(hash.hash, known_hash);
}
}
@@ -5,16 +5,64 @@
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
use std::convert::TryFrom;
+use std::str::FromStr;
-use minidom::Element;
+use minidom::{Element, IntoAttributeValue};
use error::Error;
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 can’t 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)]
pub struct Hash {
- pub algo: String,
+ pub algo: Algo,
pub hash: String,
}
@@ -28,7 +76,10 @@ impl<'a> TryFrom<&'a Element> for Hash {
for _ in elem.children() {
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() {
"" => return Err(Error::ParseError("Hash element shouldn’t be empty.")),
text => text.to_owned(),
@@ -58,7 +109,7 @@ mod tests {
fn test_simple() {
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();
- assert_eq!(hash.algo, "sha-256");
+ assert_eq!(hash.algo, Algo::Sha_256);
assert_eq!(hash.hash, "2XarmwTlNxDAMkvymloX3S5+VbylNrJt/l5QyPa+YoU=");
}
@@ -238,6 +238,7 @@ impl<'a> Into<Element> for &'a Description {
#[cfg(test)]
mod tests {
use super::*;
+ use hashes::Algo;
#[test]
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.size, Some(6144u64));
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=");
}
@@ -283,7 +284,7 @@ mod tests {
assert_eq!(desc.file.date, None);
assert_eq!(desc.file.size, 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=");
}
}