use std::collections::HashMap;
use chrono::Utc;
use hmac::{Hmac, Mac};
use sha2::Sha256;
pub struct Signature {
datetime: String,
secret_access_key: String,
region: String,
service: String,
cache: HashMap<String, Vec<u8>>,
}
impl Signature {
pub fn new(secret_access_key: String, region: String, service: String) -> Self {
Self {
datetime: Utc::now().format("%Y%m%dT%H%M%SZ").to_string(),
secret_access_key,
region,
service,
cache: HashMap::new(),
}
}
pub fn signature(&mut self) -> String {
let date = &self.datetime[0..8];
let cache_key = format!("{},{},{},{}", self.secret_access_key, date, self.region, self.service);
let k_date = hmac_sha256(format!("AWS4{}", self.secret_access_key).as_bytes(), date.as_bytes());
let k_region = hmac_sha256(&k_date, self.region.as_bytes());
let k_service = hmac_sha256(&k_region, self.service.as_bytes());
let k_signing = hmac_sha256(&k_service, b"aws4_request");
self.cache.insert(cache_key.clone(), k_signing.clone());
buf2hex(k_signing.as_slice())
}
}
type HmacSha256 = Hmac<Sha256>;
fn hmac_sha256(key: &[u8], data: &[u8]) -> Vec<u8> {
let mut mac = HmacSha256::new_from_slice(key).expect("HMAC can take key of any size");
mac.update(data);
mac.finalize().into_bytes().to_vec()
}
pub fn buf2hex(array_buffer: &[u8]) -> String {
const HEX_CHARS: [char; 16] = [
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
];
let mut out = String::with_capacity(array_buffer.len() * 2);
for &byte in array_buffer {
out.push(HEX_CHARS[(byte >> 4) as usize]);
out.push(HEX_CHARS[(byte & 0xf) as usize]);
}
out
}