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 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
use super::*;
use crate::error::SigningErr;
use hmac::{Hmac, Mac};
use sha2::{Sha512, Sha256};
use crate::{cryptography::*, error::*};
/// Represents a cryptographic signing operation, including data, passphrase, operational status,
/// hash type, signature length, and verification status.
impl Sign {
/// Constructs a new `Sign` instance with specified data, passphrase, operation status, and hash type.
///
/// # Parameters
/// - `data`: The data to be signed or verified.
/// - `passphrase`: The passphrase used for HMAC generation.
/// - `status`: The operation status (signing or verifying).
/// - `hash_type`: The hash algorithm to use for signing.
///
/// # Returns
/// A new `Sign` instance.
pub fn new(data: Vec<u8>, passphrase: Vec<u8>, status: Operation, hash_type: SignType) -> Self {
let data = SignatureData {
data, passphrase, hmac: Vec::new(), concat_data: Vec::new()
};
match hash_type {
SignType::Sha512 => Sign { data, status, hash_type, length: 64, veryfied: false},
SignType::Sha256 => Sign { data, status, hash_type, length: 32, veryfied: false},
_ => Sign { data, status, hash_type, length: 64, veryfied: false},
}
}
/// Performs the HMAC operation based on the operation status: generates HMAC for signing
/// or verifies HMAC for verification.
///
/// # Returns
/// HMAC as a `Vec<u8>` for signing or the verified data for verification.
pub fn hmac(&mut self) -> Vec<u8> {
match &self.status {
Operation::Sign => {
let data = self.generate_hmac();
data
},
Operation::Verify => {
let data = self.verify_hmac();
data.unwrap()
},
_ => vec![],
}
}
/// Generates HMAC for the data using the specified hash type and passphrase.
///
/// # Returns
/// Concatenated original data and its HMAC as a `Vec<u8>`.
pub fn generate_hmac(&self) -> Vec<u8> {
let mut data = &self.data.data;
match &self.hash_type {
SignType::Sha512 => {
let mut mac = <Hmac<Sha512> as Mac>::new_from_slice(&self.data.passphrase)
.expect("HMAC can take key of any size");
mac.update(&data);
let hmac = mac.finalize().into_bytes().to_vec();
//println!("HMAC: {:?}", hmac);
let concat_data = [&self.data.data, hmac.as_slice()].concat();
//println!("Concated data: {:?}", concat_data);
concat_data
},
SignType::Sha256 => {
let mut mac = <Hmac<Sha256> as Mac>::new_from_slice(&self.data.passphrase)
.expect("HMAC can take key of any size");
mac.update(&data);
let hmac = mac.finalize().into_bytes().to_vec();
println!("HMAC: {:?}", hmac);
let concat_data = [&self.data.data, hmac.as_slice()].concat();
println!("Concated data: {:?}", concat_data);
concat_data
},
_ => vec![],
}
}
/// Verifies HMAC using SHA-512.
///
/// # Parameters
/// - `data`: The data part of the message.
/// - `hmac`: The HMAC to verify against.
/// - `passphrase`: The passphrase used for HMAC generation.
///
/// # Returns
/// `true` if verification is successful, `false` otherwise.
fn verify_hmac_sha512(data: &[u8], hmac: &[u8], passphrase: &[u8]) -> bool {
let mut mac = <Hmac<Sha512> as Mac>::new_from_slice(passphrase)
.expect("HMAC can take key of any size");
mac.update(data);
mac.verify_slice(hmac).is_ok()
}
/// Verifies HMAC using SHA-256.
///
/// # Parameters
/// - `data`: The data part of the message.
/// - `hmac`: The HMAC to verify against.
/// - `passphrase`: The passphrase used for HMAC generation.
///
/// # Returns
/// `true` if verification is successful, `false` otherwise.
fn verify_hmac_sha256(data: &[u8], hmac: &[u8], passphrase: &[u8]) -> bool {
let mut mac = <Hmac<Sha256> as Mac>::new_from_slice(passphrase)
.expect("HMAC can take key of any size");
mac.update(data);
mac.verify_slice(hmac).is_ok()
}
/// Verifies HMAC based on the hash type. Splits the provided data into the original data
/// and HMAC, then verifies the HMAC.
///
/// # Returns
/// `Ok(Vec<u8>)` containing the original data if verification is successful, `Err(&'static str)` otherwise.
pub fn verify_hmac(&self) -> Result<Vec<u8>, &'static str> {
if self.data.data.len() < self.length {
return Err("Data is too short for HMAC verification");
}
let (data, hmac) = self.data.data.split_at(self.data.data.len() - self.length);
let verification_success = match &self.hash_type {
SignType::Sha512 => Self::verify_hmac_sha512(data, hmac, &self.data.passphrase),
SignType::Sha256 => Self::verify_hmac_sha256(data, hmac, &self.data.passphrase),
_ => return Err("Unsupported HMAC hash type"),
};
if verification_success {
println!("splittet data: {:?}", data);
Ok(data.to_owned())
} else {
Err("HMAC verification failed")
}
}
}