aboutsummaryrefslogtreecommitdiff
path: root/src/passwordmaker/hmac.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/passwordmaker/hmac.rs')
-rw-r--r--src/passwordmaker/hmac.rs58
1 files changed, 58 insertions, 0 deletions
diff --git a/src/passwordmaker/hmac.rs b/src/passwordmaker/hmac.rs
new file mode 100644
index 0000000..4c9d6aa
--- /dev/null
+++ b/src/passwordmaker/hmac.rs
@@ -0,0 +1,58 @@
+use crate::Hasher;
+
+pub(super) fn hmac<T, K, M>(key : K, data : M) -> T::Output
+ where T : Hasher,
+ T::Output : AsRef<[u8]>,
+ K : Iterator<Item=u8> + Clone,
+ M : Iterator<Item=u8>,
+{
+ let key_len = key.clone().count();
+ let key = if key_len > 64 {
+ KeyOrHash::from_hash(T::hash(&key.collect::<Vec<_>>()))
+ } else {
+ KeyOrHash::from_key(key)
+ };
+ let key = key.chain(std::iter::repeat(0)); //if key[i] does not exist, use 0 instead.
+
+ let mut inner_pad = [0u8;64];
+ let mut outer_pad = [0u8;64];
+
+ let pads = inner_pad.iter_mut().zip(outer_pad.iter_mut());
+ for ((i,o),k) in pads.zip(key) {
+ *i = k ^ 0x36;
+ *o = k ^ 0x5C;
+ }
+
+ let hash = T::hash(&inner_pad.iter().copied().chain(data).collect::<Vec<_>>());
+ T::hash(&outer_pad.iter().chain(hash.as_ref().iter()).copied().collect::<Vec<_>>())
+}
+
+enum KeyOrHash<K: Iterator<Item=u8>, H: AsRef<[u8]>> {
+ Key(K),
+ Hash{
+ hash : H,
+ idx : usize
+ }
+}
+
+impl<K: Iterator<Item=u8>, H: AsRef<[u8]>> KeyOrHash<K, H>{
+ fn from_key(key : K) -> Self {
+ Self::Key(key)
+ }
+ fn from_hash(hash : H) -> Self {
+ Self::Hash { hash, idx: 0 }
+ }
+}
+
+impl<K: Iterator<Item=u8>, H: AsRef<[u8]>> Iterator for KeyOrHash<K, H>{
+ type Item = u8;
+ fn next(&mut self) -> Option<Self::Item> {
+ match self {
+ KeyOrHash::Key(k) => k.next(),
+ KeyOrHash::Hash { hash: owned, idx } => {
+ *idx += 1;
+ owned.as_ref().get(*idx-1).copied()
+ },
+ }
+ }
+} \ No newline at end of file