use crate::prelude::*;
#[ext]
pub impl<T> T where T: Debug {
fn to_debug(&self) -> String { format!("{:?}", self) }
}
#[ext]
pub impl<T,E> Result<T,E> where AE: From<E> {
fn dcontext<D:Debug>(self, d: D) -> anyhow::Result<T> {
self.map_err(|e| AE::from(e)).with_context(|| d.to_debug())
}
}
#[derive(Error,Debug)]
pub enum ReadLimitedError {
#[error("maximum size {limit} exceeded")]
Truncated { sofar: Box<[u8]>, limit: usize },
#[error("HTTP error {0}")]
Hyper(#[from] hyper::Error),
}
impl ReadLimitedError {
pub fn discard_data(&mut self) { match self {
ReadLimitedError::Truncated { sofar,.. } => { mem::take(sofar); },
_ => { },
} }
}
#[ext]
pub impl<T> Result<T,ReadLimitedError> {
fn discard_data(self) -> Self {
self.map_err(|mut e| { e.discard_data(); e })
}
}
#[ext]
pub impl io::Error {
fn is_is_a_directory(&self) -> bool {
self.raw_os_error()
.unwrap_or_else(|| panic!(
"trying to tell whether Kind is IsADirectory for non-OS error io::Error {}",
self))
== libc::EISDIR
}
}
#[throws(ReadLimitedError)]
pub async fn read_limited_bytes<S>(limit: usize, initial: Box<[u8]>,
capacity: usize,
stream: &mut S) -> Box<[u8]>
where S: futures::Stream<Item=Result<hyper::body::Bytes,hyper::Error>>
+ Debug + Unpin,
{
let mut accum = initial.into_vec();
let capacity = min(limit, capacity);
if capacity > accum.len() { accum.reserve(capacity - accum.len()); }
while let Some(item) = stream.next().await {
let b = item?;
accum.extend(b);
if accum.len() > limit {
throw!(ReadLimitedError::Truncated { limit, sofar: accum.into() })
}
}
accum.into()
}
pub fn time_t_now() -> u64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_else(|_| Duration::default()) .as_secs()
}
use sha2::Digest as _;
use sha2::digest::Update as _;
pub type HmacH = sha2::Sha256;
pub const HMAC_B: usize = 64;
pub const HMAC_L: usize = 32;
pub fn token_hmac(key: &[u8], message: &[u8]) -> [u8; HMAC_L] {
let key = {
let mut padded = [0; HMAC_B];
if key.len() > padded.len() {
let digest: [u8; HMAC_L] = HmacH::digest(key).into();
padded[0..HMAC_L].copy_from_slice(&digest);
} else {
padded[0.. key.len()].copy_from_slice(key);
}
padded
};
let mut ikey = key; for k in &mut ikey { *k ^= 0x36; }
let mut okey = key; for k in &mut okey { *k ^= 0x5C; }
let h1 = HmacH::new()
.chain(ikey)
.chain(message)
.finalize();
let h2 = HmacH::new()
.chain(okey)
.chain(h1)
.finalize();
h2.into()
}
#[test]
fn hmac_test_vectors(){
let vectors = r#"
Key = 0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
0b0b0b0b (20 bytes)
Data = 4869205468657265 ("Hi There")
HMAC-SHA-256 = b0344c61d8db38535ca8afceaf0bf12b
881dc200c9833da726e9376c2e32cff7
Key = 4a656665 ("Jefe")
Data = 7768617420646f2079612077616e7420 ("what do ya want ")
666f72206e6f7468696e673f ("for nothing?")
HMAC-SHA-256 = 5bdcc146bf60754e6a042426089575c7
5a003f089d2739839dec58b964ec3843
Key = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaa (20 bytes)
Data = dddddddddddddddddddddddddddddddd
dddddddddddddddddddddddddddddddd
dddddddddddddddddddddddddddddddd
dddd (50 bytes)
HMAC-SHA-256 = 773ea91e36800e46854db8ebd09181a7
2959098b3ef8c122d9635514ced565fe
Key = 0102030405060708090a0b0c0d0e0f10
111213141516171819 (25 bytes)
Data = cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd
cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd
cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd
cdcd (50 bytes)
HMAC-SHA-256 = 82558a389a443c0ea4cc819899f2083a
85f0faa3e578f8077a2e3ff46729665b
Key = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaa (131 bytes)
Data = 54657374205573696e67204c61726765 ("Test Using Large")
72205468616e20426c6f636b2d53697a ("r Than Block-Siz")
65204b6579202d2048617368204b6579 ("e Key - Hash Key")
204669727374 (" First")
HMAC-SHA-256 = 60e431591ee0b67f0d8a26aacbf5b77f
8e0bc6213728c5140546040f0ee37f54
Key = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaa (131 bytes)
Data = 54686973206973206120746573742075 ("This is a test u")
73696e672061206c6172676572207468 ("sing a larger th")
616e20626c6f636b2d73697a65206b65 ("an block-size ke")
7920616e642061206c61726765722074 ("y and a larger t")
68616e20626c6f636b2d73697a652064 ("han block-size d")
6174612e20546865206b6579206e6565 ("ata. The key nee")
647320746f2062652068617368656420 ("ds to be hashed ")
6265666f7265206265696e6720757365 ("before being use")
642062792074686520484d414320616c ("d by the HMAC al")
676f726974686d2e ("gorithm.")
HMAC-SHA-256 = 9b09ffa71b942fcb27635fbcd5b0e944
bfdc63644f0713938a7f51535c3a35e2
"#;
let vectors = regex_replace_all!{
r#"\(.*\)"#,
vectors.trim_end(),
|_| "",
};
let vectors = regex_replace_all!{
r#" *\n "#,
&vectors,
|_| "",
};
let vectors = regex_replace_all!{
r#"\s*\n"#,
&vectors,
|_| "\n",
};
let mut lines = vectors.split('\n');
assert_eq!( lines.next().unwrap(), "" );
let mut get = |prefix| {
let l = lines.next()?;
dbg!(l);
let b = l.strip_prefix(prefix).unwrap().as_bytes().chunks(2)
.map(|s| str::from_utf8(s).unwrap())
.map(|s| { assert_eq!(s.len(), 2); u8::from_str_radix(s,16).unwrap() })
.collect::<Vec<u8>>();
Some(b)
};
while let Some(key) = get(" Key = ") {
let data = get(" Data = ").unwrap();
let exp = get(" HMAC-SHA-256 = ").unwrap();
let got = token_hmac(&key, &data);
assert_eq!(&got[..], &exp);
}
}