upgrade base64 crate to 0.21 (#289)
This commit is contained in:
parent
d1ff150cbf
commit
96f342137a
11 changed files with 98 additions and 57 deletions
14
Cargo.lock
generated
14
Cargo.lock
generated
|
@ -262,12 +262,6 @@ version = "0.2.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270"
|
checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "base64"
|
|
||||||
version = "0.13.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base64"
|
name = "base64"
|
||||||
version = "0.21.2"
|
version = "0.21.2"
|
||||||
|
@ -2427,7 +2421,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55"
|
checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-compression",
|
"async-compression",
|
||||||
"base64 0.21.2",
|
"base64",
|
||||||
"bytes",
|
"bytes",
|
||||||
"cookie 0.16.2",
|
"cookie 0.16.2",
|
||||||
"cookie_store",
|
"cookie_store",
|
||||||
|
@ -2567,7 +2561,7 @@ version = "1.0.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2"
|
checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.21.2",
|
"base64",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -3009,7 +3003,7 @@ name = "steamguard"
|
||||||
version = "0.10.1"
|
version = "0.10.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"base64 0.13.1",
|
"base64",
|
||||||
"cookie 0.14.4",
|
"cookie 0.14.4",
|
||||||
"hmac",
|
"hmac",
|
||||||
"lazy_static 1.4.0",
|
"lazy_static 1.4.0",
|
||||||
|
@ -3043,7 +3037,7 @@ dependencies = [
|
||||||
"aes 0.8.3",
|
"aes 0.8.3",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"argon2",
|
"argon2",
|
||||||
"base64 0.13.1",
|
"base64",
|
||||||
"cbc",
|
"cbc",
|
||||||
"clap",
|
"clap",
|
||||||
"clap_complete",
|
"clap_complete",
|
||||||
|
|
|
@ -31,7 +31,7 @@ path = "src/main.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "^1.0"
|
anyhow = "^1.0"
|
||||||
base64 = "0.13.0"
|
base64 = "0.21.2"
|
||||||
text_io = "0.1.8"
|
text_io = "0.1.8"
|
||||||
rpassword = "5.0"
|
rpassword = "5.0"
|
||||||
reqwest = { version = "0.11", default-features = false, features = ["blocking", "json", "cookies", "gzip", "rustls-tls"] }
|
reqwest = { version = "0.11", default-features = false, features = ["blocking", "json", "cookies", "gzip", "rustls-tls"] }
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
use aes::cipher::block_padding::Pkcs7;
|
use aes::cipher::block_padding::Pkcs7;
|
||||||
use aes::cipher::{BlockDecryptMut, BlockEncryptMut, KeyIvInit};
|
use aes::cipher::{BlockDecryptMut, BlockEncryptMut, KeyIvInit};
|
||||||
use aes::Aes256;
|
use aes::Aes256;
|
||||||
|
use anyhow::Context;
|
||||||
use argon2::Argon2;
|
use argon2::Argon2;
|
||||||
|
use base64::Engine;
|
||||||
use log::*;
|
use log::*;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -19,7 +21,7 @@ impl Argon2idAes256 {
|
||||||
|
|
||||||
fn get_encryption_key(passkey: &str, salt: &str) -> anyhow::Result<[u8; Self::KEY_SIZE_BYTES]> {
|
fn get_encryption_key(passkey: &str, salt: &str) -> anyhow::Result<[u8; Self::KEY_SIZE_BYTES]> {
|
||||||
let password_bytes = passkey.as_bytes();
|
let password_bytes = passkey.as_bytes();
|
||||||
let salt_bytes = base64::decode(salt)?;
|
let salt_bytes = base64::engine::general_purpose::STANDARD.decode(salt)?;
|
||||||
let mut full_key: [u8; Self::KEY_SIZE_BYTES] = [0u8; Self::KEY_SIZE_BYTES];
|
let mut full_key: [u8; Self::KEY_SIZE_BYTES] = [0u8; Self::KEY_SIZE_BYTES];
|
||||||
let deriver = Argon2::new(
|
let deriver = Argon2::new(
|
||||||
argon2::Algorithm::Argon2id,
|
argon2::Algorithm::Argon2id,
|
||||||
|
@ -40,6 +42,14 @@ impl Argon2idAes256 {
|
||||||
)
|
)
|
||||||
.expect("Unable to create Argon2 config.")
|
.expect("Unable to create Argon2 config.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn decode_iv(&self) -> anyhow::Result<[u8; Self::IV_LENGTH]> {
|
||||||
|
let mut iv = [0u8; Self::IV_LENGTH];
|
||||||
|
base64::engine::general_purpose::STANDARD
|
||||||
|
.decode_slice_unchecked(&self.iv, &mut iv)
|
||||||
|
.context("decoding iv")?;
|
||||||
|
Ok(iv)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EntryEncryptor for Argon2idAes256 {
|
impl EntryEncryptor for Argon2idAes256 {
|
||||||
|
@ -50,8 +60,8 @@ impl EntryEncryptor for Argon2idAes256 {
|
||||||
rng.fill(&mut salt);
|
rng.fill(&mut salt);
|
||||||
rng.fill(&mut iv);
|
rng.fill(&mut iv);
|
||||||
Argon2idAes256 {
|
Argon2idAes256 {
|
||||||
iv: base64::encode(iv),
|
iv: base64::engine::general_purpose::STANDARD.encode(iv),
|
||||||
salt: base64::encode(salt),
|
salt: base64::engine::general_purpose::STANDARD.encode(salt),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,11 +75,11 @@ impl EntryEncryptor for Argon2idAes256 {
|
||||||
debug!("key derivation took: {:?}", start.elapsed());
|
debug!("key derivation took: {:?}", start.elapsed());
|
||||||
|
|
||||||
let start = std::time::Instant::now();
|
let start = std::time::Instant::now();
|
||||||
let mut iv = [0u8; Self::IV_LENGTH];
|
let iv = self.decode_iv()?;
|
||||||
base64::decode_config_slice(&self.iv, base64::STANDARD, &mut iv)?;
|
let cipher =
|
||||||
let cipher = cbc::Encryptor::<Aes256>::new_from_slices(&key, &iv)?;
|
cbc::Encryptor::<Aes256>::new_from_slices(&key, &iv).context("creating cipher")?;
|
||||||
let ciphertext = cipher.encrypt_padded_vec_mut::<Pkcs7>(&plaintext);
|
let ciphertext = cipher.encrypt_padded_vec_mut::<Pkcs7>(&plaintext);
|
||||||
let encoded = base64::encode(ciphertext);
|
let encoded = base64::engine::general_purpose::STANDARD.encode(ciphertext);
|
||||||
debug!("encryption took: {:?}", start.elapsed());
|
debug!("encryption took: {:?}", start.elapsed());
|
||||||
Ok(encoded.as_bytes().to_vec())
|
Ok(encoded.as_bytes().to_vec())
|
||||||
}
|
}
|
||||||
|
@ -84,10 +94,10 @@ impl EntryEncryptor for Argon2idAes256 {
|
||||||
debug!("key derivation took: {:?}", start.elapsed());
|
debug!("key derivation took: {:?}", start.elapsed());
|
||||||
|
|
||||||
let start = std::time::Instant::now();
|
let start = std::time::Instant::now();
|
||||||
let mut iv = [0u8; Self::IV_LENGTH];
|
let iv = self.decode_iv()?;
|
||||||
base64::decode_config_slice(&self.iv, base64::STANDARD, &mut iv)?;
|
let cipher =
|
||||||
let cipher = cbc::Decryptor::<Aes256>::new_from_slices(&key, &iv)?;
|
cbc::Decryptor::<Aes256>::new_from_slices(&key, &iv).context("creating cipher")?;
|
||||||
let decoded = base64::decode(ciphertext)?;
|
let decoded = base64::engine::general_purpose::STANDARD.decode(ciphertext)?;
|
||||||
let size: usize = decoded.len() / 16 + (if decoded.len() % 16 == 0 { 0 } else { 1 });
|
let size: usize = decoded.len() / 16 + (if decoded.len() % 16 == 0 { 0 } else { 1 });
|
||||||
let mut buffer = vec![0xffu8; 16 * size];
|
let mut buffer = vec![0xffu8; 16 * size];
|
||||||
buffer[..decoded.len()].copy_from_slice(&decoded);
|
buffer[..decoded.len()].copy_from_slice(&decoded);
|
||||||
|
@ -104,7 +114,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_encryption_key() {
|
fn test_encryption_key() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
base64::encode(
|
base64::engine::general_purpose::STANDARD.encode(
|
||||||
Argon2idAes256::get_encryption_key("password", "GMhL0N2hqXg=")
|
Argon2idAes256::get_encryption_key("password", "GMhL0N2hqXg=")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_slice()
|
.as_slice()
|
||||||
|
@ -116,7 +126,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_encryption_key2() {
|
fn test_encryption_key2() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
base64::encode(
|
base64::engine::general_purpose::STANDARD.encode(
|
||||||
Argon2idAes256::get_encryption_key("password", "wTzTE9A6aN8=")
|
Argon2idAes256::get_encryption_key("password", "wTzTE9A6aN8=")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_slice()
|
.as_slice()
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
use aes::cipher::block_padding::Pkcs7;
|
use aes::cipher::block_padding::Pkcs7;
|
||||||
use aes::cipher::{BlockDecryptMut, BlockEncryptMut, KeyIvInit};
|
use aes::cipher::{BlockDecryptMut, BlockEncryptMut, KeyIvInit};
|
||||||
use aes::Aes256;
|
use aes::Aes256;
|
||||||
|
use anyhow::Context;
|
||||||
|
use base64::Engine;
|
||||||
use log::*;
|
use log::*;
|
||||||
use sha1::Sha1;
|
use sha1::Sha1;
|
||||||
|
|
||||||
|
@ -21,7 +23,7 @@ impl LegacySdaCompatible {
|
||||||
|
|
||||||
fn get_encryption_key(passkey: &str, salt: &str) -> anyhow::Result<[u8; Self::KEY_SIZE_BYTES]> {
|
fn get_encryption_key(passkey: &str, salt: &str) -> anyhow::Result<[u8; Self::KEY_SIZE_BYTES]> {
|
||||||
let password_bytes = passkey.as_bytes();
|
let password_bytes = passkey.as_bytes();
|
||||||
let salt_bytes = base64::decode(salt)?;
|
let salt_bytes = base64::engine::general_purpose::STANDARD.decode(salt)?;
|
||||||
let mut full_key: [u8; Self::KEY_SIZE_BYTES] = [0u8; Self::KEY_SIZE_BYTES];
|
let mut full_key: [u8; Self::KEY_SIZE_BYTES] = [0u8; Self::KEY_SIZE_BYTES];
|
||||||
pbkdf2::pbkdf2_hmac::<Sha1>(
|
pbkdf2::pbkdf2_hmac::<Sha1>(
|
||||||
password_bytes,
|
password_bytes,
|
||||||
|
@ -31,6 +33,14 @@ impl LegacySdaCompatible {
|
||||||
);
|
);
|
||||||
Ok(full_key)
|
Ok(full_key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn decode_iv(&self) -> anyhow::Result<[u8; Self::IV_LENGTH]> {
|
||||||
|
let mut iv = [0u8; Self::IV_LENGTH];
|
||||||
|
base64::engine::general_purpose::STANDARD
|
||||||
|
.decode_slice_unchecked(&self.iv, &mut iv)
|
||||||
|
.context("decoding iv")?;
|
||||||
|
Ok(iv)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EntryEncryptor for LegacySdaCompatible {
|
impl EntryEncryptor for LegacySdaCompatible {
|
||||||
|
@ -41,8 +51,8 @@ impl EntryEncryptor for LegacySdaCompatible {
|
||||||
rng.fill(&mut salt);
|
rng.fill(&mut salt);
|
||||||
rng.fill(&mut iv);
|
rng.fill(&mut iv);
|
||||||
LegacySdaCompatible {
|
LegacySdaCompatible {
|
||||||
iv: base64::encode(iv),
|
iv: base64::engine::general_purpose::STANDARD.encode(iv),
|
||||||
salt: base64::encode(salt),
|
salt: base64::engine::general_purpose::STANDARD.encode(salt),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,11 +66,11 @@ impl EntryEncryptor for LegacySdaCompatible {
|
||||||
debug!("key derivation took: {:?}", start.elapsed());
|
debug!("key derivation took: {:?}", start.elapsed());
|
||||||
|
|
||||||
let start = std::time::Instant::now();
|
let start = std::time::Instant::now();
|
||||||
let mut iv = [0u8; Self::IV_LENGTH];
|
let iv = self.decode_iv()?;
|
||||||
base64::decode_config_slice(&self.iv, base64::STANDARD, &mut iv)?;
|
let cipher =
|
||||||
let cipher = cbc::Encryptor::<Aes256>::new_from_slices(&key, &iv)?;
|
cbc::Encryptor::<Aes256>::new_from_slices(&key, &iv).context("creating cipher")?;
|
||||||
let ciphertext = cipher.encrypt_padded_vec_mut::<Pkcs7>(&plaintext);
|
let ciphertext = cipher.encrypt_padded_vec_mut::<Pkcs7>(&plaintext);
|
||||||
let encoded = base64::encode(ciphertext);
|
let encoded = base64::engine::general_purpose::STANDARD.encode(ciphertext);
|
||||||
debug!("encryption took: {:?}", start.elapsed());
|
debug!("encryption took: {:?}", start.elapsed());
|
||||||
Ok(encoded.as_bytes().to_vec())
|
Ok(encoded.as_bytes().to_vec())
|
||||||
}
|
}
|
||||||
|
@ -75,10 +85,10 @@ impl EntryEncryptor for LegacySdaCompatible {
|
||||||
debug!("key derivation took: {:?}", start.elapsed());
|
debug!("key derivation took: {:?}", start.elapsed());
|
||||||
|
|
||||||
let start = std::time::Instant::now();
|
let start = std::time::Instant::now();
|
||||||
let mut iv = [0u8; Self::IV_LENGTH];
|
let iv = self.decode_iv()?;
|
||||||
base64::decode_config_slice(&self.iv, base64::STANDARD, &mut iv)?;
|
let cipher =
|
||||||
let cipher = cbc::Decryptor::<Aes256>::new_from_slices(&key, &iv)?;
|
cbc::Decryptor::<Aes256>::new_from_slices(&key, &iv).context("creating cipher")?;
|
||||||
let decoded = base64::decode(ciphertext)?;
|
let decoded = base64::engine::general_purpose::STANDARD.decode(ciphertext)?;
|
||||||
let size: usize = decoded.len() / 16 + (if decoded.len() % 16 == 0 { 0 } else { 1 });
|
let size: usize = decoded.len() / 16 + (if decoded.len() % 16 == 0 { 0 } else { 1 });
|
||||||
let mut buffer = vec![0xffu8; 16 * size];
|
let mut buffer = vec![0xffu8; 16 * size];
|
||||||
buffer[..decoded.len()].copy_from_slice(&decoded);
|
buffer[..decoded.len()].copy_from_slice(&decoded);
|
||||||
|
@ -100,7 +110,8 @@ mod tests {
|
||||||
LegacySdaCompatible::get_encryption_key("password", "GMhL0N2hqXg=")
|
LegacySdaCompatible::get_encryption_key("password", "GMhL0N2hqXg=")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_slice(),
|
.as_slice(),
|
||||||
base64::decode("KtiRa4/OxW83MlB6URf+Z8rAGj7CBY+pDlwD/NuVo6Y=")
|
base64::engine::general_purpose::STANDARD
|
||||||
|
.decode("KtiRa4/OxW83MlB6URf+Z8rAGj7CBY+pDlwD/NuVo6Y=")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_slice()
|
.as_slice()
|
||||||
);
|
);
|
||||||
|
@ -109,7 +120,8 @@ mod tests {
|
||||||
LegacySdaCompatible::get_encryption_key("password", "wTzTE9A6aN8=")
|
LegacySdaCompatible::get_encryption_key("password", "wTzTE9A6aN8=")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_slice(),
|
.as_slice(),
|
||||||
base64::decode("Dqpej/3DqEat0roJaHmu3luYgDzRCUmzX94n4fqvWj8=")
|
base64::engine::general_purpose::STANDARD
|
||||||
|
.decode("Dqpej/3DqEat0roJaHmu3luYgDzRCUmzX94n4fqvWj8=")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_slice()
|
.as_slice()
|
||||||
);
|
);
|
||||||
|
@ -140,8 +152,8 @@ mod tests {
|
||||||
/// An insecure but reproducible strategy for generating encryption params.
|
/// An insecure but reproducible strategy for generating encryption params.
|
||||||
fn encryption_params()(salt in any::<[u8; LegacySdaCompatible::SALT_LENGTH]>(), iv in any::<[u8; LegacySdaCompatible::IV_LENGTH]>()) -> LegacySdaCompatible {
|
fn encryption_params()(salt in any::<[u8; LegacySdaCompatible::SALT_LENGTH]>(), iv in any::<[u8; LegacySdaCompatible::IV_LENGTH]>()) -> LegacySdaCompatible {
|
||||||
LegacySdaCompatible {
|
LegacySdaCompatible {
|
||||||
salt: base64::encode(salt),
|
salt: base64::engine::general_purpose::STANDARD.encode(salt),
|
||||||
iv: base64::encode(iv),
|
iv: base64::engine::general_purpose::STANDARD.encode(iv),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ license = "MIT OR Apache-2.0"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "^1.0"
|
anyhow = "^1.0"
|
||||||
sha1 = "^0.10"
|
sha1 = "^0.10"
|
||||||
base64 = "0.13.0"
|
base64 = "^0.21"
|
||||||
reqwest = { version = "0.11", default-features = false, features = ["blocking", "json", "cookies", "gzip", "rustls-tls", "multipart"] }
|
reqwest = { version = "0.11", default-features = false, features = ["blocking", "json", "cookies", "gzip", "rustls-tls", "multipart"] }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
|
|
@ -5,6 +5,7 @@ use crate::steamapi::twofactor::TwoFactorClient;
|
||||||
use crate::token::TwoFactorSecret;
|
use crate::token::TwoFactorSecret;
|
||||||
use crate::transport::Transport;
|
use crate::transport::Transport;
|
||||||
use crate::{steamapi::EResult, token::Tokens, SteamGuardAccount};
|
use crate::{steamapi::EResult, token::Tokens, SteamGuardAccount};
|
||||||
|
use base64::Engine;
|
||||||
use log::*;
|
use log::*;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
@ -64,9 +65,13 @@ where
|
||||||
uri: resp.take_uri().into(),
|
uri: resp.take_uri().into(),
|
||||||
shared_secret: TwoFactorSecret::from_bytes(resp.take_shared_secret()),
|
shared_secret: TwoFactorSecret::from_bytes(resp.take_shared_secret()),
|
||||||
token_gid: resp.take_token_gid(),
|
token_gid: resp.take_token_gid(),
|
||||||
identity_secret: base64::encode(resp.take_identity_secret()).into(),
|
identity_secret: base64::engine::general_purpose::STANDARD
|
||||||
|
.encode(resp.take_identity_secret())
|
||||||
|
.into(),
|
||||||
device_id: self.device_id.clone(),
|
device_id: self.device_id.clone(),
|
||||||
secret_1: base64::encode(resp.take_secret_1()).into(),
|
secret_1: base64::engine::general_purpose::STANDARD
|
||||||
|
.encode(resp.take_secret_1())
|
||||||
|
.into(),
|
||||||
tokens: Some(self.tokens.clone()),
|
tokens: Some(self.tokens.clone()),
|
||||||
};
|
};
|
||||||
let success = AccountLinkSuccess {
|
let success = AccountLinkSuccess {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
use base64::Engine;
|
||||||
use hmac::{Hmac, Mac};
|
use hmac::{Hmac, Mac};
|
||||||
use log::*;
|
use log::*;
|
||||||
use reqwest::{
|
use reqwest::{
|
||||||
|
@ -403,13 +404,15 @@ fn generate_confirmation_hash_for_time(
|
||||||
tag: &str,
|
tag: &str,
|
||||||
identity_secret: impl AsRef<[u8]>,
|
identity_secret: impl AsRef<[u8]>,
|
||||||
) -> String {
|
) -> String {
|
||||||
let decode: &[u8] = &base64::decode(identity_secret).unwrap();
|
let decode: &[u8] = &base64::engine::general_purpose::STANDARD
|
||||||
|
.decode(identity_secret)
|
||||||
|
.unwrap();
|
||||||
let mut mac = Hmac::<Sha1>::new_from_slice(decode).unwrap();
|
let mut mac = Hmac::<Sha1>::new_from_slice(decode).unwrap();
|
||||||
mac.update(&build_time_bytes(time));
|
mac.update(&build_time_bytes(time));
|
||||||
mac.update(tag.as_bytes());
|
mac.update(tag.as_bytes());
|
||||||
let result = mac.finalize();
|
let result = mac.finalize();
|
||||||
let hash = result.into_bytes();
|
let hash = result.into_bytes();
|
||||||
base64::encode(hash)
|
base64::engine::general_purpose::STANDARD.encode(hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -24,6 +24,7 @@ impl Zeroize for Ip_addr {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod parse_tests {
|
mod parse_tests {
|
||||||
|
use base64::Engine;
|
||||||
use protobuf::Message;
|
use protobuf::Message;
|
||||||
|
|
||||||
use super::steammessages_auth_steamclient::CAuthentication_GetPasswordRSAPublicKey_Request;
|
use super::steammessages_auth_steamclient::CAuthentication_GetPasswordRSAPublicKey_Request;
|
||||||
|
@ -34,7 +35,7 @@ mod parse_tests {
|
||||||
req.set_account_name("hydrastar2".to_owned());
|
req.set_account_name("hydrastar2".to_owned());
|
||||||
|
|
||||||
let bytes = req.write_to_bytes().unwrap();
|
let bytes = req.write_to_bytes().unwrap();
|
||||||
let s = base64::encode_config(bytes, base64::URL_SAFE);
|
let s = base64::engine::general_purpose::URL_SAFE.encode(bytes);
|
||||||
assert_eq!(s, "CgpoeWRyYXN0YXIy");
|
assert_eq!(s, "CgpoeWRyYXN0YXIy");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use base64::Engine;
|
||||||
use hmac::{Hmac, Mac};
|
use hmac::{Hmac, Mac};
|
||||||
use secrecy::{ExposeSecret, Secret, SecretString};
|
use secrecy::{ExposeSecret, Secret, SecretString};
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
@ -25,7 +26,10 @@ impl TwoFactorSecret {
|
||||||
|
|
||||||
pub fn parse_shared_secret(secret: String) -> anyhow::Result<Self> {
|
pub fn parse_shared_secret(secret: String) -> anyhow::Result<Self> {
|
||||||
ensure!(!secret.is_empty(), "unable to parse empty shared secret");
|
ensure!(!secret.is_empty(), "unable to parse empty shared secret");
|
||||||
let result: [u8; 20] = base64::decode(secret)?.try_into().unwrap();
|
let result: [u8; 20] = base64::engine::general_purpose::STANDARD
|
||||||
|
.decode(secret)?
|
||||||
|
.try_into()
|
||||||
|
.unwrap();
|
||||||
Ok(Self(result.into()))
|
Ok(Self(result.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +71,11 @@ impl Serialize for TwoFactorSecret {
|
||||||
where
|
where
|
||||||
S: Serializer,
|
S: Serializer,
|
||||||
{
|
{
|
||||||
serializer.serialize_str(base64::encode(self.0.expose_secret()).as_str())
|
serializer.serialize_str(
|
||||||
|
base64::engine::general_purpose::STANDARD
|
||||||
|
.encode(self.0.expose_secret())
|
||||||
|
.as_str(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,7 +160,7 @@ fn decode_jwt(jwt: impl AsRef<str>) -> anyhow::Result<SteamJwtData> {
|
||||||
ensure!(parts.len() == 3, "Invalid JWT");
|
ensure!(parts.len() == 3, "Invalid JWT");
|
||||||
|
|
||||||
let data = parts[1];
|
let data = parts[1];
|
||||||
let bytes = base64::decode_config(data, base64::URL_SAFE)?;
|
let bytes = base64::engine::general_purpose::URL_SAFE.decode(data)?;
|
||||||
let json = String::from_utf8(bytes)?;
|
let json = String::from_utf8(bytes)?;
|
||||||
let jwt_data: SteamJwtData = serde_json::from_str(&json)?;
|
let jwt_data: SteamJwtData = serde_json::from_str(&json)?;
|
||||||
Ok(jwt_data)
|
Ok(jwt_data)
|
||||||
|
|
|
@ -43,7 +43,10 @@ impl Transport for WebApiTransport {
|
||||||
let mut req = self.client.request(Req::method(), &url);
|
let mut req = self.client.request(Req::method(), &url);
|
||||||
|
|
||||||
req = if Req::method() == reqwest::Method::GET {
|
req = if Req::method() == reqwest::Method::GET {
|
||||||
let encoded = encode_msg(apireq.request_data(), base64::URL_SAFE)?;
|
let encoded = encode_msg(
|
||||||
|
apireq.request_data(),
|
||||||
|
base64::engine::general_purpose::URL_SAFE,
|
||||||
|
)?;
|
||||||
let mut params = vec![("input_protobuf_encoded", encoded.as_str())];
|
let mut params = vec![("input_protobuf_encoded", encoded.as_str())];
|
||||||
if let Some(access_token) = apireq.access_token() {
|
if let Some(access_token) = apireq.access_token() {
|
||||||
params.push(("access_token", access_token.expose_secret()));
|
params.push(("access_token", access_token.expose_secret()));
|
||||||
|
@ -53,7 +56,10 @@ impl Transport for WebApiTransport {
|
||||||
if let Some(access_token) = apireq.access_token() {
|
if let Some(access_token) = apireq.access_token() {
|
||||||
req = req.query(&[("access_token", access_token)]);
|
req = req.query(&[("access_token", access_token)]);
|
||||||
}
|
}
|
||||||
let encoded = encode_msg(apireq.request_data(), base64::STANDARD)?;
|
let encoded = encode_msg(
|
||||||
|
apireq.request_data(),
|
||||||
|
base64::engine::general_purpose::STANDARD,
|
||||||
|
)?;
|
||||||
let form = Form::new().text("input_protobuf_encoded", encoded);
|
let form = Form::new().text("input_protobuf_encoded", encoded);
|
||||||
req.multipart(form)
|
req.multipart(form)
|
||||||
};
|
};
|
||||||
|
@ -119,9 +125,9 @@ impl Transport for WebApiTransport {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn encode_msg<T: MessageFull>(msg: &T, config: base64::Config) -> anyhow::Result<String> {
|
fn encode_msg<T: MessageFull>(msg: &T, engine: impl base64::Engine) -> anyhow::Result<String> {
|
||||||
let bytes = msg.write_to_bytes()?;
|
let bytes = msg.write_to_bytes()?;
|
||||||
let b64 = base64::encode_config(bytes, config);
|
let b64 = engine.encode(bytes);
|
||||||
Ok(b64)
|
Ok(b64)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,12 +144,13 @@ mod tests {
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use base64::{engine::general_purpose::STANDARD, Engine};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_poll_response() {
|
fn test_parse_poll_response() {
|
||||||
let sample = b"GuUDZXlBaWRIbHdJam9nSWtwWFZDSXNJQ0poYkdjaU9pQWlSV1JFVTBFaUlIMC5leUFpYVhOeklqb2dJbk4wWldGdElpd2dJbk4xWWlJNklDSTNOalUyTVRFNU9URTFOVGN3TmpnNU1pSXNJQ0poZFdRaU9pQmJJQ0ozWldJaUxDQWljbVZ1WlhjaUxDQWlaR1Z5YVhabElpQmRMQ0FpWlhod0lqb2dNVGN3TlRBeE1UazFOU3dnSW01aVppSTZJREUyTnpnME5qUTRNemNzSUNKcFlYUWlPaUF4TmpnM01UQTBPRE0zTENBaWFuUnBJam9nSWpFNFF6VmZNakpDTTBZME16RmZRMFJHTmtFaUxDQWliMkYwSWpvZ01UWTROekV3TkRnek55d2dJbkJsY2lJNklERXNJQ0pwY0Y5emRXSnFaV04wSWpvZ0lqWTVMakV5TUM0eE16WXVNVEkwSWl3Z0ltbHdYMk52Ym1acGNtMWxjaUk2SUNJMk9TNHhNakF1TVRNMkxqRXlOQ0lnZlEuR3A1VFBqOXBHUWJ4SXpXREROQ1NQOU9rS1lTZXduV0JFOEUtY1ZxalFxcVQ1M0FzRTRya213OER5TThoVXJ4T0VQQ1dDWHdyYkRVcmgxOTlSempQRHci/gNleUFpZEhsd0lqb2dJa3BYVkNJc0lDSmhiR2NpT2lBaVJXUkVVMEVpSUgwLmV5QWlhWE56SWpvZ0luSTZNVGhETlY4eU1rSXpSalF6TVY5RFJFWTJRU0lzSUNKemRXSWlPaUFpTnpZMU5qRXhPVGt4TlRVM01EWTRPVElpTENBaVlYVmtJam9nV3lBaWQyVmlJaUJkTENBaVpYaHdJam9nTVRZNE56RTVNamM0T0N3Z0ltNWlaaUk2SURFMk56ZzBOalE0TXpjc0lDSnBZWFFpT2lBeE5qZzNNVEEwT0RNM0xDQWlhblJwSWpvZ0lqRXlSREZmTWpKQ00wVTROekZmT1RaRk5EQWlMQ0FpYjJGMElqb2dNVFk0TnpFd05EZ3pOeXdnSW5KMFgyVjRjQ0k2SURFM01EVXdNVEU1TlRVc0lDSndaWElpT2lBd0xDQWlhWEJmYzNWaWFtVmpkQ0k2SUNJMk9TNHhNakF1TVRNMkxqRXlOQ0lzSUNKcGNGOWpiMjVtYVhKdFpYSWlPaUFpTmprdU1USXdMakV6Tmk0eE1qUWlJSDAuMVNnUEotSVZuWEp6Nk9nSW1udUdOQ0hMbEJTcGdvc0Z0UkxoOV9iVVBHQ1RaMmFtRWY2ZTZVYkJzVWZ3bnlYbEdFdG5LSHhPemhibTdLNzBwVFhEQ0EoADIKaHlkcmFzdGFyMg==";
|
let sample = b"GuUDZXlBaWRIbHdJam9nSWtwWFZDSXNJQ0poYkdjaU9pQWlSV1JFVTBFaUlIMC5leUFpYVhOeklqb2dJbk4wWldGdElpd2dJbk4xWWlJNklDSTNOalUyTVRFNU9URTFOVGN3TmpnNU1pSXNJQ0poZFdRaU9pQmJJQ0ozWldJaUxDQWljbVZ1WlhjaUxDQWlaR1Z5YVhabElpQmRMQ0FpWlhod0lqb2dNVGN3TlRBeE1UazFOU3dnSW01aVppSTZJREUyTnpnME5qUTRNemNzSUNKcFlYUWlPaUF4TmpnM01UQTBPRE0zTENBaWFuUnBJam9nSWpFNFF6VmZNakpDTTBZME16RmZRMFJHTmtFaUxDQWliMkYwSWpvZ01UWTROekV3TkRnek55d2dJbkJsY2lJNklERXNJQ0pwY0Y5emRXSnFaV04wSWpvZ0lqWTVMakV5TUM0eE16WXVNVEkwSWl3Z0ltbHdYMk52Ym1acGNtMWxjaUk2SUNJMk9TNHhNakF1TVRNMkxqRXlOQ0lnZlEuR3A1VFBqOXBHUWJ4SXpXREROQ1NQOU9rS1lTZXduV0JFOEUtY1ZxalFxcVQ1M0FzRTRya213OER5TThoVXJ4T0VQQ1dDWHdyYkRVcmgxOTlSempQRHci/gNleUFpZEhsd0lqb2dJa3BYVkNJc0lDSmhiR2NpT2lBaVJXUkVVMEVpSUgwLmV5QWlhWE56SWpvZ0luSTZNVGhETlY4eU1rSXpSalF6TVY5RFJFWTJRU0lzSUNKemRXSWlPaUFpTnpZMU5qRXhPVGt4TlRVM01EWTRPVElpTENBaVlYVmtJam9nV3lBaWQyVmlJaUJkTENBaVpYaHdJam9nTVRZNE56RTVNamM0T0N3Z0ltNWlaaUk2SURFMk56ZzBOalE0TXpjc0lDSnBZWFFpT2lBeE5qZzNNVEEwT0RNM0xDQWlhblJwSWpvZ0lqRXlSREZmTWpKQ00wVTROekZmT1RaRk5EQWlMQ0FpYjJGMElqb2dNVFk0TnpFd05EZ3pOeXdnSW5KMFgyVjRjQ0k2SURFM01EVXdNVEU1TlRVc0lDSndaWElpT2lBd0xDQWlhWEJmYzNWaWFtVmpkQ0k2SUNJMk9TNHhNakF1TVRNMkxqRXlOQ0lzSUNKcGNGOWpiMjVtYVhKdFpYSWlPaUFpTmprdU1USXdMakV6Tmk0eE1qUWlJSDAuMVNnUEotSVZuWEp6Nk9nSW1udUdOQ0hMbEJTcGdvc0Z0UkxoOV9iVVBHQ1RaMmFtRWY2ZTZVYkJzVWZ3bnlYbEdFdG5LSHhPemhibTdLNzBwVFhEQ0EoADIKaHlkcmFzdGFyMg==";
|
||||||
|
|
||||||
let bytes = base64::decode_config(sample, base64::STANDARD).unwrap();
|
let bytes = STANDARD.decode(sample).unwrap();
|
||||||
|
|
||||||
let resp: CAuthentication_PollAuthSessionStatus_Response = decode_msg(&bytes).unwrap();
|
let resp: CAuthentication_PollAuthSessionStatus_Response = decode_msg(&bytes).unwrap();
|
||||||
|
|
||||||
|
@ -154,7 +161,7 @@ mod tests {
|
||||||
fn parse_get_public_rsa_response() {
|
fn parse_get_public_rsa_response() {
|
||||||
let sample = b"CoAEYjYyMGI1ZWNhMWIxMjgyYjkxYzZkZmZkYWFhOWI0ODI0YjlhNmRiYmEyZDVmYjc0ODcxNDczZDc1MDYxNGEzNWM4ODQ3NDYzZTEyNjAwNTJmNzZlNTYxMDM5ODdlN2U3NGJkMWZjZGRjYWJhMDVmZGM5OTBjMWIyNmQ2ZDg5MGM2MTEzZmRkNTZmMmQ1YmZjNzU4ODhlMzZhNTM2NjM3N2IzZTE3ZTJiZWM5MjhlNGY4MmE1YzY0NGYxZTZlMTk3NzZkNjIzMDIxYjhmYTA0MGRjNWE5YjY0M2I0N2I5YmVhMjM2YmEyZjM4ODVjM2ZlNWVhNjMzZThlNjJjNGE1YTY4NjNmMzNiMzdlMTQ4M2MwZTUzZTg4ODIzMGFkNTVjNzg5ZmU4Y2NkMjVjNzdiMTkxOTg0ZThjN2JmNWYzNzY2MjI0OGI1NWVmOWM1OGY3NDM5YjA4ZjNhNWJiNzljNTc5ZDE5M2I3NzhmMzFiY2IwYTA3MmVhZWYxOGEyYjljZDY2M2VmYmY2YmRiZDU3MGEyMTNiOTIxNTc4ODk0MjJkMDY3ODFiNTVkY2VjYjQ4NjA4MjUyMmUzZWQyOWM4MjExYzQ5N2Q1YjNhYTk2OGM2MDY1YWFhZTNhNGVmYzZiMGJjNDYyMzMxNmVmYTUxN2JjNzRiZDYzODcxMWU4ZWYSBjAxMDAwMRiQn6Ly3wk=";
|
let sample = b"CoAEYjYyMGI1ZWNhMWIxMjgyYjkxYzZkZmZkYWFhOWI0ODI0YjlhNmRiYmEyZDVmYjc0ODcxNDczZDc1MDYxNGEzNWM4ODQ3NDYzZTEyNjAwNTJmNzZlNTYxMDM5ODdlN2U3NGJkMWZjZGRjYWJhMDVmZGM5OTBjMWIyNmQ2ZDg5MGM2MTEzZmRkNTZmMmQ1YmZjNzU4ODhlMzZhNTM2NjM3N2IzZTE3ZTJiZWM5MjhlNGY4MmE1YzY0NGYxZTZlMTk3NzZkNjIzMDIxYjhmYTA0MGRjNWE5YjY0M2I0N2I5YmVhMjM2YmEyZjM4ODVjM2ZlNWVhNjMzZThlNjJjNGE1YTY4NjNmMzNiMzdlMTQ4M2MwZTUzZTg4ODIzMGFkNTVjNzg5ZmU4Y2NkMjVjNzdiMTkxOTg0ZThjN2JmNWYzNzY2MjI0OGI1NWVmOWM1OGY3NDM5YjA4ZjNhNWJiNzljNTc5ZDE5M2I3NzhmMzFiY2IwYTA3MmVhZWYxOGEyYjljZDY2M2VmYmY2YmRiZDU3MGEyMTNiOTIxNTc4ODk0MjJkMDY3ODFiNTVkY2VjYjQ4NjA4MjUyMmUzZWQyOWM4MjExYzQ5N2Q1YjNhYTk2OGM2MDY1YWFhZTNhNGVmYzZiMGJjNDYyMzMxNmVmYTUxN2JjNzRiZDYzODcxMWU4ZWYSBjAxMDAwMRiQn6Ly3wk=";
|
||||||
|
|
||||||
let bytes = base64::decode_config(sample, base64::STANDARD).unwrap();
|
let bytes = STANDARD.decode(sample).unwrap();
|
||||||
|
|
||||||
let resp: CAuthentication_GetPasswordRSAPublicKey_Response = decode_msg(&bytes).unwrap();
|
let resp: CAuthentication_GetPasswordRSAPublicKey_Response = decode_msg(&bytes).unwrap();
|
||||||
|
|
||||||
|
@ -165,11 +172,11 @@ mod tests {
|
||||||
fn test_decode_encode_roundtrip() {
|
fn test_decode_encode_roundtrip() {
|
||||||
let sample = b"EgpoeWRyYXN0YXIyGtgCRUxaNTBXdHM2Z0kxWlZaVjl6bzRJNFBEcEhTMGRZR3RSNzJPbytqZkR5QmRBUitrbnBUcUVGcGF4NDd1UVdqdUQ1R2hpRC9JanA2cEtGQzlrdUZDdzBFT0RMSFpINERZUG5hci9IMktOZGoxSFNjWEhyemZjNmk1OWpsRE5OTTI0RVllNUEyUjVSdzBoa2lodU14Z1A4NDJESFUxMkgwNWFyYmdRUWp3NFJmVHh6cDBQQlRjdTk4VUViUjJnak1RajlVK3RsYStPdTN6WTQ5K1BKc0szTkpMTVdxWm4vaFZ1dTR3NFprZGhXNVBqNWphb2Flb3J6MG8zbWIvUXo2M0NlNFdwWmUra1lFYUlSa29oUXBaZkliaW4rTWdQcVpNelg4cW4vNDcyNFp5N05mblpETlVBV3RoTkowTkUxSDVESXZ4N0IwRFJHZVBwdk5FbVdqWEJ3PT0g4MCW2tYBOAFCBk1vYmlsZUocCgpHYWxheHkgUzIyEAMYjPz/////////ASCQBA==";
|
let sample = b"EgpoeWRyYXN0YXIyGtgCRUxaNTBXdHM2Z0kxWlZaVjl6bzRJNFBEcEhTMGRZR3RSNzJPbytqZkR5QmRBUitrbnBUcUVGcGF4NDd1UVdqdUQ1R2hpRC9JanA2cEtGQzlrdUZDdzBFT0RMSFpINERZUG5hci9IMktOZGoxSFNjWEhyemZjNmk1OWpsRE5OTTI0RVllNUEyUjVSdzBoa2lodU14Z1A4NDJESFUxMkgwNWFyYmdRUWp3NFJmVHh6cDBQQlRjdTk4VUViUjJnak1RajlVK3RsYStPdTN6WTQ5K1BKc0szTkpMTVdxWm4vaFZ1dTR3NFprZGhXNVBqNWphb2Flb3J6MG8zbWIvUXo2M0NlNFdwWmUra1lFYUlSa29oUXBaZkliaW4rTWdQcVpNelg4cW4vNDcyNFp5N05mblpETlVBV3RoTkowTkUxSDVESXZ4N0IwRFJHZVBwdk5FbVdqWEJ3PT0g4MCW2tYBOAFCBk1vYmlsZUocCgpHYWxheHkgUzIyEAMYjPz/////////ASCQBA==";
|
||||||
|
|
||||||
let bytes = base64::decode_config(sample, base64::STANDARD).unwrap();
|
let bytes = STANDARD.decode(sample).unwrap();
|
||||||
let decoded: CAuthentication_BeginAuthSessionViaCredentials_Request =
|
let decoded: CAuthentication_BeginAuthSessionViaCredentials_Request =
|
||||||
decode_msg(&bytes).expect("Failed to decode");
|
decode_msg(&bytes).expect("Failed to decode");
|
||||||
|
|
||||||
let encoded = encode_msg(&decoded, base64::STANDARD).expect("Failed to encode");
|
let encoded = encode_msg(&decoded, STANDARD).expect("Failed to encode");
|
||||||
|
|
||||||
assert_eq!(encoded, String::from_utf8(sample.to_vec()).unwrap());
|
assert_eq!(encoded, String::from_utf8(sample.to_vec()).unwrap());
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ use crate::steamapi::authentication::AuthenticationClient;
|
||||||
use crate::steamapi::EResult;
|
use crate::steamapi::EResult;
|
||||||
use crate::token::Tokens;
|
use crate::token::Tokens;
|
||||||
use crate::transport::Transport;
|
use crate::transport::Transport;
|
||||||
|
use base64::Engine;
|
||||||
use log::*;
|
use log::*;
|
||||||
use rsa::{Pkcs1v15Encrypt, RsaPublicKey};
|
use rsa::{Pkcs1v15Encrypt, RsaPublicKey};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
@ -275,7 +276,7 @@ fn encrypt_password(
|
||||||
let mut rng = tests::MockStepRng(rand::rngs::mock::StepRng::new(2, 1));
|
let mut rng = tests::MockStepRng(rand::rngs::mock::StepRng::new(2, 1));
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
let mut rng = rand::rngs::OsRng;
|
let mut rng = rand::rngs::OsRng;
|
||||||
base64::encode(
|
base64::engine::general_purpose::STANDARD.encode(
|
||||||
public_key
|
public_key
|
||||||
.encrypt(&mut rng, Pkcs1v15Encrypt, password.as_ref())
|
.encrypt(&mut rng, Pkcs1v15Encrypt, password.as_ref())
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
|
|
Loading…
Reference in a new issue