Switched from ring to the RustCrypto project
This commit is contained in:
parent
0c19a359c3
commit
bba8e818da
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "totp-rs"
|
name = "totp-rs"
|
||||||
version = "0.2.5"
|
version = "0.2.6"
|
||||||
authors = ["Cleo Rebert <cleo.rebert@gmail.com>"]
|
authors = ["Cleo Rebert <cleo.rebert@gmail.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
@ -13,7 +13,9 @@ categories = ["authentication", "web-programming"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
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"
|
byteorder = ">= 1.3"
|
||||||
base32 = ">= 0.4"
|
base32 = ">= 0.4"
|
||||||
qrcode = ">= 0.12"
|
qrcode = ">= 0.12"
|
||||||
|
|
66
src/lib.rs
66
src/lib.rs
|
@ -18,14 +18,22 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use base32;
|
use base32;
|
||||||
|
use base64;
|
||||||
|
|
||||||
use byteorder::{BigEndian, ReadBytesExt};
|
use byteorder::{BigEndian, ReadBytesExt};
|
||||||
use ring::hmac;
|
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
|
||||||
use base64;
|
|
||||||
use image::Luma;
|
use image::Luma;
|
||||||
use qrcode::QrCode;
|
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)
|
/// 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)]
|
#[derive(Debug, Serialize, Deserialize, Copy, Clone)]
|
||||||
pub enum Algorithm {
|
pub enum Algorithm {
|
||||||
|
@ -61,18 +69,31 @@ impl TOTP {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Will generate a token according to the provided timestamp in seconds
|
/// Will sign the given timestamp
|
||||||
pub fn generate(&self, time: u64) -> String {
|
pub fn sign(&self, time: u64) -> Vec<u8> {
|
||||||
let key: hmac::Key;
|
let ctr = (time / self.step).to_be_bytes().to_vec();
|
||||||
match self.algorithm {
|
match self.algorithm {
|
||||||
Algorithm::SHA1 => {
|
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 offset = (result.as_ref()[19] & 15) as usize;
|
||||||
let mut rdr = Cursor::new(result.as_ref()[offset..offset + 4].to_vec());
|
let mut rdr = Cursor::new(result.as_ref()[offset..offset + 4].to_vec());
|
||||||
let result = rdr.read_u32::<BigEndian>().unwrap() & 0x7fff_ffff;
|
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)
|
/// 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 {
|
pub fn check(&self, token: String, time: u64) -> bool {
|
||||||
let key: hmac::Key;
|
let basestep = time / self.step - (self.skew as u64);
|
||||||
match self.algorithm {
|
for i in 0..self.skew * 2 + 1 {
|
||||||
Algorithm::SHA1 => {
|
let step_time = (basestep + (i as u64)) * (self.step as u64);
|
||||||
key = hmac::Key::new(hmac::HMAC_SHA1_FOR_LEGACY_USE_ONLY, &self.secret)
|
println!("{}", self.generate(step_time));
|
||||||
}
|
if self.generate(step_time) == token {
|
||||||
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
|
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue