From bba8e818daf8f8c407ce21ce6f62f31fc2b19704 Mon Sep 17 00:00:00 2001 From: Cleo Rebert Date: Tue, 16 Jun 2020 14:39:08 +0200 Subject: [PATCH] Switched from ring to the RustCrypto project --- Cargo.toml | 6 +++-- src/lib.rs | 66 +++++++++++++++++++++++++++++------------------------- 2 files changed, 40 insertions(+), 32 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 57f8dc6..cdbd1a1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "totp-rs" -version = "0.2.5" +version = "0.2.6" authors = ["Cleo Rebert "] edition = "2018" readme = "README.md" @@ -13,7 +13,9 @@ categories = ["authentication", "web-programming"] [dependencies] serde = { version = "1.0", features = ["derive"] } -ring = ">= 0.13" +sha2 = "0.9.0" +sha-1 = "0.9.0" +hmac = "0.8.0" byteorder = ">= 1.3" base32 = ">= 0.4" qrcode = ">= 0.12" diff --git a/src/lib.rs b/src/lib.rs index aa94529..2a27f02 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,14 +18,22 @@ use serde::{Deserialize, Serialize}; use base32; +use base64; + use byteorder::{BigEndian, ReadBytesExt}; -use ring::hmac; use std::io::Cursor; -use base64; use image::Luma; use qrcode::QrCode; +use hmac::{Hmac, Mac, NewMac}; +use sha1::Sha1; +use sha2::{Sha256, Sha512}; + +type HmacSha1 = Hmac; +type HmacSha256 = Hmac; +type HmacSha512 = Hmac; + /// Algorithm enum holds the three standards algorithms for TOTP as per the [reference implementation](https://tools.ietf.org/html/rfc6238#appendix-A) #[derive(Debug, Serialize, Deserialize, Copy, Clone)] pub enum Algorithm { @@ -61,18 +69,31 @@ impl TOTP { } } - /// Will generate a token according to the provided timestamp in seconds - pub fn generate(&self, time: u64) -> String { - let key: hmac::Key; + /// Will sign the given timestamp + pub fn sign(&self, time: u64) -> Vec { + let ctr = (time / self.step).to_be_bytes().to_vec(); match self.algorithm { Algorithm::SHA1 => { - key = hmac::Key::new(hmac::HMAC_SHA1_FOR_LEGACY_USE_ONLY, &self.secret) + let mut mac = HmacSha1::new_varkey(&self.secret).expect("no key"); + mac.update(&ctr); + mac.finalize().into_bytes().to_vec() + } + Algorithm::SHA256 => { + let mut mac = HmacSha256::new_varkey(&self.secret).expect("no key"); + mac.update(&ctr); + mac.finalize().into_bytes().to_vec() + } + Algorithm::SHA512 => { + let mut mac = HmacSha512::new_varkey(&self.secret).expect("no key"); + mac.update(&ctr); + mac.finalize().into_bytes().to_vec() } - Algorithm::SHA256 => key = hmac::Key::new(hmac::HMAC_SHA256, &self.secret), - Algorithm::SHA512 => key = hmac::Key::new(hmac::HMAC_SHA512, &self.secret), } - let ctr = (time / self.step).to_be_bytes().to_vec(); - let result = hmac::sign(&key, &ctr); + } + + /// Will generate a token according to the provided timestamp in seconds + pub fn generate(&self, time: u64) -> String { + let result: &[u8] = &self.sign(time); let offset = (result.as_ref()[19] & 15) as usize; let mut rdr = Cursor::new(result.as_ref()[offset..offset + 4].to_vec()); let result = rdr.read_u32::().unwrap() & 0x7fff_ffff; @@ -85,26 +106,11 @@ impl TOTP { /// Will check if token is valid by current time, accounting [skew](struct.TOTP.html#structfield.skew) pub fn check(&self, token: String, time: u64) -> bool { - let key: hmac::Key; - match self.algorithm { - Algorithm::SHA1 => { - key = hmac::Key::new(hmac::HMAC_SHA1_FOR_LEGACY_USE_ONLY, &self.secret) - } - Algorithm::SHA256 => key = hmac::Key::new(hmac::HMAC_SHA256, &self.secret), - Algorithm::SHA512 => key = hmac::Key::new(hmac::HMAC_SHA512, &self.secret), - } - let basestep = time / 30 - (self.skew as u64); - for _i in 0..self.skew * 2 + 1 { - let result = hmac::sign(&key, &basestep.to_be_bytes().to_vec()); - let offset = (result.as_ref()[19] & 15) as usize; - let mut rdr = Cursor::new(result.as_ref()[offset..offset + 4].to_vec()); - let result = rdr.read_u32::().unwrap() & 0x7fffffff; - if format!( - "{1:00$}", - self.digits, - result % (10 as u32).pow(self.digits as u32) - ) == token - { + let basestep = time / self.step - (self.skew as u64); + for i in 0..self.skew * 2 + 1 { + let step_time = (basestep + (i as u64)) * (self.step as u64); + println!("{}", self.generate(step_time)); + if self.generate(step_time) == token { return true; } }