add working 2fa code generation
This commit is contained in:
parent
24fefadd4d
commit
5b8d581a48
5 changed files with 147 additions and 1 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -5,4 +5,6 @@ obj/
|
|||
SteamAuth/SteamAuth/packages/
|
||||
test_maFiles/
|
||||
|
||||
*.deb
|
||||
*.deb
|
||||
|
||||
target/
|
||||
|
|
30
Cargo.lock
generated
Normal file
30
Cargo.lock
generated
Normal 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
11
Cargo.toml
Normal 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
92
src/lib.rs
Normal 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
11
src/main.rs
Normal 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)
|
||||
}
|
Loading…
Reference in a new issue