1use rand::RngCore;
8use rsa::{Oaep, RsaPublicKey};
9use sha1::Sha1;
10
11use crate::{error::CryptoError, session_key::SessionKey};
12
13const STEAM_PUBLIC_KEY_MODULUS: &[u8] = &[
16 0xDF, 0xEC, 0x1A, 0xD6, 0x2C, 0x10, 0x66, 0x2C, 0x17, 0x35, 0x3A, 0x14, 0xB0, 0x7C, 0x59, 0x11, 0x7F, 0x9D, 0xD3, 0xD8, 0x2B, 0x7A, 0xE3, 0xE0, 0x15, 0xCD, 0x19, 0x1E, 0x46, 0xE8, 0x7B, 0x87, 0x74, 0xA2, 0x18, 0x46, 0x31, 0xA9, 0x03, 0x14, 0x79, 0x82, 0x1F, 0x11, 0x13, 0xF4, 0xC0, 0xCE, 0x63, 0x1F, 0x73, 0x53, 0xD0, 0x5C, 0x82, 0xD5, 0x14, 0x9C, 0x1E, 0xB8, 0x67, 0xE9, 0x5B, 0xF7, 0x0F, 0xD5, 0x51, 0x40, 0x11, 0x4E, 0xF9, 0x75, 0x6D, 0x29, 0x00, 0x10, 0xB4, 0xF6, 0x0E, 0x7F, 0x79, 0xE5, 0x67, 0xE7, 0x62, 0x25, 0x9E, 0xC7, 0x3B, 0xAB, 0x19, 0x7C, 0xD2, 0xF9, 0x18, 0x51, 0xBF, 0x68, 0x6E,
17 0xA5, 0x30, 0x6B, 0x00, 0x63, 0x1A, 0x5A, 0x1E, 0x1C, 0x11, 0x75, 0xC4, 0x15, 0xD9, 0x3C, 0xE0, 0xF5, 0x97, 0xF6, 0xE6, 0x08, 0x27, 0xFE, 0xA6, 0xF4, 0x08, 0x8C, 0xD8, 0x59,
18];
19
20const STEAM_PUBLIC_KEY_EXPONENT: u32 = 0x11; pub struct SessionKeyPair {
24 pub plain: SessionKey,
26 pub encrypted: Vec<u8>,
28}
29
30pub fn generate_session_key(nonce: &[u8; 16]) -> Result<SessionKeyPair, CryptoError> {
44 let mut key_bytes = [0u8; 32];
46 rand::rng().fill_bytes(&mut key_bytes);
47
48 for i in 0..16 {
50 key_bytes[i] ^= nonce[i];
51 }
52
53 let n = rsa::BigUint::from_bytes_be(STEAM_PUBLIC_KEY_MODULUS);
55 let e = rsa::BigUint::from(STEAM_PUBLIC_KEY_EXPONENT);
56 let public_key = RsaPublicKey::new(n, e).map_err(|e| CryptoError::EncryptionFailed(format!("Invalid RSA key: {}", e)))?;
57
58 let padding = Oaep::new::<Sha1>();
60
61 struct RandCore6Wrapper;
63 impl rsa::rand_core::RngCore for RandCore6Wrapper {
64 fn next_u32(&mut self) -> u32 {
65 rand::random()
66 }
67 fn next_u64(&mut self) -> u64 {
68 rand::random()
69 }
70 fn fill_bytes(&mut self, dest: &mut [u8]) {
71 rand::rng().fill_bytes(dest)
72 }
73 fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rsa::rand_core::Error> {
74 rand::rng().fill_bytes(dest);
75 Ok(())
76 }
77 }
78 impl rsa::rand_core::CryptoRng for RandCore6Wrapper {}
79
80 let mut rng = RandCore6Wrapper;
81 let encrypted = public_key.encrypt(&mut rng, padding, &key_bytes).map_err(|e| CryptoError::EncryptionFailed(format!("RSA encryption failed: {}", e)))?;
82
83 let plain = SessionKey::from_bytes(&key_bytes).ok_or_else(|| CryptoError::EncryptionFailed("Invalid session key length".into()))?;
86
87 Ok(SessionKeyPair { plain, encrypted })
88}
89
90pub fn calculate_key_crc(encrypted_key: &[u8]) -> u32 {
94 crc32fast::hash(encrypted_key)
95}
96
97#[cfg(test)]
98mod tests {
99 use super::*;
100
101 #[test]
102 fn test_generate_session_key() {
103 let nonce = [0u8; 16];
104 let result = generate_session_key(&nonce).unwrap();
105
106 assert_eq!(result.encrypted.len(), 128);
108
109 assert_eq!(result.plain.as_bytes().len(), 32);
111 }
112
113 #[test]
114 fn test_key_crc() {
115 let data = b"test data";
116 let crc = calculate_key_crc(data);
117 assert!(crc != 0);
118 }
119}