1
- use crate :: util:: { get_code, hash_generic, MacDigest } ;
2
- use base32:: Alphabet ;
1
+ use crate :: util:: { base32_decode, get_code, hash_generic, MacDigest } ;
3
2
4
3
/// A TOTP generator
5
4
///
@@ -30,28 +29,38 @@ pub struct TOTP {
30
29
/// Unless an initializer ending in 'with_digest' is used, this value
31
30
/// defaults to [`MacDigest::SHA1`]
32
31
mac_digest : MacDigest ,
32
+
33
+ digits : u32 ,
34
+
35
+ period : u64 ,
33
36
}
34
37
35
38
/// All initializer implementations for the [`TOTP`] struct
36
39
impl TOTP {
40
+ pub fn new ( secret : & [ u8 ] , mac_digest : MacDigest , digits : u32 , period : u64 ) -> Self {
41
+ TOTP {
42
+ secret : secret. to_vec ( ) ,
43
+ mac_digest,
44
+ digits,
45
+ period,
46
+ }
47
+ }
48
+
37
49
/// Creates a new TOTP instance with a byte-array representation
38
50
/// of the secret
39
51
///
40
52
/// Defaults to using [`MacDigest::SHA1`] as the digest for HMAC
41
53
/// operations.
42
- pub fn new ( secret : & [ u8 ] ) -> Self {
43
- TOTP :: new_with_digest ( secret, MacDigest :: SHA1 )
54
+ pub fn from_secret ( secret : & [ u8 ] ) -> Self {
55
+ TOTP :: from_secret_with_digest ( secret, MacDigest :: SHA1 )
44
56
}
45
57
46
58
/// Creates a new TOTP instance with a byte-array representation
47
59
/// of the secret and a specific digest for HMAC operations
48
60
///
49
61
/// Allows for non-SHA1 algorithms to be used with TOTP generation
50
- pub fn new_with_digest ( secret : & [ u8 ] , mac_digest : MacDigest ) -> Self {
51
- TOTP {
52
- secret : secret. to_vec ( ) ,
53
- mac_digest,
54
- }
62
+ pub fn from_secret_with_digest ( secret : & [ u8 ] , mac_digest : MacDigest ) -> Self {
63
+ TOTP :: new ( secret, mac_digest, 6 , 30 )
55
64
}
56
65
57
66
/// Creates a new TOTP instance from a utf8-encoded string secret
@@ -67,7 +76,7 @@ impl TOTP {
67
76
/// Like [`TOTP::new_with_digest`], this method allows a digest to be specified
68
77
/// instead of the default SHA1 being used.
69
78
pub fn from_utf8_with_digest ( secret : & str , mac_digest : MacDigest ) -> Self {
70
- TOTP :: new_with_digest ( secret. as_bytes ( ) , mac_digest)
79
+ TOTP :: from_secret_with_digest ( secret. as_bytes ( ) , mac_digest)
71
80
}
72
81
73
82
/// Creates a new TOTP instance from a base32-encoded string secret
@@ -90,9 +99,22 @@ impl TOTP {
90
99
/// # Panics
91
100
/// This method panics if the provided string is not correctly base32 encoded.
92
101
pub fn from_base32_with_digest ( secret : & str , mac_digest : MacDigest ) -> Self {
93
- let decoded = base32:: decode ( Alphabet :: RFC4648 { padding : false } , secret)
94
- . expect ( "Failed to decode base32 string" ) ;
95
- TOTP :: new_with_digest ( & decoded, mac_digest)
102
+ let decoded = base32_decode ( secret) . expect ( "Failed to decode base32 string" ) ;
103
+ TOTP :: from_secret_with_digest ( & decoded, mac_digest)
104
+ }
105
+ }
106
+
107
+ impl TOTP {
108
+ pub fn get_digest ( & self ) -> MacDigest {
109
+ self . mac_digest
110
+ }
111
+
112
+ pub fn get_digits ( & self ) -> u32 {
113
+ self . digits
114
+ }
115
+
116
+ pub fn get_period ( & self ) -> u64 {
117
+ self . period
96
118
}
97
119
}
98
120
@@ -111,8 +133,8 @@ impl TOTP {
111
133
/// # Panics
112
134
/// This method panics if the called [`TOTP::get_otp_with_custom`] method
113
135
/// does, which would happen if the hash's secret is incorrectly given.
114
- pub fn get_otp ( & self , time : u64 , digits : u32 ) -> u32 {
115
- self . get_otp_with_custom ( time, 30 , 0 , digits )
136
+ pub fn get_otp ( & self , time : u64 ) -> u32 {
137
+ self . get_otp_with_custom_time_start ( time, 0 )
116
138
}
117
139
118
140
/// Generates and returns the TOTP value for the time with a provided step,
@@ -125,21 +147,15 @@ impl TOTP {
125
147
///
126
148
/// # Panics
127
149
/// This method panics if the hash's secret is incorrectly given.
128
- pub fn get_otp_with_custom (
129
- & self ,
130
- time : u64 ,
131
- time_step : u64 ,
132
- time_start : u64 ,
133
- digits : u32 ,
134
- ) -> u32 {
135
- let time_count = ( time - time_start) / time_step;
150
+ pub fn get_otp_with_custom_time_start ( & self , time : u64 , time_start : u64 ) -> u32 {
151
+ let time_count = ( time - time_start) / self . period ;
136
152
137
153
let hash = hash_generic ( & time_count. to_be_bytes ( ) , & self . secret , & self . mac_digest ) ;
138
154
let offset = ( hash[ hash. len ( ) - 1 ] & 0xf ) as usize ;
139
155
let bytes: [ u8 ; 4 ] = hash[ offset..offset + 4 ]
140
156
. try_into ( )
141
157
. expect ( "Failed byte get" ) ;
142
158
143
- get_code ( bytes, digits)
159
+ get_code ( bytes, self . digits )
144
160
}
145
161
}
0 commit comments