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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
use crate::error::ChecksumError;
use md5::Md5;
use sha1::Sha1;
use sha2::{Digest, Sha224, Sha256, Sha384, Sha512};

pub struct Checksum {
    hasher: Hasher,
    contents: String,
}

impl Checksum {
    pub fn new_inner(hash: impl Into<String>, checksum_type: CsType) -> Self {
        Self {
            hasher: checksum_type.into(),
            contents: hash.into(),
        }
    }
    pub fn new(hash: impl Into<String>) -> Result<Self, ChecksumError> {
        let hash = hash.into();
        let checksum_type = match hash.len() {
            32 => CsType::MD5,
            40 => CsType::Sha1,
            56 => CsType::Sha224,
            64 => CsType::Sha256,
            96 => CsType::Sha384,
            128 => CsType::Sha512,
            _ => return Err(ChecksumError::UnrecognizedSize),
        };
        Ok(Self::new_inner(hash, checksum_type))
    }
    pub fn update(&mut self, data: &[u8]) {
        match &mut self.hasher {
            Hasher::Md5(hasher) => hasher.update(data),
            Hasher::Sha1(hasher) => hasher.update(data),
            Hasher::Sha224(hasher) => hasher.update(data),
            Hasher::Sha256(hasher) => hasher.update(data),
            Hasher::Sha384(hasher) => hasher.update(data),
            Hasher::Sha512(hasher) => hasher.update(data),
        }
    }
    pub fn verify(self) -> bool {
        let hash = match self.hasher {
            Hasher::Md5(hasher) => format!("{:x}", hasher.finalize()),
            Hasher::Sha1(hasher) => format!("{:x}", hasher.finalize()),
            Hasher::Sha224(hasher) => format!("{:x}", hasher.finalize()),
            Hasher::Sha256(hasher) => format!("{:x}", hasher.finalize()),
            Hasher::Sha384(hasher) => format!("{:x}", hasher.finalize()),
            Hasher::Sha512(hasher) => format!("{:x}", hasher.finalize()),
        };
        log::debug!("Hash: {}, Contents: {}", hash, self.contents);
        hash == self.contents
    }
}

pub enum Hasher {
    Md5(Md5),
    Sha1(Sha1),
    Sha224(Sha224),
    Sha256(Sha256),
    Sha384(Sha384),
    Sha512(Sha512),
}
impl From<CsType> for Hasher {
    fn from(value: CsType) -> Self {
        match value {
            CsType::MD5 => Self::Md5(Md5::new()),
            CsType::Sha1 => Self::Sha1(Sha1::new()),
            CsType::Sha224 => Self::Sha224(Sha224::new()),
            CsType::Sha256 => Self::Sha256(Sha256::new()),
            CsType::Sha384 => Self::Sha384(Sha384::new()),
            CsType::Sha512 => Self::Sha512(Sha512::new()),
        }
    }
}

pub enum CsType {
    MD5,
    Sha1,
    Sha224,
    Sha256,
    Sha384,
    Sha512,
}