more progress on friends
This commit is contained in:
parent
1b802ff33f
commit
7918e54487
19 changed files with 320 additions and 205 deletions
|
|
@ -1,21 +1,26 @@
|
|||
use std::io::{Read, Write};
|
||||
use bytemuck::{bytes_of, Pod, Zeroable};
|
||||
use crate::rmc::structures::RmcSerialize;
|
||||
use bytemuck::{Pod, Zeroable, bytes_of};
|
||||
use chrono::{Datelike, NaiveDate, NaiveDateTime, NaiveTime, Timelike, Utc};
|
||||
use hmac::Hmac;
|
||||
use hmac::Mac;
|
||||
use md5::{Digest, Md5};
|
||||
use rc4::{Rc4, Rc4Core, StreamCipher};
|
||||
use rc4::KeyInit;
|
||||
use rc4::cipher::StreamCipherCoreWrapper;
|
||||
use rc4::consts::U16;
|
||||
use hmac::Mac;
|
||||
use rc4::KeyInit;
|
||||
use crate::rmc::structures::RmcSerialize;
|
||||
use rc4::{Rc4, Rc4Core, StreamCipher};
|
||||
use std::io::{Read, Write};
|
||||
|
||||
type Md5Hmac = Hmac<md5::Md5>;
|
||||
|
||||
pub fn derive_key(pid: u32, password: [u8; 16]) -> [u8; 16]{
|
||||
let iteration_count = 65000 + pid%1024;
|
||||
pub fn derive_key(pid: u32, password: &[u8]) -> [u8; 16] {
|
||||
let iteration_count = 65000 + pid % 1024 - 1;
|
||||
// we do one iteration out here to ensure the key is always 16 bytes
|
||||
|
||||
let mut key = password;
|
||||
let mut key: [u8; 16] = {
|
||||
let mut md5 = Md5::new();
|
||||
md5.update(password);
|
||||
md5.finalize().try_into().unwrap()
|
||||
};
|
||||
|
||||
for _ in 0..iteration_count {
|
||||
let mut md5 = Md5::new();
|
||||
|
|
@ -29,12 +34,12 @@ pub fn derive_key(pid: u32, password: [u8; 16]) -> [u8; 16]{
|
|||
#[repr(transparent)]
|
||||
pub struct KerberosDateTime(pub u64);
|
||||
|
||||
impl KerberosDateTime{
|
||||
pub fn new(second: u64, minute: u64, hour: u64, day: u64, month: u64, year:u64 ) -> Self {
|
||||
impl KerberosDateTime {
|
||||
pub fn new(second: u64, minute: u64, hour: u64, day: u64, month: u64, year: u64) -> Self {
|
||||
Self(second | (minute << 6) | (hour << 12) | (day << 17) | (month << 22) | (year << 26))
|
||||
}
|
||||
|
||||
pub fn now() -> Self{
|
||||
pub fn now() -> Self {
|
||||
let now = chrono::Utc::now();
|
||||
Self::new(
|
||||
now.second() as u64,
|
||||
|
|
@ -47,42 +52,53 @@ impl KerberosDateTime{
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_seconds(&self) -> u8{
|
||||
pub fn get_seconds(&self) -> u8 {
|
||||
(self.0 & 0b111111) as u8
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_minutes(&self) -> u8{
|
||||
pub fn get_minutes(&self) -> u8 {
|
||||
((self.0 >> 6) & 0b111111) as u8
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_hours(&self) -> u8{
|
||||
pub fn get_hours(&self) -> u8 {
|
||||
((self.0 >> 12) & 0b111111) as u8
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_days(&self) -> u8{
|
||||
pub fn get_days(&self) -> u8 {
|
||||
((self.0 >> 17) & 0b111111) as u8
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_month(&self) -> u8{
|
||||
pub fn get_month(&self) -> u8 {
|
||||
((self.0 >> 22) & 0b1111) as u8
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_year(&self) -> u64{
|
||||
pub fn get_year(&self) -> u64 {
|
||||
(self.0 >> 26) & 0xFFFFFFFF
|
||||
}
|
||||
|
||||
pub fn to_regular_time(&self) -> chrono::DateTime<Utc>{
|
||||
pub fn to_regular_time(&self) -> chrono::DateTime<Utc> {
|
||||
NaiveDateTime::new(
|
||||
NaiveDate::from_ymd_opt(self.get_year() as i32, self.get_month() as u32, self.get_days() as u32).unwrap(),
|
||||
NaiveTime::from_hms_opt(self.get_hours() as u32, self.get_minutes() as u32, self.get_seconds() as u32).unwrap()
|
||||
).and_utc()
|
||||
NaiveDate::from_ymd_opt(
|
||||
self.get_year() as i32,
|
||||
self.get_month() as u32,
|
||||
self.get_days() as u32,
|
||||
)
|
||||
.unwrap(),
|
||||
NaiveTime::from_hms_opt(
|
||||
self.get_hours() as u32,
|
||||
self.get_minutes() as u32,
|
||||
self.get_seconds() as u32,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
.and_utc()
|
||||
}
|
||||
}
|
||||
|
||||
impl RmcSerialize for KerberosDateTime{
|
||||
impl RmcSerialize for KerberosDateTime {
|
||||
fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> {
|
||||
Ok(self.0.serialize(writer)?)
|
||||
}
|
||||
|
|
@ -94,22 +110,22 @@ impl RmcSerialize for KerberosDateTime{
|
|||
|
||||
#[derive(Pod, Zeroable, Copy, Clone)]
|
||||
#[repr(C, packed)]
|
||||
pub struct TicketInternalData{
|
||||
pub struct TicketInternalData {
|
||||
pub issued_time: KerberosDateTime,
|
||||
pub pid: u32,
|
||||
pub session_key: [u8; 32],
|
||||
}
|
||||
|
||||
impl TicketInternalData{
|
||||
pub(crate) fn new(pid: u32) -> Self{
|
||||
Self{
|
||||
impl TicketInternalData {
|
||||
pub(crate) fn new(pid: u32) -> Self {
|
||||
Self {
|
||||
issued_time: KerberosDateTime::now(),
|
||||
pid,
|
||||
session_key: rand::random()
|
||||
session_key: rand::random(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn encrypt(&self, key: [u8; 16]) -> Box<[u8]>{
|
||||
pub(crate) fn encrypt(&self, key: [u8; 16]) -> Box<[u8]> {
|
||||
let mut data = bytes_of(self).to_vec();
|
||||
|
||||
let mut rc4: StreamCipherCoreWrapper<Rc4Core<U16>> = Rc4::new_from_slice(&key).unwrap();
|
||||
|
|
@ -117,11 +133,13 @@ impl TicketInternalData{
|
|||
|
||||
let mut hmac = <Md5Hmac as KeyInit>::new_from_slice(&key).unwrap();
|
||||
|
||||
hmac.write_all(&data[..]).expect("failed to write data to hmac");
|
||||
hmac.write_all(&data[..])
|
||||
.expect("failed to write data to hmac");
|
||||
|
||||
let hmac_result = &hmac.finalize().into_bytes()[..];
|
||||
|
||||
data.write_all(&hmac_result).expect("failed to write data to vec");
|
||||
data.write_all(&hmac_result)
|
||||
.expect("failed to write data to vec");
|
||||
|
||||
data.into_boxed_slice()
|
||||
}
|
||||
|
|
@ -129,41 +147,44 @@ impl TicketInternalData{
|
|||
|
||||
#[derive(Pod, Zeroable, Copy, Clone)]
|
||||
#[repr(C, packed)]
|
||||
pub struct Ticket{
|
||||
pub struct Ticket {
|
||||
pub session_key: [u8; 32],
|
||||
pub pid: u32,
|
||||
}
|
||||
|
||||
impl Ticket{
|
||||
pub fn encrypt(&self, key: [u8; 16], internal_data: &[u8]) -> Box<[u8]>{
|
||||
impl Ticket {
|
||||
pub fn encrypt(&self, key: [u8; 16], internal_data: &[u8]) -> Box<[u8]> {
|
||||
let mut data = bytes_of(self).to_vec();
|
||||
|
||||
internal_data.serialize(&mut data).expect("unable to write to vec");
|
||||
internal_data
|
||||
.serialize(&mut data)
|
||||
.expect("unable to write to vec");
|
||||
|
||||
let mut rc4: StreamCipherCoreWrapper<Rc4Core<U16>> = Rc4::new_from_slice(&key).unwrap();
|
||||
rc4.apply_keystream(&mut data);
|
||||
|
||||
let mut hmac = <Md5Hmac as KeyInit>::new_from_slice(&key).unwrap();
|
||||
|
||||
hmac.write_all(&data[..]).expect("failed to write data to hmac");
|
||||
hmac.write_all(&data[..])
|
||||
.expect("failed to write data to hmac");
|
||||
|
||||
let hmac_result = &hmac.finalize().into_bytes()[..];
|
||||
|
||||
data.write_all(&hmac_result).expect("failed to write data to vec");
|
||||
data.write_all(&hmac_result)
|
||||
.expect("failed to write data to vec");
|
||||
|
||||
data.into_boxed_slice()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod test{
|
||||
mod test {
|
||||
use crate::kerberos::KerberosDateTime;
|
||||
|
||||
#[test]
|
||||
fn kerberos_time_convert_test(){
|
||||
fn kerberos_time_convert_test() {
|
||||
let time = KerberosDateTime(135904948834);
|
||||
|
||||
println!("{}", time.to_regular_time().to_rfc2822());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,39 +1,38 @@
|
|||
use macros::RmcSerialize;
|
||||
|
||||
#[derive(RmcSerialize)]
|
||||
#[derive(Clone)]
|
||||
pub struct Account{
|
||||
#[derive(RmcSerialize, Clone)]
|
||||
pub struct Account {
|
||||
pub pid: u32,
|
||||
pub username: String,
|
||||
pub kerbros_password: [u8; 16],
|
||||
}
|
||||
|
||||
impl Account{
|
||||
pub fn new(pid: u32, username: &str, passwd: &str) -> Self{
|
||||
impl Account {
|
||||
pub fn new(pid: u32, username: &str, passwd: &str) -> Self {
|
||||
let passwd_data = passwd.as_bytes();
|
||||
|
||||
let mut passwd = [0u8; 16];
|
||||
|
||||
for (idx, byte) in passwd_data.iter().enumerate(){
|
||||
for (idx, byte) in passwd_data.iter().enumerate() {
|
||||
passwd[idx] = *byte;
|
||||
}
|
||||
|
||||
Self{
|
||||
Self {
|
||||
kerbros_password: passwd,
|
||||
username: username.into(),
|
||||
pid
|
||||
pid,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_raw_password(pid: u32, username: &str, passwd: [u8; 16]) -> Self{
|
||||
Self{
|
||||
pub fn new_raw_password(pid: u32, username: &str, passwd: [u8; 16]) -> Self {
|
||||
Self {
|
||||
kerbros_password: passwd,
|
||||
username: username.into(),
|
||||
pid
|
||||
pid,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_login_data(&self) -> (u32, [u8; 16]){
|
||||
(self.pid, self.kerbros_password)
|
||||
pub fn get_login_data(&self) -> (u32, &[u8]) {
|
||||
(self.pid, &self.kerbros_password)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use crate::grpc::account;
|
||||
use crate::reggie::{RemoteEdgeNodeHolder, RemoteEdgeNodeManagement};
|
||||
use crate::{define_rmc_proto, kerberos};
|
||||
use log::warn;
|
||||
use macros::rmc_struct;
|
||||
use rnex_core::kerberos::{KerberosDateTime, Ticket, derive_key};
|
||||
use rnex_core::nex::account::Account;
|
||||
|
|
@ -13,7 +14,7 @@ use rnex_core::rmc::structures::connection_data::ConnectionData;
|
|||
use rnex_core::rmc::structures::qresult::QResult;
|
||||
use std::hash::{DefaultHasher, Hasher};
|
||||
use std::net::SocketAddrV4;
|
||||
use std::sync::Arc;
|
||||
use std::sync::{Arc, LazyLock, OnceLock};
|
||||
|
||||
define_rmc_proto!(
|
||||
proto AuthClientProtocol{
|
||||
|
|
@ -30,8 +31,8 @@ pub struct AuthHandler {
|
|||
}
|
||||
|
||||
pub fn generate_ticket(
|
||||
source_act_login_data: (u32, [u8; 16]),
|
||||
dest_act_login_data: (u32, [u8; 16]),
|
||||
source_act_login_data: (u32, &[u8]),
|
||||
dest_act_login_data: (u32, &[u8]),
|
||||
) -> Box<[u8]> {
|
||||
let source_key = derive_key(source_act_login_data.0, source_act_login_data.1);
|
||||
let dest_key = derive_key(dest_act_login_data.0, dest_act_login_data.1);
|
||||
|
|
@ -68,27 +69,57 @@ fn station_url_from_sock_addr(sock_addr: SocketAddrV4) -> String {
|
|||
)
|
||||
}
|
||||
|
||||
static GUEST_ACCOUNT: LazyLock<Account> =
|
||||
LazyLock::new(|| Account::new(100, "guest", "MMQea3n!fsik"));
|
||||
|
||||
impl AuthHandler {
|
||||
pub async fn generate_ticket_from_name(
|
||||
&self,
|
||||
name: &str,
|
||||
) -> Result<(u32, Box<[u8]>), ErrorCode> {
|
||||
#[cfg(feature = "guest_login")]
|
||||
{
|
||||
if name == GUEST_ACCOUNT.username {
|
||||
let source_login_data = GUEST_ACCOUNT.get_login_data();
|
||||
let destination_login_data = self.destination_server_acct.get_login_data();
|
||||
|
||||
return Ok((
|
||||
source_login_data.0,
|
||||
generate_ticket(source_login_data, destination_login_data),
|
||||
));
|
||||
}
|
||||
}
|
||||
let Ok(pid) = name.parse() else {
|
||||
warn!("unable to connect to parse pid: {}", name);
|
||||
return Err(ErrorCode::Core_InvalidArgument);
|
||||
};
|
||||
|
||||
let Ok(mut client) = account::Client::new().await else {
|
||||
warn!("unable to connect to grpc");
|
||||
return Err(ErrorCode::Core_Exception);
|
||||
};
|
||||
|
||||
let Ok(passwd) = client.get_nex_password(pid).await else {
|
||||
warn!("unable to get nex password");
|
||||
return Err(ErrorCode::Core_Exception);
|
||||
};
|
||||
|
||||
let source_login_data = (pid, &passwd[..]);
|
||||
let destination_login_data = self.destination_server_acct.get_login_data();
|
||||
|
||||
Ok((
|
||||
pid,
|
||||
generate_ticket(source_login_data, destination_login_data),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl Auth for AuthHandler {
|
||||
async fn login(
|
||||
&self,
|
||||
name: String,
|
||||
) -> Result<(QResult, u32, Vec<u8>, ConnectionData, String), ErrorCode> {
|
||||
let Ok(pid) = name.parse() else {
|
||||
return Err(ErrorCode::Core_InvalidArgument);
|
||||
};
|
||||
|
||||
let Ok(mut client) = account::Client::new().await else {
|
||||
return Err(ErrorCode::Core_Exception);
|
||||
};
|
||||
|
||||
let Ok(passwd) = client.get_nex_password(pid).await else {
|
||||
return Err(ErrorCode::Core_Exception);
|
||||
};
|
||||
|
||||
let source_login_data = (pid, passwd);
|
||||
let destination_login_data = self.destination_server_acct.get_login_data();
|
||||
|
||||
let ticket = generate_ticket(source_login_data, destination_login_data);
|
||||
let (pid, ticket) = self.generate_ticket_from_name(&name).await?;
|
||||
|
||||
let result = QResult::success(Core_Unknown);
|
||||
|
||||
|
|
@ -97,6 +128,7 @@ impl Auth for AuthHandler {
|
|||
hasher.write(name.as_bytes());
|
||||
|
||||
let Ok(addr) = self.control_server.get_url(hasher.finish()).await else {
|
||||
warn!("no secure proxies");
|
||||
return Err(ErrorCode::Core_Exception);
|
||||
};
|
||||
|
||||
|
|
@ -110,7 +142,7 @@ impl Auth for AuthHandler {
|
|||
|
||||
Ok((
|
||||
result,
|
||||
source_login_data.0,
|
||||
pid,
|
||||
ticket.into(),
|
||||
connection_data,
|
||||
self.build_name.to_string(), //format!("{}; Rust NEX Version {} by DJMrTV", self.build_name, env!("CARGO_PKG_VERSION")),
|
||||
|
|
@ -130,22 +162,19 @@ impl Auth for AuthHandler {
|
|||
source_pid: u32,
|
||||
destination_pid: u32,
|
||||
) -> Result<(QResult, Vec<u8>), ErrorCode> {
|
||||
let Some(source_login_data) = get_login_data_by_pid(source_pid).await else {
|
||||
let Some((pid, passwd)) = get_login_data_by_pid(source_pid).await else {
|
||||
return Err(ErrorCode::Core_Exception);
|
||||
};
|
||||
|
||||
let desgination_login_data = if destination_pid == self.destination_server_acct.pid {
|
||||
self.destination_server_acct.get_login_data()
|
||||
} else {
|
||||
let Some(login) = get_login_data_by_pid(destination_pid).await else {
|
||||
return Err(ErrorCode::Core_Exception);
|
||||
};
|
||||
login
|
||||
return Err(ErrorCode::RendezVous_InvalidOperation);
|
||||
};
|
||||
|
||||
let result = QResult::success(Core_Unknown);
|
||||
|
||||
let ticket = generate_ticket(source_login_data, desgination_login_data);
|
||||
let ticket = generate_ticket((pid, &passwd[..]), desgination_login_data);
|
||||
|
||||
Ok((result, ticket.into()))
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue