steam_vent_crypto/
lib.rs

1use aes::cipher::generic_array::GenericArray;
2use aes::cipher::{BlockDecrypt, BlockEncrypt, KeyInit, KeyIvInit};
3use aes::Aes256;
4use bytes::BytesMut;
5use cbc::cipher::block_padding::Pkcs7;
6use cbc::cipher::{BlockDecryptMut, BlockEncryptMut};
7use hmac::{Hmac, Mac};
8use once_cell::sync::Lazy;
9use rand::{random, Rng};
10use rsa::{BigUint, Oaep, Pkcs1v15Encrypt, Pss, RsaPublicKey};
11use sha1::Sha1;
12use std::convert::TryInto;
13use thiserror::Error;
14
15#[derive(Debug, Error)]
16pub enum CryptError {
17    #[error("Malformed signature: {0}")]
18    MalformedSignature(#[from] RsaError),
19    #[error("Malformed message")]
20    MalformedMessage,
21    #[error("Invalid HMAC")]
22    InvalidHmac,
23}
24
25pub type Result<T> = std::result::Result<T, CryptError>;
26
27#[derive(Debug, Error)]
28#[error("{0}")]
29pub struct RsaError(rsa::errors::Error);
30
31mod system_key {
32    include!(concat!(env!("OUT_DIR"), "/system_key.rs"));
33}
34
35static SYSTEM_PUBLIC_KEY: Lazy<RsaPublicKey> = Lazy::new(|| {
36    RsaPublicKey::new(
37        BigUint::from_bytes_le(system_key::N),
38        BigUint::from_bytes_le(system_key::E),
39    )
40    .expect("Failed to parse public key")
41});
42
43/// Verify sha1 signature using the steam "system" public key
44pub fn verify_signature(data: &[u8], signature: &[u8]) -> Result<bool> {
45    match SYSTEM_PUBLIC_KEY.verify(Pss::new::<Sha1>(), data, signature) {
46        Ok(_) => Ok(true),
47        Err(rsa::errors::Error::Verification) => Ok(false),
48        Err(err) => Err(CryptError::MalformedSignature(RsaError(err))),
49    }
50}
51
52pub struct SessionKeys {
53    pub plain: [u8; 32],
54    pub encrypted: Vec<u8>,
55}
56
57pub fn generate_session_key(nonce: Option<&[u8; 16]>) -> SessionKeys {
58    let mut rng = rand::thread_rng();
59    let plain: [u8; 32] = rng.gen();
60
61    let encrypted = match nonce {
62        Some(nonce) => {
63            let mut data = [0; 48];
64            data[0..32].copy_from_slice(&plain);
65            data[32..48].copy_from_slice(nonce);
66            encrypt_with_key(&SYSTEM_PUBLIC_KEY, &data)
67        }
68        None => encrypt_with_key(&SYSTEM_PUBLIC_KEY, &plain),
69    }
70    .expect("Invalid crypt setup");
71
72    SessionKeys { plain, encrypted }
73}
74
75pub fn encrypt_with_key(key: &RsaPublicKey, data: &[u8]) -> Result<Vec<u8>> {
76    let mut rng = rand::thread_rng();
77    Ok(key
78        .encrypt(&mut rng, Oaep::new::<Sha1>(), data)
79        .map_err(RsaError)?)
80}
81
82pub fn encrypt_with_key_pkcs1(key: &RsaPublicKey, data: &[u8]) -> Result<Vec<u8>> {
83    let mut rng = rand::thread_rng();
84    Ok(key
85        .encrypt(&mut rng, Pkcs1v15Encrypt, data)
86        .map_err(RsaError)?)
87}
88
89#[test]
90fn test_gen_session_key() {
91    assert!(!generate_session_key(None).encrypted.is_empty());
92    assert!(!generate_session_key(Some(&[
93        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
94    ]))
95    .encrypted
96    .is_empty(),);
97}
98
99/// Decrypt an Initialization Vector with AES 256 ECB.
100fn encrypt_iv(iv: [u8; 16], key: &[u8; 32]) -> [u8; 16] {
101    let iv_crypter = Aes256::new(GenericArray::from_slice(key));
102    let mut iv_block = GenericArray::from(iv);
103    iv_crypter.encrypt_block(&mut iv_block);
104    iv_block.into()
105}
106
107/// Encrypt an Initialization Vector with AES 256 ECB.
108fn decrypt_iv(iv: [u8; 16], key: &[u8; 32]) -> [u8; 16] {
109    let iv_crypter = Aes256::new(GenericArray::from_slice(key));
110    let mut iv_block = GenericArray::from(iv);
111    iv_crypter.decrypt_block(&mut iv_block);
112    iv_block.into()
113}
114
115#[test]
116fn test_iv_encryption_round_trip() {
117    let iv = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
118    let key = [
119        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
120        12, 13, 14, 15, 16,
121    ];
122    let encrypted = encrypt_iv(iv, &key);
123    assert_eq!(iv, decrypt_iv(encrypted, &key));
124}
125
126type Aes256CbcEnc = cbc::Encryptor<Aes256>;
127type Aes256CbcDec = cbc::Decryptor<Aes256>;
128
129fn encrypt_message(mut message: BytesMut, key: &[u8; 32], plain_iv: &[u8; 16]) -> BytesMut {
130    let cipher = <Aes256CbcEnc as KeyIvInit>::new(
131        GenericArray::from_slice(key),
132        GenericArray::from_slice(plain_iv),
133    );
134    let length = message.len();
135    message.resize(length + 16, 0);
136    let len = cipher
137        .encrypt_padded_mut::<Pkcs7>(&mut message, length)
138        .expect("not enough padding")
139        .len();
140
141    message.truncate(len);
142    message
143}
144
145fn decrypt_message(mut message: BytesMut, key: &[u8; 32], plain_iv: &[u8; 16]) -> Result<BytesMut> {
146    let cipher = Aes256CbcDec::new(
147        GenericArray::from_slice(key),
148        GenericArray::from_slice(plain_iv),
149    );
150    let len = cipher
151        .decrypt_padded_mut::<Pkcs7>(message.as_mut())
152        .map_err(|_| CryptError::MalformedMessage)?
153        .len();
154    message.truncate(len);
155    Ok(message)
156}
157
158#[test]
159fn test_encryption_round_trip() {
160    let iv = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
161    let key = [
162        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
163        12, 13, 14, 15, 16,
164    ];
165    let msg = "some test message to encrypt";
166    let plain = BytesMut::from(msg);
167    let encrypted = encrypt_message(plain.clone(), &key, &iv);
168    assert_eq!(plain, decrypt_message(encrypted, &key, &iv).unwrap());
169}
170
171fn symmetric_encrypt_with_iv(
172    mut iv_buff: BytesMut,
173    message: BytesMut,
174    key: &[u8; 32],
175    plain_iv: [u8; 16],
176) -> BytesMut {
177    let encrypted_iv = encrypt_iv(plain_iv, key);
178    iv_buff[0..16].copy_from_slice(&encrypted_iv);
179    let encrypted_message = encrypt_message(message, key, &plain_iv);
180
181    iv_buff.unsplit(encrypted_message);
182    iv_buff
183}
184
185type HmacSha1 = Hmac<Sha1>;
186
187/// Generate a random IV and encrypt `input` with it and `key` with a buffer for storing the iv.
188///
189/// The `iv_buff` has to be 16 bytes large should come from a split slice in front of the input buffer
190pub fn symmetric_encrypt_with_iv_buffer(
191    iv_buff: BytesMut,
192    input: BytesMut,
193    key: &[u8; 32],
194) -> BytesMut {
195    let hmac_random: [u8; 3] = random();
196
197    let mut hmac_key = [0; 64];
198    hmac_key[0..16].copy_from_slice(&key[0..16]);
199
200    let mut hmac = <HmacSha1 as Mac>::new(GenericArray::from_slice(&hmac_key));
201    hmac.update(&hmac_random);
202    hmac.update(&input);
203
204    let hmac: [u8; 20] = hmac.finalize().into_bytes().into();
205
206    let mut iv = [0; 16];
207    iv[0..13].copy_from_slice(&hmac[0..13]);
208    iv[13..].copy_from_slice(&hmac_random);
209
210    symmetric_encrypt_with_iv(iv_buff, input, key, iv)
211}
212
213/// Generate a random IV and encrypt `input` with it and `key`.
214pub fn symmetric_encrypt(input: BytesMut, key: &[u8; 32]) -> BytesMut {
215    symmetric_encrypt_with_iv_buffer(BytesMut::from(&[0; 16][..]), input, key)
216}
217
218fn symmetric_decrypt_impl(mut input: BytesMut, key: &[u8; 32]) -> Result<([u8; 16], BytesMut)> {
219    let message = input.split_off(16);
220    let encrypted_iv = input.as_ref().try_into().unwrap();
221    let plain_iv = decrypt_iv(encrypted_iv, key);
222
223    let message = decrypt_message(message, key, &plain_iv)?;
224
225    Ok((plain_iv, message))
226}
227
228/// Decrypt the IV stored in the first 16 bytes of `input`
229/// and use it to decrypt the remaining bytes, skipping HMAC validation.
230pub fn symmetric_decrypt_without_hmac(input: BytesMut, key: &[u8; 32]) -> Result<BytesMut> {
231    let (_, message) = symmetric_decrypt_impl(input, key)?;
232    Ok(message)
233}
234
235/// Decrypt the IV stored in the first 16 bytes of `input`
236/// and use it to decrypt the remaining bytes.
237pub fn symmetric_decrypt(input: BytesMut, key: &[u8; 32]) -> Result<BytesMut> {
238    let (plain_iv, message) = symmetric_decrypt_impl(input, key)?;
239    // let padding = *message.last().unwrap();
240    // message.resize(message.len() - padding as usize, 0);
241
242    let hmac_random = &plain_iv[13..];
243
244    let mut hmac_key = [0; 64];
245    hmac_key[0..16].copy_from_slice(&key[0..16]);
246
247    let mut hmac = <HmacSha1 as Mac>::new(GenericArray::from_slice(&hmac_key));
248    hmac.update(hmac_random);
249    hmac.update(&message);
250
251    let hmac: [u8; 20] = hmac.finalize().into_bytes().into();
252
253    if hmac[0..13] != plain_iv[0..13] {
254        return Err(CryptError::InvalidHmac);
255    }
256    Ok(message)
257}
258
259#[test]
260fn roundtrip_test() {
261    let key = random();
262
263    let input = BytesMut::from(&[55; 16][..]);
264
265    let encrypted = symmetric_encrypt(input.clone(), &key);
266
267    let decrypted = symmetric_decrypt(encrypted, &key).unwrap();
268
269    assert_eq!(input, decrypted);
270}