Adding support for aes256-gcm
Dependencies
- [2]
OBHPOIUHModernising the API with async traits - [3]
D6H7OWTTFixing the terrapin attack mitigation - [4]
TAOFQAIIcargo fmt - [5]
2WEO7OZLVersion updates: getting rid of anyhow + moving to Tokio 1.0 - [6]
2B2UUFXGFixing the doc tests - [7]
WXZWQLGLCorrect negotiation without OpenSSL - [8]
UHAEQPZUSupport ecdsa-sha2-nistp256 keys for authentication - [9]
SMUTYV2CFixing warnings - [10]
VJIXIN4TFixing CVE-2023-48795 - [11]
7FRJYUI6Reboot because of a bad change - [12]
NHOSLQGGThrussh: making OpenSSL optional - [13]
32GIIFWRFixing strict mode
Change contents
- edit in thrussh/src/negotiation.rs at line 57
- replacement in thrussh/src/negotiation.rs at line 74
cipher: &[cipher::chacha20poly1305::NAME],cipher: &[cipher::chacha20poly1305::NAME, cipher::aes256_gcm::NAME], - replacement in thrussh/src/negotiation.rs at line 88
cipher: &[cipher::chacha20poly1305::NAME],cipher: &[cipher::chacha20poly1305::NAME, cipher::aes256_gcm::NAME], - replacement in thrussh/src/negotiation.rs at line 118
cipher: &[cipher::chacha20poly1305::NAME],cipher: &[cipher::chacha20poly1305::NAME, cipher::aes256_gcm::NAME], - replacement in thrussh/src/negotiation.rs at line 128
cipher: &[cipher::chacha20poly1305::NAME],cipher: &[cipher::chacha20poly1305::NAME, cipher::aes256_gcm::NAME], - replacement in thrussh/src/negotiation.rs at line 346
rand::thread_rng().fill_bytes(&mut cookie);rand::rng().fill_bytes(&mut cookie); - replacement in thrussh/src/lib.rs at line 264
mod cipher;pub mod cipher; - edit in thrussh/src/kex.rs at line 55
static IV_BUF: RefCell<CryptoVec> = RefCell::new(CryptoVec::new()); - replacement in thrussh/src/kex.rs at line 83
rand::thread_rng().fill_bytes(&mut server_secret.0);rand::rng().fill_bytes(&mut server_secret.0); - replacement in thrussh/src/kex.rs at line 104
rand::thread_rng().fill_bytes(&mut client_secret.0);rand::rng().fill_bytes(&mut client_secret.0); - edit in thrussh/src/kex.rs at line 167
#[cfg(feature = "openssl")]super::cipher::aes256_gcm::NAME => &super::cipher::aes256_gcm::CIPHER, - replacement in thrussh/src/kex.rs at line 175
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);}IV_BUF.with(|iv| {let compute_key = |c, key: &mut CryptoVec, len| -> Result<(), crate::Error> {let mut buffer = buffer.borrow_mut();buffer.clear();key.clear(); - edit in thrussh/src/kex.rs at line 181[3.312877]→[3.312877:313028](∅→∅),[3.313028]→[3.1339:1372](∅→∅),[3.1372]→[3.1463:1661](∅→∅),[3.1463]→[3.1463:1661](∅→∅),[3.1661]→[3.313273:313463](∅→∅),[3.313273]→[3.313273:313463](∅→∅)
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());while key.len() < len {// extend.buffer.clear(); - edit in thrussh/src/kex.rs at line 184
- replacement in thrussh/src/kex.rs at line 186
buffer.extend(key);buffer.push(c);buffer.extend(session_id.as_ref()); - replacement in thrussh/src/kex.rs at line 194
key.extend(&hash.as_ref());}Ok(())};key.extend(hash.as_ref()); - replacement in thrussh/src/kex.rs at line 196
let (local_to_remote, remote_to_local) = if is_server {(b'D', b'C')} else {(b'C', b'D')};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(())};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')} else {(b'C', b'A', b'D', b'B')}; - replacement in thrussh/src/kex.rs at line 223
let mut key = key.borrow_mut();compute_key(local_to_remote, &mut key, cipher.key_len)?;let local_to_remote = (cipher.make_sealing_cipher)(&key);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); - replacement in thrussh/src/kex.rs at line 231
compute_key(remote_to_local, &mut key, cipher.key_len)?;let remote_to_local = (cipher.make_opening_cipher)(&key);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); - replacement in thrussh/src/kex.rs at line 237
Ok(super::cipher::CipherPair {local_to_remote: local_to_remote,remote_to_local: remote_to_local,Ok(super::cipher::CipherPair {local_to_remote: local_to_remote,remote_to_local: remote_to_local,}) - edit in thrussh/src/cipher/mod.rs at line 20
#[cfg(feature = "openssl")]pub mod aes256_gcm; - replacement in thrussh/src/cipher/mod.rs at line 28
pub make_opening_cipher: fn(key: &[u8]) -> OpeningCipher,pub make_sealing_cipher: fn(key: &[u8]) -> SealingCipher,pub iv_len: usize,pub make_opening_cipher: fn(key: &[u8], iv: &[u8]) -> OpeningCipher,pub make_sealing_cipher: fn(key: &[u8], iv: &[u8]) -> SealingCipher, - edit in thrussh/src/cipher/mod.rs at line 36
#[cfg(feature = "openssl")]Aes256Gcm(aes256_gcm::Key), - edit in thrussh/src/cipher/mod.rs at line 45
#[cfg(feature = "openssl")]OpeningCipher::Aes256Gcm(ref key) => key, - edit in thrussh/src/cipher/mod.rs at line 54
#[cfg(feature = "openssl")]Aes256Gcm(aes256_gcm::Key), - edit in thrussh/src/cipher/mod.rs at line 63
#[cfg(feature = "openssl")]SealingCipher::Aes256Gcm(ref key) => key, - edit in thrussh/src/cipher/chacha20poly1305.rs at line 36
iv_len: 0, - replacement in thrussh/src/cipher/chacha20poly1305.rs at line 43
fn make_sealing_cipher(k: &[u8]) -> super::SealingCipher {fn make_sealing_cipher(k: &[u8], _: &[u8]) -> super::SealingCipher { - replacement in thrussh/src/cipher/chacha20poly1305.rs at line 51
fn make_opening_cipher(k: &[u8]) -> super::OpeningCipher {fn make_opening_cipher(k: &[u8], _: &[u8]) -> super::OpeningCipher { - file addition: aes256_gcm.rs[3.409076]
// Copyright 2016 Pierre-Étienne Meunier//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at//// http://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.//use super::super::Error;use byteorder::{BigEndian, ByteOrder};use openssl::symm::Cipher;use rand::Rng;use std::sync::atomic::{AtomicU64, Ordering};pub const NAME: super::Name = super::Name("aes256-gcm@openssh.com");pub struct Key {cipher: openssl::symm::Cipher,key: [u8; 32],iv: (u32, AtomicU64),}pub static CIPHER: super::Cipher = super::Cipher {_name: NAME,key_len: 32,iv_len: 12,make_sealing_cipher,make_opening_cipher,};fn make_sealing_cipher(k: &[u8], i: &[u8]) -> super::SealingCipher {let mut key = [0; 32];key.clone_from_slice(k);let (a, b) = i.split_at(4);let a = BigEndian::read_u32(&a);let b = BigEndian::read_u64(&b);super::SealingCipher::Aes256Gcm(Key {key,iv: (a, b.into()),cipher: Cipher::aes_256_gcm(),})}fn make_opening_cipher(k: &[u8], i: &[u8]) -> super::OpeningCipher {let mut key = [0; 32];key.clone_from_slice(k);let (a, b) = i.split_at(4);let a = BigEndian::read_u32(&a);let b = BigEndian::read_u64(&b);super::OpeningCipher::Aes256Gcm(Key {key,iv: (a, b.into()),cipher: Cipher::aes_256_gcm(),})}impl super::OpeningKey for Key {fn decrypt_packet_length(&self,_sequence_number: u32,encrypted_packet_length: [u8; 4],) -> [u8; 4] {encrypted_packet_length}fn tag_len(&self) -> usize {16}fn open<'a>(&self,_sequence_number: u32,payload: &'a mut [u8],tag: &[u8],) -> Result<&'a [u8], Error> {let (aad, data) = payload.split_at_mut(4);let mut iv = [0; 12];{let (a, b) = iv.split_at_mut(4);BigEndian::write_u32(a, self.iv.0);let counter = self.iv.1.fetch_add(1, Ordering::Relaxed);BigEndian::write_u64(b, counter);}let mut tag_ = [0; 16];tag_.clone_from_slice(tag);crypt_aead(self.cipher,openssl::symm::Mode::Decrypt,&self.key,Some(&iv),aad,data,&mut tag_,).unwrap();Ok(payload)}}impl super::SealingKey for Key {fn padding_length(&self, payload: &[u8]) -> usize {let encrypted_len = payload.len() + 1;let padding = 16 - (encrypted_len % 16);let min_padding = if padding < 4 { padding + 16 } else { padding };let mut rng = rand::rng();(rng.random::<u8>() & 0xf0 - 16) as usize + min_padding}fn fill_padding(&self, padding_out: &mut [u8]) {openssl::rand::rand_bytes(padding_out).unwrap()}fn tag_len(&self) -> usize {16}/// Append an encrypted packet with contents `packet_content` at/// the end of `buffer`.fn seal(&self, _sequence_number: u32, payload: &mut [u8], tag_out: &mut [u8]) {let (aad, data) = payload.split_at_mut(4);let mut iv = [0; 12];{let (a, b) = iv.split_at_mut(4);BigEndian::write_u32(a, self.iv.0);let counter = self.iv.1.fetch_add(1, Ordering::Relaxed);BigEndian::write_u64(b, counter);}crypt_aead(self.cipher,openssl::symm::Mode::Encrypt,&self.key,Some(&iv),aad,data,tag_out,).unwrap()}}// The following is copied from the OpenSSL crate, with the addition// of a thread-local buffer and less genericity on encryption modes.use std::cell::RefCell;thread_local! {static BUF: RefCell<cryptovec::CryptoVec> = RefCell::new(cryptovec::CryptoVec::new());}pub fn crypt_aead(t: openssl::symm::Cipher,mode: openssl::symm::Mode,key: &[u8],iv: Option<&[u8]>,aad: &[u8],data: &mut [u8],tag: &mut [u8],) -> Result<(), openssl::error::ErrorStack> {let mut c = openssl::symm::Crypter::new(t, mode, key, iv)?;BUF.with(|buffer| {let mut buffer = buffer.borrow_mut();buffer.resize(data.len() + t.block_size());c.aad_update(aad)?;let count = c.update(data, &mut buffer)?;let rest = if let openssl::symm::Mode::Encrypt = mode {let rest = c.finalize(&mut buffer[count..])?;c.get_tag(tag)?;rest} else {c.set_tag(tag)?;c.finalize(&mut buffer[count..])?};data.clone_from_slice(&buffer[..count + rest]);buffer.clear();Ok(())})} - replacement in thrussh/Cargo.toml at line 58
rand = "0.8"rand = "0.9"