Switched from ring to the RustCrypto project
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
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 <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"
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<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;
}
}