Switched from ring to the RustCrypto project
This commit is contained in:
parent
0c19a359c3
commit
bba8e818da
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "totp-rs"
|
||||
version = "0.2.5"
|
||||
version = "0.2.6"
|
||||
authors = ["Cleo Rebert <cleo.rebert@gmail.com>"]
|
||||
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"
|
||||
|
|
66
src/lib.rs
66
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<Sha1>;
|
||||
type HmacSha256 = Hmac<Sha256>;
|
||||
type HmacSha512 = Hmac<Sha512>;
|
||||
|
||||
/// 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<u8> {
|
||||
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::<BigEndian>().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::<BigEndian>().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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue