Merge branch 'binascii' into 'master'

otp: Use binascii to decode base32

See merge request World/Authenticator!197
This commit is contained in:
Bilal Elmoussaoui 2021-02-05 10:09:59 +00:00
commit 4013436c98
3 changed files with 43 additions and 12 deletions

8
Cargo.lock generated
View file

@ -259,7 +259,7 @@ dependencies = [
"anyhow",
"ashpd",
"async-std",
"data-encoding",
"binascii",
"diesel",
"diesel_migrations",
"futures",
@ -314,6 +314,12 @@ version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
[[package]]
name = "binascii"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "383d29d513d8764dcdc42ea295d979eb99c3c9f00607b3692cf68a431f7dca72"
[[package]]
name = "bitflags"
version = "1.2.1"

View file

@ -8,7 +8,7 @@ adw = {package = "libadwaita", git = "https://gitlab.gnome.org/bilelmoussaoui/li
anyhow = "1.0"
ashpd = {git = "https://github.com/bilelmoussaoui/ashpd", features = ["feature_gtk4"]}
async-std = "1.9"
data-encoding = "2.3"
binascii = "0.1"
diesel = {version = "1.4", features = ["sqlite", "r2d2"]}
diesel_migrations = {version = "1.4", features = ["sqlite"]}
futures = "0.3"

View file

@ -1,5 +1,5 @@
use super::Algorithm;
use anyhow::Result;
use anyhow::{anyhow, Result};
use ring::hmac;
use std::convert::TryInto;
use std::time::{SystemTime, UNIX_EPOCH};
@ -18,10 +18,14 @@ pub static TOTP_DEFAULT_PERIOD: u32 = 30;
/// into a byte string. It fails if secret is not a valid Base32 string.
fn decode_secret(secret: &str) -> Result<Vec<u8>> {
let secret = secret.trim().replace(' ', "").to_uppercase();
// The buffer should have a length of secret.len() * 5 / 8.
let size = secret.len();
let mut output_buffer = std::iter::repeat(0).take(size).collect::<Vec<u8>>();
let vec = binascii::b32decode(secret.as_bytes(), &mut output_buffer)
.map_err(|_| anyhow!("Invalid Input"))?
.to_vec();
data_encoding::BASE32_NOPAD
.decode(secret.as_bytes())
.map_err(From::from)
Ok(vec)
}
/// Validates if `secret` is a valid Base32 String.
@ -96,13 +100,29 @@ pub(crate) fn time_based_counter(period: u32) -> u64 {
#[cfg(test)]
mod tests {
use super::{format, hotp, steam, Algorithm, DEFAULT_DIGITS, TOTP_DEFAULT_PERIOD};
use data_encoding::BASE32_NOPAD;
#[test]
fn test_totp() {
let secret_sha1 = BASE32_NOPAD.encode(b"12345678901234567890");
let secret_sha256 = BASE32_NOPAD.encode(b"12345678901234567890123456789012");
let secret_sha512 = BASE32_NOPAD
.encode(b"1234567890123456789012345678901234567890123456789012345678901234");
let secret_sha1 = String::from_utf8(
binascii::b32encode(b"12345678901234567890", &mut [0; 64])
.unwrap()
.to_vec(),
)
.unwrap();
let secret_sha256 = String::from_utf8(
binascii::b32encode(b"12345678901234567890123456789012", &mut [0; 64])
.unwrap()
.to_vec(),
)
.unwrap();
let secret_sha512 = String::from_utf8(
binascii::b32encode(
b"1234567890123456789012345678901234567890123456789012345678901234",
&mut [0; 128],
)
.unwrap()
.to_vec(),
)
.unwrap();
let counter1 = 59 / TOTP_DEFAULT_PERIOD as u64;
assert_eq!(
@ -204,7 +224,12 @@ mod tests {
hotp("BASE32SECRET3232", 1401, Algorithm::SHA1, DEFAULT_DIGITS).ok(),
Some(316439)
);
let secret = BASE32_NOPAD.encode(b"12345678901234567890");
let secret = String::from_utf8(
binascii::b32encode(b"12345678901234567890", &mut [0; 64])
.unwrap()
.to_vec(),
)
.unwrap();
assert_eq!(
Some(755224),
hotp(&secret, 0, Algorithm::SHA1, DEFAULT_DIGITS).ok()