Switched from ring to the RustCrypto project

This commit is contained in:
Cleo Rebert 2020-06-16 14:39:08 +02:00
parent 0c19a359c3
commit bba8e818da
2 changed files with 40 additions and 32 deletions

View File

@ -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"

View File

@ -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;
} }
} }