add working 2fa code generation

This commit is contained in:
Carson McManus 2021-03-21 21:21:29 -04:00
parent 24fefadd4d
commit 5b8d581a48
5 changed files with 147 additions and 1 deletions

2
.gitignore vendored
View file

@ -6,3 +6,5 @@ SteamAuth/SteamAuth/packages/
test_maFiles/ test_maFiles/
*.deb *.deb
target/

30
Cargo.lock generated Normal file
View file

@ -0,0 +1,30 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "base64"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
[[package]]
name = "hmac-sha1"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1333fad8d94b82cab989da428b0b36a3435db3870d85e971a1d6dc0a8576722"
dependencies = [
"sha1",
]
[[package]]
name = "sha1"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc30b1e1e8c40c121ca33b86c23308a090d19974ef001b4bf6e61fd1a0fb095c"
[[package]]
name = "steamguard-cli"
version = "0.2.0"
dependencies = [
"base64",
"hmac-sha1",
]

11
Cargo.toml Normal file
View file

@ -0,0 +1,11 @@
[package]
name = "steamguard-cli"
version = "0.2.0"
authors = ["Carson McManus <carson.mcmanus1@gmail.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
hmac-sha1 = "^0.1"
base64 = "0.13.0"

92
src/lib.rs Normal file
View file

@ -0,0 +1,92 @@
use std::convert::TryInto;
// const STEAMAPI_BASE: String = "https://api.steampowered.com";
// const COMMUNITY_BASE: String = "https://steamcommunity.com";
// const MOBILEAUTH_BASE: String = STEAMAPI_BASE + "/IMobileAuthService/%s/v0001";
// static MOBILEAUTH_GETWGTOKEN: String = MOBILEAUTH_BASE.Replace("%s", "GetWGToken");
// const TWO_FACTOR_BASE: String = STEAMAPI_BASE + "/ITwoFactorService/%s/v0001";
// static TWO_FACTOR_TIME_QUERY: String = TWO_FACTOR_BASE.Replace("%s", "QueryTime");
extern crate hmacsha1;
extern crate base64;
#[derive(Debug)]
pub struct SteamGuardAccount {
pub account_name: String,
pub revocation_code: String,
pub shared_secret: [u8; 20],
}
fn build_time_bytes(mut time: i64) -> [u8; 8] {
time /= 30i64;
let mut bytes: [u8; 8] = [0; 8];
for i in (0..8).rev() {
bytes[i] = time as u8;
time >>= 8;
}
return bytes
}
pub fn parse_shared_secret(secret: String) -> [u8; 20] {
if secret.len() == 0 {
panic!("unable to parse empty shared secret")
}
match base64::decode(secret) {
Result::Ok(v) => {
return v.try_into().unwrap()
}
_ => {
panic!("unable to parse shared secret")
}
}
}
impl SteamGuardAccount {
pub fn new() -> Self {
return SteamGuardAccount{
account_name: String::from(""),
revocation_code: String::from(""),
shared_secret: [0; 20],
}
}
pub fn generate_code(&self, time: i64) -> String {
let steam_guard_code_translations: [u8; 26] = [50, 51, 52, 53, 54, 55, 56, 57, 66, 67, 68, 70, 71, 72, 74, 75, 77, 78, 80, 81, 82, 84, 86, 87, 88, 89];
let time_bytes: [u8; 8] = build_time_bytes(time);
// println!("time_bytes: {:?}", time_bytes);
let hashed_data = hmacsha1::hmac_sha1(&self.shared_secret, &time_bytes);
// println!("hashed_data: {:?}", hashed_data);
let mut code_array: [u8; 5] = [0; 5];
let b = (hashed_data[19] & 0xF) as usize;
let mut code_point: i32 =
((hashed_data[b] & 0x7F) as i32) << 24 |
((hashed_data[b + 1] & 0xFF) as i32) << 16 |
((hashed_data[b + 2] & 0xFF) as i32) << 8 |
((hashed_data[b + 3] & 0xFF) as i32);
for i in 0..5 {
code_array[i] = steam_guard_code_translations[code_point as usize % steam_guard_code_translations.len()];
code_point /= steam_guard_code_translations.len() as i32;
}
// println!("code_array: {:?}", code_array);
return String::from_utf8(code_array.iter().map(|c| *c).collect()).unwrap()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_generate_code() {
let mut account = SteamGuardAccount::new();
account.shared_secret = parse_shared_secret(String::from("zvIayp3JPvtvX/QGHqsqKBk/44s="));
let code = account.generate_code(1616374841i64);
assert_eq!(code, "2F9J5")
}
}

11
src/main.rs Normal file
View file

@ -0,0 +1,11 @@
use steamguard_cli::*;
fn main() {
println!("Hello, world!");
let mut account = SteamGuardAccount::new();
account.shared_secret = parse_shared_secret(String::from("K5I0Fmm+sN0yF41vIslTVm+0nPE="));
let code = account.generate_code(93847539487i64);
println!("{}", code)
}