use std::sync::{Arc, Mutex};
use base64::Engine;
use base64::prelude::BASE64_STANDARD;
use rand_core::{OsRng, RngCore};
use crate::crypto::{encrypt, generate_aes_nonce};
use crate::DomainConfig;
use crate::message::{Direction, DNSHeader, DNSMessage, DNSQuestion, Opcode, QClass, QType, ResponseCode};
use crate::session::ClientCryptoContext;
pub fn generate_client_handshake_message(rand: &mut OsRng, domain_config: &DomainConfig, crypto_context: Arc<Mutex<ClientCryptoContext>>, peer: &String) -> DNSMessage {
get_client_handshake_message(
rand.next_u32() as u16,
domain_config.get_fq_key_endpoint(),
crypto_context.lock().unwrap().get_public_key_domain(&domain_config.base_domain),
peer
)
}
pub fn get_client_handshake_message(msg_id: u16, key_domain: String, public_key_domain: String, peer: &String) -> DNSMessage {
DNSMessage {
header: DNSHeader {
id: msg_id,
direction: Direction::Request,
opcode: Opcode::Query,
authoritative: false,
truncation: false,
recursion_desired: false,
recursion_available: false,
valid_zeroes: true,
response: ResponseCode::NoError,
question_count: 2,
answer_record_count: 0,
authority_record_count: 0,
additional_record_count: 0,
},
questions: vec![
DNSQuestion {
qname: key_domain,
qtype: QType::A,
qclass: QClass::Internet,
},
DNSQuestion {
qname: public_key_domain,
qtype: QType::A,
qclass: QClass::Internet,
}
],
answer_records: vec![],
authority_records: vec![],
additional_records: vec![],
peer: peer.parse().unwrap(),
}
}
pub fn generate_string_encryption_message(value: String, rand: &mut OsRng, domain_config: &DomainConfig, crypto_context: Arc<Mutex<ClientCryptoContext>>, peer: &String) -> Result<DNSMessage, ()> {
let nonce = generate_aes_nonce();
let encrypted = encrypt(&crypto_context.lock().unwrap().shared_key.clone().unwrap(), &nonce, &value.clone().into_bytes());
if let Ok(e) = encrypted {
let encrypted_string = BASE64_STANDARD.encode(e);
let nonce_string = BASE64_STANDARD.encode(nonce);
return Ok(get_string_encryption_message(
rand.next_u32() as u16,
crypto_context.lock().unwrap().get_public_key_domain(&domain_config.base_domain),
encrypted_string,
nonce_string,
peer
))
}
Err(())
}
pub fn get_string_encryption_message(msg_id: u16, public_key_domain: String, encrypted_string: String, nonce_string: String, peer: &String) -> DNSMessage {
DNSMessage {
header: DNSHeader {
id: msg_id,
direction: Direction::Request,
opcode: Opcode::Query,
authoritative: false,
truncation: false,
recursion_desired: false,
recursion_available: false,
valid_zeroes: true,
response: ResponseCode::NoError,
question_count: 3,
answer_record_count: 0,
authority_record_count: 0,
additional_record_count: 0,
},
questions: vec![
DNSQuestion {
qname: public_key_domain,
qtype: QType::A,
qclass: QClass::Internet,
},
DNSQuestion {
qname: encrypted_string,
qtype: QType::A,
qclass: QClass::Internet,
},
DNSQuestion {
qname: nonce_string,
qtype: QType::A,
qclass: QClass::Internet,
}
],
answer_records: vec![],
authority_records: vec![],
additional_records: vec![],
peer: peer.parse().unwrap(),
}
}
pub fn generate_key_string_encryption_message(key: String, value: String, rand: &mut OsRng, domain_config: &DomainConfig, crypto_context: Arc<Mutex<ClientCryptoContext>>, peer: &String) -> Result<DNSMessage, ()> {
let nonce = generate_aes_nonce();
let encrypted_key = encrypt(&crypto_context.lock().unwrap().shared_key.clone().unwrap(), &nonce, &key.clone().into_bytes());
let encrypted_value = encrypt(&crypto_context.lock().unwrap().shared_key.clone().unwrap(), &nonce, &value.clone().into_bytes());
match (encrypted_key, encrypted_value) {
(Ok(encrypted_key), Ok(encrypted_value)) => {
let encrypted_key = BASE64_STANDARD.encode(encrypted_key);
let encrypted_value = BASE64_STANDARD.encode(encrypted_value);
let nonce_string = BASE64_STANDARD.encode(nonce);
return Ok(get_key_string_encryption_message(
rand.next_u32() as u16,
crypto_context.lock().unwrap().get_public_key_domain(&domain_config.base_domain),
encrypted_key,
encrypted_value,
nonce_string,
peer
))
}
(_, _) => {}
}
Err(())
}
pub fn get_key_string_encryption_message(msg_id: u16, public_key_domain: String, encrypted_key: String, encrypted_string: String, nonce_string: String, peer: &String) -> DNSMessage {
DNSMessage {
header: DNSHeader {
id: msg_id,
direction: Direction::Request,
opcode: Opcode::Query,
authoritative: false,
truncation: false,
recursion_desired: false,
recursion_available: false,
valid_zeroes: true,
response: ResponseCode::NoError,
question_count: 4,
answer_record_count: 0,
authority_record_count: 0,
additional_record_count: 0,
},
questions: vec![
DNSQuestion {
qname: public_key_domain,
qtype: QType::A,
qclass: QClass::Internet,
},
DNSQuestion {
qname: encrypted_key,
qtype: QType::A,
qclass: QClass::Internet,
},
DNSQuestion {
qname: encrypted_string,
qtype: QType::A,
qclass: QClass::Internet,
},
DNSQuestion {
qname: nonce_string,
qtype: QType::A,
qclass: QClass::Internet,
}
],
answer_records: vec![],
authority_records: vec![],
additional_records: vec![],
peer: peer.parse().unwrap(),
}
}