LYRZREY75IOPQJ3DMJJB4SINAEVI5P5TE32SSFO7QKFBDYVXXKNAC 5EV2X6V42RKTOER62WQPTLMCES74WAIZI6IR7IJJPFYQ7Q4VMTTAC WX7UY5KKUXOHBGPNWJC6ZQDQ3LFGNTKGF6ZQFIPYNI6H5IMWGOYAC SKTE2HF665D2NL7TVZAADZDKHLKZKKEC7CLNKSYSJM36TRBWWVZQC 7FRJYUI62VW257VVFQXND6OKSAILVTHGEJCXFE6CG6FIOIUTDVYAC OBHPOIUH2CPAB2ORVMOGAAQVN4NYP6GHGTIODEQ46VUFNZIUAIRQC Q323RFJSTFYUJ5FPTKT4NI7DK3KDC3O4YLBDEYWKEYCA7G276SUQC MCS77Y4VJGB6TU2HOLASGSRW4B6MT74XABD4KYALIRS54GGN2DDQC NHOSLQGG4CIWBE7VKL5MB7PSY3RZ5IVDFENMGZG6X755GGZ6B3VQC D6H7OWTTMHHX6BTB3B6MNBOBX2L66CBL4LGSEUSAI2MCRCJDQFRQC UHAEQPZUODJ5YVBZJPPJVLO7EBW6DC2JXHQBN26ARELAVULG3JUQC WXZWQLGLNQ3QRHMBH7YPTHKSPUST4HD34H3PW5E4LHQYH3KLNHYAC 2WEO7OZLWJJPUYK4WXLT5FD46G2MAEIHEYMDW5GASCBUNKOPXCVAC Y67GNDVBCXX5V3SL3OAQCU3NX52OR34NXK7ARKHK7EQDGCLVTHTQC }}}pub mod hmac256 {pub const KEY_BYTES: usize = libsodium_sys::crypto_auth_hmacsha256_KEYBYTES as usize;pub const BYTES: usize = libsodium_sys::crypto_auth_hmacsha256_BYTES as usize;pub fn init_state(key: &[u8; KEY_BYTES]) -> libsodium_sys::crypto_auth_hmacsha256_state {unsafe {let mut state = std::mem::zeroed();libsodium_sys::crypto_auth_hmacsha256_init(&mut state, key.as_ptr(), KEY_BYTES);state}}pub fn update(s: &mut libsodium_sys::crypto_auth_hmacsha256_state, msg: &[u8]) {unsafe {libsodium_sys::crypto_auth_hmacsha256_update(s, msg.as_ptr(), msg.len() as u64);
let mac = Self::select(pref.mac, r.read_string()?);let mac = mac.and_then(|(_, x)| Some(x));
let mac_string = r.read_string()?;let mac = Self::select(pref.mac, mac_string);if mac.is_none() {debug!("Could not find common mac, other side only supports {:?}, we only support {:?}",from_utf8(mac_string),pref.mac);return Err(Error::NoCommonMac.into());}let mac = mac.unwrap().1;
pub enum MacKey {None,HmacSha256(hmac_sha256::Key),}impl MacKey {pub fn len(&self) -> usize {match self {MacKey::None => 0,MacKey::HmacSha256(_) => thrussh_libsodium::hmac256::BYTES,}}pub fn authenticate(&self, number: u32, b: &[u8], out: &mut [u8]) {match self {MacKey::None => {}MacKey::HmacSha256(k) => hmac_sha256::authenticate(k, number, b, out),}}pub fn verify(&self, number: u32, b: &[u8], out: &[u8]) -> bool {match self {MacKey::None => true,MacKey::HmacSha256(k) => hmac_sha256::verify(k, number, b, out),}}}#[derive(Debug, PartialEq, Eq, Copy, Clone)]pub struct Name(pub &'static str);impl AsRef<str> for Name {fn as_ref(&self) -> &str {self.0}}pub struct Mac {pub _name: Name,pub key_len: usize,pub make_key: fn(key: &[u8]) -> MacKey,}pub mod hmac_sha256 {use byteorder::{BigEndian, ByteOrder};pub const NAME: super::Name = super::Name("hmac-sha2-256");pub struct Key([u8; thrussh_libsodium::hmac256::KEY_BYTES]);pub const MAC: super::Mac = super::Mac {_name: NAME,key_len: 32,make_key,};fn make_key(b: &[u8]) -> super::MacKey {let mut k = Key([0; thrussh_libsodium::hmac256::KEY_BYTES]);k.0.clone_from_slice(b);super::MacKey::HmacSha256(k)}pub fn authenticate(k: &Key, number: u32, b: &[u8], out: &mut [u8]) {let mut s = thrussh_libsodium::hmac256::init_state(&k.0);let mut n = [0; 4];BigEndian::write_u32(&mut n, number);thrussh_libsodium::hmac256::update(&mut s, &n);thrussh_libsodium::hmac256::update(&mut s, b);thrussh_libsodium::hmac256::finalize(&mut s, out);}pub fn verify(k: &Key, number: u32, b: &[u8], h: &[u8]) -> bool {let mut s = thrussh_libsodium::hmac256::init_state(&k.0);let mut n = [0; 4];BigEndian::write_u32(&mut n, number);thrussh_libsodium::hmac256::update(&mut s, &n);thrussh_libsodium::hmac256::update(&mut s, b);let mut out = [0; thrussh_libsodium::hmac256::BYTES];thrussh_libsodium::hmac256::finalize(&mut s, &mut out);thrussh_libsodium::memcmp(&out, h)}}
let compute_key = |c, key: &mut CryptoVec, len| -> Result<(), crate::Error> {let mut buffer = buffer.borrow_mut();buffer.clear();key.clear();
MAC_BUF.with(|mac_buf| {let compute_key =|c, key: &mut CryptoVec, len| -> Result<(), crate::Error> {let mut buffer = buffer.borrow_mut();buffer.clear();key.clear();if let Some(ref shared) = self.shared_secret {buffer.extend_ssh_mpint(&shared.0);}buffer.extend(exchange_hash.as_ref());buffer.push(c);buffer.extend(session_id.as_ref());let hash = {use sha2::Digest;let mut hasher = sha2::Sha256::new();hasher.update(&buffer[..]);hasher.finalize()};key.extend(hash.as_ref());
if let Some(ref shared) = self.shared_secret {buffer.extend_ssh_mpint(&shared.0);}
while key.len() < len {// extend.buffer.clear();if let Some(ref shared) = self.shared_secret {buffer.extend_ssh_mpint(&shared.0);}buffer.extend(exchange_hash.as_ref());buffer.extend(key);let hash = {use sha2::Digest;let mut hasher = sha2::Sha256::new();hasher.update(&buffer[..]);hasher.finalize()};key.extend(&hash.as_ref());}key.resize(len);Ok(())};
buffer.extend(exchange_hash.as_ref());buffer.push(c);buffer.extend(session_id.as_ref());let hash = {use sha2::Digest;let mut hasher = sha2::Sha256::new();hasher.update(&buffer[..]);hasher.finalize()
let (local_to_remote,local_to_remote_iv,local_to_remote_mac,remote_to_local,remote_to_local_iv,remote_to_local_mac,) = if is_server {(b'D', b'B', b'F', b'C', b'A', b'E')} else {(b'C', b'A', b'E', b'D', b'B', b'F')
while key.len() < len {// extend.buffer.clear();if let Some(ref shared) = self.shared_secret {buffer.extend_ssh_mpint(&shared.0);}buffer.extend(exchange_hash.as_ref());buffer.extend(key);let hash = {use sha2::Digest;let mut hasher = sha2::Sha256::new();hasher.update(&buffer[..]);hasher.finalize()};key.extend(&hash.as_ref());
let mut key = key.borrow_mut();compute_key(local_to_remote, &mut key, cipher.key_len)?;let mut iv = iv.borrow_mut();if cipher.iv_len > 0 {compute_key(local_to_remote_iv, &mut iv, cipher.iv_len)?;
let (local_to_remote, local_to_remote_iv, remote_to_local, remote_to_local_iv) =if is_server {(b'D', b'B', b'C', b'A')
let local_to_remote_mac = if let Some(mac) = mac {let mut mac_buf = mac_buf.borrow_mut();compute_key(local_to_remote_mac, &mut mac_buf, mac.key_len)?;(mac.make_key)(&mac_buf)
let mut key = key.borrow_mut();compute_key(local_to_remote, &mut key, cipher.key_len)?;let mut iv = iv.borrow_mut();if cipher.iv_len > 0 {compute_key(local_to_remote_iv, &mut iv, cipher.iv_len)?;}let local_to_remote = (cipher.make_sealing_cipher)(&key, &iv);
let local_to_remote =(cipher.make_sealing_cipher)(&key, &iv, local_to_remote_mac);
compute_key(remote_to_local, &mut key, cipher.key_len)?;if cipher.iv_len > 0 {compute_key(remote_to_local_iv, &mut iv, cipher.iv_len)?;}let remote_to_local = (cipher.make_opening_cipher)(&key, &iv);
compute_key(remote_to_local, &mut key, cipher.key_len)?;if cipher.iv_len > 0 {compute_key(remote_to_local_iv, &mut iv, cipher.iv_len)?;}let remote_to_local_mac = if let Some(mac) = mac {let mut mac_buf = mac_buf.borrow_mut();compute_key(remote_to_local_mac, &mut mac_buf, mac.key_len)?;(mac.make_key)(&mac_buf)} else {mac::MacKey::None};let remote_to_local =(cipher.make_opening_cipher)(&key, &iv, remote_to_local_mac);
pub make_opening_cipher: fn(key: &[u8], iv: &[u8]) -> OpeningCipher,pub make_sealing_cipher: fn(key: &[u8], iv: &[u8]) -> SealingCipher,
pub make_opening_cipher: fn(key: &[u8], iv: &[u8], mac: mac::MacKey) -> OpeningCipher,pub make_sealing_cipher: fn(key: &[u8], iv: &[u8], mac: mac::MacKey) -> SealingCipher,
fn seal(&self, _seqn: u32, _plaintext_in_ciphertext_out: &mut [u8], tag_out: &mut [u8]) {debug_assert_eq!(tag_out.len(), self.tag_len());
fn seal(&self, _seqn: u32, plaintext_in_ciphertext_out: &mut [u8], tag_out: usize) {debug_assert_eq!(tag_out, plaintext_in_ciphertext_out.len());
fn seal(&self,sequence_number: u32,plaintext_in_ciphertext_out: &mut [u8],tag_out: &mut [u8],) {
fn seal(&self, sequence_number: u32, plaintext_in_ciphertext_out: &mut [u8], tag_out: usize) {let (payload, tag_out) = plaintext_in_ciphertext_out.split_at_mut(tag_out);
use openssl::symm::{Cipher, Crypter};use rand::Rng;use std::sync::Mutex;pub const NAME: super::Name = super::Name("aes256-ctr");pub struct Key {mac: crate::mac::MacKey,crypter: Mutex<Crypter>,buf: Mutex<cryptovec::CryptoVec>,}pub static CIPHER: super::Cipher = super::Cipher {_name: NAME,key_len: 32,iv_len: 16,make_sealing_cipher,make_opening_cipher,};fn make_sealing_cipher(k: &[u8], iv: &[u8], mac: crate::mac::MacKey) -> super::SealingCipher {super::SealingCipher::Aes256Ctr(Key {crypter: Mutex::new(openssl::symm::Crypter::new(Cipher::aes_256_ctr(),openssl::symm::Mode::Encrypt,&k,Some(&iv),).unwrap(),),mac,buf: Mutex::new(cryptovec::CryptoVec::new()),})}fn make_opening_cipher(k: &[u8], iv: &[u8], mac: crate::mac::MacKey) -> super::OpeningCipher {super::OpeningCipher::Aes256Ctr(Key {crypter: Mutex::new(openssl::symm::Crypter::new(Cipher::aes_256_ctr(),openssl::symm::Mode::Encrypt,&k,Some(&iv),).unwrap(),),mac,buf: Mutex::new(cryptovec::CryptoVec::new()),})}impl super::SealingKey for Key {fn padding_length(&self, payload: &[u8]) -> usize {let encrypted_len = payload.len() + 5;let padding = 16 - (encrypted_len % 16);let min_padding = if padding < 4 { padding + 16 } else { padding };let mut rng = rand::rng();(rng.random::<u8>() & 0xe0) as usize + min_padding}fn fill_padding(&self, padding_out: &mut [u8]) {openssl::rand::rand_bytes(padding_out).unwrap()}fn tag_len(&self) -> usize {self.mac.len()}/// Append an encrypted packet with contents `packet_content` at/// the end of `buffer`.fn seal(&self, sequence_number: u32, payload_tag: &mut [u8], tag_out: usize) {let (payload, tag) = payload_tag.split_at_mut(tag_out);self.mac.authenticate(sequence_number, &payload[..], tag);let mut out = self.buf.lock().unwrap();out.resize(payload.len());let mut crypter = self.crypter.lock().unwrap();let count = crypter.update(&payload, &mut out).unwrap();crypter.finalize(&mut out[count..]).unwrap();payload.clone_from_slice(&out);}}impl super::OpeningKey for Key {fn decrypt_packet_length(&self,_sequence_number: u32,encrypted_packet_length: [u8; 4],) -> [u8; 4] {let mut out = [0; 4];let mut crypter = self.crypter.lock().unwrap();let count = crypter.update(&encrypted_packet_length, &mut out).unwrap();crypter.finalize(&mut out[count..]).unwrap();out}fn tag_len(&self) -> usize {self.mac.len()}fn open<'a>(&self,sequence_number: u32,payload: &'a mut [u8],tag: usize,) -> Result<&'a [u8], crate::Error> {let (payload, tag) = payload.split_at_mut(tag);let mut out = self.buf.lock().unwrap();out.resize(payload.len());let mut c = self.crypter.lock().unwrap();let count = c.update(&payload, &mut out).unwrap();c.finalize(&mut out[count..]).unwrap();if !self.mac.verify(sequence_number, &out, tag) {return Err(crate::Error::WrongMAC);}payload.clone_from_slice(&out);Ok(payload)}}