Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
370 changes: 173 additions & 197 deletions Cargo.lock

Large diffs are not rendered by default.

18 changes: 9 additions & 9 deletions ssh-cipher/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,18 @@ edition = "2024"
rust-version = "1.85"

[dependencies]
cipher = "=0.5.0-pre.6"
cipher = "0.5.0-rc.0"
encoding = { package = "ssh-encoding", version = "=0.3.0-pre.1", path = "../ssh-encoding" }

# optional dependencies
aead = { version = "0.6.0-rc.0", optional = true, default-features = false }
aes = { version = "=0.9.0-pre.1", optional = true, default-features = false }
aes-gcm = { version = "=0.11.0-pre.1", optional = true, default-features = false, features = ["aes"] }
cbc = { version = "=0.2.0-pre.1", optional = true }
ctr = { version = "=0.10.0-pre.1", optional = true, default-features = false }
chacha20 = { version = "=0.10.0-pre.1", optional = true, default-features = false, features = ["cipher", "legacy"] }
des = { version = "=0.9.0-pre.1", optional = true, default-features = false }
poly1305 = { version = "0.9.0-rc.0", optional = true, default-features = false }
aead = { version = "0.6.0-rc.1", optional = true, default-features = false }
aes = { version = "0.9.0-rc.0", optional = true, default-features = false }
aes-gcm = { version = "0.11.0-rc.0", optional = true, default-features = false, features = ["aes"] }
cbc = { version = "0.2.0-rc.0", optional = true }
ctr = { version = "0.10.0-rc.0", optional = true, default-features = false }
chacha20 = { version = "0.10.0-rc.0", optional = true, default-features = false, features = ["cipher", "legacy"] }
des = { version = "0.9.0-rc.0", optional = true, default-features = false }
poly1305 = { version = "0.9.0-rc.1", optional = true, default-features = false }
subtle = { version = "2", optional = true, default-features = false }
zeroize = { version = "1", optional = true, default-features = false }

Expand Down
6 changes: 3 additions & 3 deletions ssh-cipher/src/chacha20poly1305.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ pub use chacha20::ChaCha20Legacy as ChaCha20;

use crate::Tag;
use aead::{
AeadCore, Error, KeyInit, KeySizeUser, Result,
array::typenum::{U0, U8, U16, U32},
AeadCore, Error, KeyInit, KeySizeUser, Result, TagPosition,
array::typenum::{U8, U16, U32},
};
use cipher::{KeyIvInit, StreamCipher, StreamCipherSeek};
use poly1305::Poly1305;
Expand Down Expand Up @@ -49,7 +49,7 @@ impl KeyInit for ChaCha20Poly1305 {
impl AeadCore for ChaCha20Poly1305 {
type NonceSize = U8;
type TagSize = U16;
type CiphertextOverhead = U0;
const TAG_POSITION: TagPosition = TagPosition::Postfix;
}

impl ChaCha20Poly1305 {
Expand Down
7 changes: 5 additions & 2 deletions ssh-cipher/src/decryptor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ use des::TdesEde3;
use aes::{Aes128, Aes192, Aes256};

#[cfg(any(feature = "aes-cbc", feature = "tdes"))]
use cipher::{Block, BlockCipher, BlockCipherDecrypt, BlockModeDecrypt};
use cipher::{
Block,
block::{BlockCipherDecrypt, BlockModeDecrypt},
};

/// Stateful decryptor object for unauthenticated SSH symmetric ciphers.
///
Expand Down Expand Up @@ -137,7 +140,7 @@ impl Decryptor {
#[cfg(any(feature = "aes-cbc", feature = "tdes"))]
fn cbc_decrypt<C>(decryptor: &mut cbc::Decryptor<C>, buffer: &mut [u8]) -> Result<()>
where
C: BlockCipher + BlockCipherDecrypt,
C: BlockCipherDecrypt,
{
let (blocks, remaining) = Block::<C>::slice_as_chunks_mut(buffer);

Expand Down
10 changes: 5 additions & 5 deletions ssh-cipher/src/encryptor.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
//! Stateful encryptor object.

use crate::{Cipher, Error, Result};
use cipher::{Block, BlockCipher, BlockCipherEncrypt, KeyIvInit};
use cipher::{Block, BlockCipherEncrypt, KeyIvInit};

#[cfg(feature = "aes-ctr")]
use {
crate::Ctr128BE,
cipher::{StreamCipherCore, array::sizes::U16},
cipher::{BlockSizeUser, StreamCipherCore, array::sizes::U16},
};

#[cfg(feature = "tdes")]
Expand All @@ -16,7 +16,7 @@ use des::TdesEde3;
use aes::{Aes128, Aes192, Aes256};

#[cfg(any(feature = "aes-cbc", feature = "tdes"))]
use cipher::BlockModeEncrypt;
use cipher::block::BlockModeEncrypt;

/// Stateful encryptor object for unauthenticated SSH symmetric ciphers.
///
Expand Down Expand Up @@ -122,7 +122,7 @@ impl Encryptor {
#[cfg(any(feature = "aes-cbc", feature = "tdes"))]
fn cbc_encrypt<C>(encryptor: &mut cbc::Encryptor<C>, buffer: &mut [u8]) -> Result<()>
where
C: BlockCipher + BlockCipherEncrypt,
C: BlockCipherEncrypt,
{
let (blocks, remaining) = Block::<C>::slice_as_chunks_mut(buffer);

Expand All @@ -139,7 +139,7 @@ where
#[cfg(feature = "aes-ctr")]
pub(crate) fn ctr_encrypt<C>(encryptor: &mut Ctr128BE<C>, buffer: &mut [u8]) -> Result<()>
where
C: BlockCipher<BlockSize = U16> + BlockCipherEncrypt,
C: BlockCipherEncrypt + BlockSizeUser<BlockSize = U16>,
{
let (blocks, remaining) = Block::<C>::slice_as_chunks_mut(buffer);

Expand Down
10 changes: 5 additions & 5 deletions ssh-cipher/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ use encoding::{Label, LabelError};

#[cfg(feature = "aes-gcm")]
use {
aead::{AeadInPlace, array::typenum::U12},
aead::{AeadInOut, array::typenum::U12},
aes_gcm::{Aes128Gcm, Aes256Gcm},
};

Expand Down Expand Up @@ -236,7 +236,7 @@ impl Cipher {
let nonce = iv.try_into().map_err(|_| Error::IvSize)?;
let tag = tag.ok_or(Error::TagSize)?;
cipher
.decrypt_in_place_detached(nonce, &[], buffer, &tag)
.decrypt_inout_detached(nonce, &[], buffer.into(), &tag)
.map_err(|_| Error::Crypto)?;

Ok(())
Expand All @@ -247,7 +247,7 @@ impl Cipher {
let nonce = iv.try_into().map_err(|_| Error::IvSize)?;
let tag = tag.ok_or(Error::TagSize)?;
cipher
.decrypt_in_place_detached(nonce, &[], buffer, &tag)
.decrypt_inout_detached(nonce, &[], buffer.into(), &tag)
.map_err(|_| Error::Crypto)?;

Ok(())
Expand Down Expand Up @@ -300,7 +300,7 @@ impl Cipher {
let cipher = Aes128Gcm::new_from_slice(key).map_err(|_| Error::KeySize)?;
let nonce = iv.try_into().map_err(|_| Error::IvSize)?;
let tag = cipher
.encrypt_in_place_detached(nonce, &[], buffer)
.encrypt_inout_detached(nonce, &[], buffer.into())
.map_err(|_| Error::Crypto)?;

Ok(Some(tag))
Expand All @@ -310,7 +310,7 @@ impl Cipher {
let cipher = Aes256Gcm::new_from_slice(key).map_err(|_| Error::KeySize)?;
let nonce = iv.try_into().map_err(|_| Error::IvSize)?;
let tag = cipher
.encrypt_in_place_detached(nonce, &[], buffer)
.encrypt_inout_detached(nonce, &[], buffer.into())
.map_err(|_| Error::Crypto)?;

Ok(Some(tag))
Expand Down
8 changes: 3 additions & 5 deletions ssh-encoding/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,14 @@ rust-version = "1.85"

[dependencies]
base64ct = { version = "1.7", optional = true }
bigint = { package = "crypto-bigint", version = "=0.7.0-pre.4", optional = true, default-features = false, features = ["alloc"] }
bytes = { version = "1", optional = true, default-features = false }
digest = { version = "=0.11.0-pre.9", optional = true, default-features = false }
pem-rfc7468 = { version = "1.0.0-rc.2", optional = true }
digest = { version = "0.11.0-rc.0", optional = true, default-features = false }
pem-rfc7468 = { version = "1.0.0-rc.3", optional = true }
ssh-derive = { version = "0.0.1-alpha", optional = true, path = "../ssh-derive" }
subtle = { version = "2", optional = true, default-features = false }
zeroize = { version = "1", optional = true, default-features = false }

# TODO(tarcieri): migrate to `crypto-bigint`
bigint = { package = "num-bigint-dig", version = "0.8", optional = true, default-features = false }

[dev-dependencies]
hex-literal = "1"

Expand Down
7 changes: 7 additions & 0 deletions ssh-encoding/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,13 @@ impl From<base64ct::InvalidLengthError> for Error {
}
}

#[cfg(feature = "bigint")]
impl From<bigint::DecodeError> for Error {
fn from(_: bigint::DecodeError) -> Error {
Error::MpintEncoding
}
}

#[cfg(feature = "pem")]
impl From<pem_rfc7468::Error> for Error {
fn from(err: pem_rfc7468::Error) -> Error {
Expand Down
14 changes: 14 additions & 0 deletions ssh-encoding/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,9 @@ pub use crate::mpint::Mpint;
#[cfg(feature = "base64")]
pub use crate::{base64::Base64Reader, base64::Base64Writer};

#[cfg(feature = "bigint")]
pub use bigint;

#[cfg(feature = "bytes")]
pub use bytes;

Expand All @@ -258,3 +261,14 @@ pub use ssh_derive::{Decode, Encode};

#[cfg(all(doc, feature = "alloc"))]
use alloc::vec::Vec;

#[cfg(feature = "bigint")]
pub use bigint::BoxedUint as Uint;

/// Non-zero [`Uint`].
#[cfg(feature = "bigint")]
pub type NonZeroUint = bigint::NonZero<Uint>;

/// Odd [`Uint`].
#[cfg(feature = "bigint")]
pub type OddUint = bigint::Odd<Uint>;
111 changes: 97 additions & 14 deletions ssh-encoding/src/mpint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ use crate::{CheckedSum, Decode, Encode, Error, Reader, Result, Writer};
use alloc::{boxed::Box, vec::Vec};
use core::fmt;

#[cfg(feature = "bigint")]
use crate::{NonZeroUint, OddUint, Uint};

#[cfg(feature = "subtle")]
use subtle::{Choice, ConstantTimeEq};

Expand Down Expand Up @@ -205,45 +208,125 @@ impl fmt::UpperHex for Mpint {
}

#[cfg(feature = "bigint")]
impl TryFrom<bigint::BigUint> for Mpint {
impl TryFrom<NonZeroUint> for Mpint {
type Error = Error;

fn try_from(uint: bigint::BigUint) -> Result<Mpint> {
fn try_from(uint: NonZeroUint) -> Result<Mpint> {
Mpint::try_from(&uint)
}
}

#[cfg(feature = "bigint")]
impl TryFrom<&bigint::BigUint> for Mpint {
impl TryFrom<&NonZeroUint> for Mpint {
type Error = Error;

fn try_from(uint: &NonZeroUint) -> Result<Mpint> {
Self::try_from(uint.as_ref())
}
}

#[cfg(feature = "bigint")]
impl TryFrom<OddUint> for Mpint {
type Error = Error;

fn try_from(uint: &bigint::BigUint) -> Result<Mpint> {
let bytes = Zeroizing::new(uint.to_bytes_be());
Mpint::from_positive_bytes(bytes.as_slice())
fn try_from(uint: OddUint) -> Result<Mpint> {
Mpint::try_from(&uint)
}
}

#[cfg(feature = "bigint")]
impl TryFrom<Mpint> for bigint::BigUint {
impl TryFrom<&OddUint> for Mpint {
type Error = Error;

fn try_from(mpint: Mpint) -> Result<bigint::BigUint> {
bigint::BigUint::try_from(&mpint)
fn try_from(uint: &OddUint) -> Result<Mpint> {
Self::try_from(uint.as_ref())
}
}

#[cfg(feature = "bigint")]
impl TryFrom<&Mpint> for bigint::BigUint {
impl TryFrom<Uint> for Mpint {
type Error = Error;

fn try_from(mpint: &Mpint) -> Result<bigint::BigUint> {
mpint
.as_positive_bytes()
.map(bigint::BigUint::from_bytes_be)
fn try_from(uint: Uint) -> Result<Mpint> {
Mpint::try_from(&uint)
}
}

#[cfg(feature = "bigint")]
impl TryFrom<&Uint> for Mpint {
type Error = Error;

fn try_from(uint: &Uint) -> Result<Mpint> {
let bytes = Zeroizing::new(uint.to_be_bytes());
Mpint::from_positive_bytes(&bytes)
}
}

#[cfg(feature = "bigint")]
impl TryFrom<Mpint> for NonZeroUint {
type Error = Error;

fn try_from(mpint: Mpint) -> Result<NonZeroUint> {
NonZeroUint::try_from(&mpint)
}
}

#[cfg(feature = "bigint")]
impl TryFrom<&Mpint> for NonZeroUint {
type Error = Error;

fn try_from(mpint: &Mpint) -> Result<NonZeroUint> {
let uint = Uint::try_from(mpint)?;
NonZeroUint::new(uint)
.into_option()
.ok_or(Error::MpintEncoding)
}
}

#[cfg(feature = "bigint")]
impl TryFrom<Mpint> for OddUint {
type Error = Error;

fn try_from(mpint: Mpint) -> Result<OddUint> {
OddUint::try_from(&mpint)
}
}

#[cfg(feature = "bigint")]
impl TryFrom<&Mpint> for OddUint {
type Error = Error;

fn try_from(mpint: &Mpint) -> Result<OddUint> {
let uint = Uint::try_from(mpint)?;
OddUint::new(uint).into_option().ok_or(Error::MpintEncoding)
}
}

#[cfg(feature = "bigint")]
impl TryFrom<Mpint> for Uint {
type Error = Error;

fn try_from(mpint: Mpint) -> Result<Uint> {
Uint::try_from(&mpint)
}
}

#[cfg(feature = "bigint")]
impl TryFrom<&Mpint> for Uint {
type Error = Error;

fn try_from(mpint: &Mpint) -> Result<Uint> {
let bytes = mpint.as_positive_bytes().ok_or(Error::MpintEncoding)?;
let bits_precision = bytes
.len()
.checked_mul(8)
.and_then(|n| u32::try_from(n).ok())
.ok_or(Error::MpintEncoding)?;

Ok(Uint::from_be_slice(bytes, bits_precision)?)
}
}

#[cfg(test)]
mod tests {
use super::Mpint;
Expand Down
Loading