Skip to content

Commit

Permalink
refactor: crypto mod structure
Browse files Browse the repository at this point in the history
  • Loading branch information
pk5ls20 committed Feb 20, 2025
1 parent 9b5bb8d commit bb93072
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 117 deletions.
2 changes: 1 addition & 1 deletion mania/src/core/context.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::ClientConfig;
use crate::core::crypto::consts::ECDH_256_PEER_LOGIN_KEY;
use crate::core::crypto::{Ecdh, P256};
use crate::core::crypto::ecdh::{Ecdh, P256};
use crate::core::key_store::KeyStore;
use crate::core::session::Session;
use crate::core::sign::SignProvider;
Expand Down
116 changes: 1 addition & 115 deletions mania/src/core/crypto.rs
Original file line number Diff line number Diff line change
@@ -1,118 +1,4 @@
use md5::{Digest, Md5};
use p256::{EncodedPoint, PublicKey, ecdh::EphemeralSecret};

pub mod consts;
pub mod ecdh;
pub mod stream_sha1;
pub mod tea;

/// The original macro that @wybxc originally wrote (b81f75b7) was perfect.
/// but since that mania has dropped OpenSSL, it seems that this kind of abstraction is no longer needed.
/// If there's ever a need in the future, we'll revisit it.
pub trait Ecdh {
fn new(server_public_key: [u8; 65]) -> Self;
fn public_key(&self) -> &[u8];
fn shared_key(&self) -> &[u8];
fn key_exchange<C>(
c_pri_key: elliptic_curve::ecdh::EphemeralSecret<C>,
s_pub_key: elliptic_curve::PublicKey<C>,
) -> Result<[u8; 16], String>
where
C: elliptic_curve::CurveArithmetic,
{
let share = c_pri_key.diffie_hellman(&s_pub_key);
let share_slice: [u8; 16] = share.raw_secret_bytes()[0..16]
.try_into()
.map_err(|_| "Failed to convert shared secret to a fixed-size array".to_string())?;
let result = Md5::digest(share_slice);
let mut shared_key = [0; 16];
shared_key.copy_from_slice(&result);
Ok(shared_key)
}
fn tea_encrypt(&self, data: &[u8]) -> Vec<u8> {
tea::tea_encrypt(data, self.shared_key())
}
fn tea_decrypt(&self, data: &[u8]) -> Vec<u8> {
tea::tea_decrypt(data, self.shared_key())
}
}

pub struct P256 {
public: Vec<u8>,
shared: [u8; 16],
}

impl Ecdh for P256 {
fn new(server_public_key: [u8; 65]) -> Self {
let s_pub_key =
PublicKey::from_sec1_bytes(&server_public_key).expect("Failed to parse public key");
let c_pri_key = EphemeralSecret::random(&mut rand::thread_rng());
let c_pub_key = c_pri_key.public_key();
let share_key = Self::key_exchange(c_pri_key, s_pub_key)
.expect("Failed to generate shared key from key exchange");
Self {
public: EncodedPoint::from(c_pub_key).as_bytes().to_vec(),
shared: share_key,
}
}

fn public_key(&self) -> &[u8] {
&self.public
}

fn shared_key(&self) -> &[u8] {
&self.shared
}
}

#[cfg(test)]
mod test {
use super::*;
use rand::thread_rng;
#[test]
fn test_ecdh_p256() {
let mut rng = thread_rng();
let server_secret = EphemeralSecret::random(&mut rng);
let server_public = server_secret.public_key();
let client_secret = EphemeralSecret::random(&mut rng);
let client_public = client_secret.public_key();
let server_pubkey = PublicKey::from_sec1_bytes(&server_public.to_sec1_bytes())
.expect("failed to parse server public key");
let client_pubkey = PublicKey::from_sec1_bytes(&client_public.to_sec1_bytes())
.expect("failed to parse client public key");
let server_shared = P256::key_exchange(server_secret, client_pubkey);
let client_shared = P256::key_exchange(client_secret, server_pubkey);
assert_eq!(server_shared, client_shared);

let client_message = b"https://music.163.com/song?id=1496089150";
let ciphertext_from_client =
tea::tea_encrypt(client_message, &client_shared.clone().unwrap());
let decrypted_by_server =
tea::tea_decrypt(&ciphertext_from_client, &server_shared.clone().unwrap());
assert_eq!(client_message.to_vec(), decrypted_by_server);
let server_message = b"https://music.163.com/song?id=1921741824";
let ciphertext_from_server =
tea::tea_encrypt(server_message, &server_shared.clone().unwrap());
let decrypted_by_client =
tea::tea_decrypt(&ciphertext_from_server, &client_shared.unwrap());
assert_eq!(server_message.to_vec(), decrypted_by_client);

println!(
"Client message: {:?}",
String::from_utf8_lossy(client_message)
);
println!("Ciphertext from client: {:?}", ciphertext_from_client);
println!(
"Decrypted by server: {:?}",
String::from_utf8_lossy(&decrypted_by_server)
);
println!(
"Server message: {:?}",
String::from_utf8_lossy(server_message)
);
println!("Ciphertext from server: {:?}", ciphertext_from_server);
println!(
"Decrypted by client: {:?}",
String::from_utf8_lossy(&decrypted_by_client)
);
}
}
117 changes: 117 additions & 0 deletions mania/src/core/crypto/ecdh.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
use crate::core::crypto::tea;
use digest::Digest;
use md5::Md5;
use p256::ecdh::EphemeralSecret;
use p256::{EncodedPoint, PublicKey};

/// The original macro that @wybxc originally wrote (b81f75b7) was perfect.
/// but since that mania has dropped OpenSSL, it seems that this kind of abstraction is no longer needed.
/// If there's ever a need in the future, we'll revisit it.
pub trait Ecdh {
fn new(server_public_key: [u8; 65]) -> Self;
fn public_key(&self) -> &[u8];
fn shared_key(&self) -> &[u8];
fn key_exchange<C>(
c_pri_key: elliptic_curve::ecdh::EphemeralSecret<C>,
s_pub_key: elliptic_curve::PublicKey<C>,
) -> Result<[u8; 16], String>
where
C: elliptic_curve::CurveArithmetic,
{
let share = c_pri_key.diffie_hellman(&s_pub_key);
let share_slice: [u8; 16] = share.raw_secret_bytes()[0..16]
.try_into()
.map_err(|_| "Failed to convert shared secret to a fixed-size array".to_string())?;
let result = Md5::digest(share_slice);
let mut shared_key = [0; 16];
shared_key.copy_from_slice(&result);
Ok(shared_key)
}
fn tea_encrypt(&self, data: &[u8]) -> Vec<u8> {
tea::tea_encrypt(data, self.shared_key())
}
fn tea_decrypt(&self, data: &[u8]) -> Vec<u8> {
tea::tea_decrypt(data, self.shared_key())
}
}

pub struct P256 {
public: Vec<u8>,
shared: [u8; 16],
}

impl Ecdh for P256 {
fn new(server_public_key: [u8; 65]) -> Self {
let s_pub_key =
PublicKey::from_sec1_bytes(&server_public_key).expect("Failed to parse public key");
let c_pri_key = EphemeralSecret::random(&mut rand::thread_rng());
let c_pub_key = c_pri_key.public_key();
let share_key = Self::key_exchange(c_pri_key, s_pub_key)
.expect("Failed to generate shared key from key exchange");
Self {
public: EncodedPoint::from(c_pub_key).as_bytes().to_vec(),
shared: share_key,
}
}

fn public_key(&self) -> &[u8] {
&self.public
}

fn shared_key(&self) -> &[u8] {
&self.shared
}
}

#[cfg(test)]
mod test {
use super::*;
use rand::thread_rng;
#[test]
fn test_ecdh_p256() {
let mut rng = thread_rng();
let server_secret = EphemeralSecret::random(&mut rng);
let server_public = server_secret.public_key();
let client_secret = EphemeralSecret::random(&mut rng);
let client_public = client_secret.public_key();
let server_pubkey = PublicKey::from_sec1_bytes(&server_public.to_sec1_bytes())
.expect("failed to parse server public key");
let client_pubkey = PublicKey::from_sec1_bytes(&client_public.to_sec1_bytes())
.expect("failed to parse client public key");
let server_shared = P256::key_exchange(server_secret, client_pubkey);
let client_shared = P256::key_exchange(client_secret, server_pubkey);
assert_eq!(server_shared, client_shared);

let client_message = b"https://music.163.com/song?id=1496089150";
let ciphertext_from_client =
tea::tea_encrypt(client_message, &client_shared.clone().unwrap());
let decrypted_by_server =
tea::tea_decrypt(&ciphertext_from_client, &server_shared.clone().unwrap());
assert_eq!(client_message.to_vec(), decrypted_by_server);
let server_message = b"https://music.163.com/song?id=1921741824";
let ciphertext_from_server =
tea::tea_encrypt(server_message, &server_shared.clone().unwrap());
let decrypted_by_client =
tea::tea_decrypt(&ciphertext_from_server, &client_shared.unwrap());
assert_eq!(server_message.to_vec(), decrypted_by_client);

println!(
"Client message: {:?}",
String::from_utf8_lossy(client_message)
);
println!("Ciphertext from client: {:?}", ciphertext_from_client);
println!(
"Decrypted by server: {:?}",
String::from_utf8_lossy(&decrypted_by_server)
);
println!(
"Server message: {:?}",
String::from_utf8_lossy(server_message)
);
println!("Ciphertext from server: {:?}", ciphertext_from_server);
println!(
"Decrypted by client: {:?}",
String::from_utf8_lossy(&decrypted_by_client)
);
}
}
2 changes: 1 addition & 1 deletion mania/src/core/event/login/trans_emp.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::core::crypto::Ecdh;
use crate::core::crypto::ecdh::Ecdh;
use crate::core::event::prelude::*;
use crate::core::tlv::*;
use chrono::Utc;
Expand Down

0 comments on commit bb93072

Please sign in to comment.