Skip to content

Commit

Permalink
Merge pull request #3 from microsoft/fips
Browse files Browse the repository at this point in the history
add flags for openssl-only crypto
  • Loading branch information
connor4312 committed Oct 13, 2022
2 parents fae5b2e + 8c7564a commit e1d29f0
Show file tree
Hide file tree
Showing 22 changed files with 689 additions and 230 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
target
Cargo.lock
.cargo-ok
/.devcontainer
24 changes: 17 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 18 additions & 8 deletions russh-keys/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,25 +29,25 @@ repository = "https://nest.pijul.com/pijul/russh"
version = "0.22.0-beta.7"

[dependencies]
aes = "0.8"
aes = { version = "0.8", optional = true }
bcrypt-pbkdf = "0.6"
bit-vec = "0.6"
cbc = "0.1"
ctr = "0.9"
block-padding = { version = "0.3", features = ["std"] }
cbc = { version = "0.1", optional = true }
ctr = { version = "0.9", optional = true }
block-padding = { version = "0.3", features = ["std"], optional = true }
byteorder = "1.4"
data-encoding = "2.3"
dirs = "3.0"
ed25519-dalek = "1.0"
ed25519-dalek = { version = "1.0", optional = true }
futures = "0.3"
hmac = "0.12"
hmac = { version = "0.12", optional = true }
inout = { version = "0.1", features = ["std"] }
log = "0.4"
md5 = "0.7"
num-bigint = "0.4"
num-integer = "0.1"
openssl = { version = "0.10", optional = true }
pbkdf2 = "0.11"
openssl = { version = "^0.10.40", optional = true }
pbkdf2 = { version = "0.11", optional = true }
rand = "0.7"
rand_core = { version = "0.5", features = ["std"] }
russh-cryptovec = { version = "0.7.0-beta.1", path = "../cryptovec" }
Expand All @@ -65,7 +65,17 @@ tokio-stream = { version = "0.1", features = ["net"] }
yasna = { version = "0.4.0", features = ["bit-vec", "num-bigint"] }

[features]
default = ["rs-crypto"]
vendored-openssl = ["openssl", "openssl/vendored"]
rs-crypto = [
"dep:aes",
"dep:cbc",
"dep:ctr",
"dep:block-padding",
"dep:hmac",
"dep:pbkdf2",
"dep:ed25519-dalek",
]

[dev-dependencies]
env_logger = "0.8"
Expand Down
3 changes: 3 additions & 0 deletions russh-keys/src/agent/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ impl<S: AsyncRead + AsyncWrite + Unpin> AgentClient<S> {
self.buf.push(msg::ADD_ID_CONSTRAINED)
}
match *key {
#[cfg(feature = "rs-crypto")]
key::KeyPair::Ed25519(ref pair) => {
self.buf.extend_ssh_string(b"ssh-ed25519");
self.buf.extend_ssh_string(pair.public.as_bytes());
Expand Down Expand Up @@ -261,6 +262,7 @@ impl<S: AsyncRead + AsyncWrite + Unpin> AgentClient<S> {
hash: SignatureHash::SHA2_512,
})
}
#[cfg(feature = "rs-crypto")]
b"ssh-ed25519" => keys.push(PublicKey::Ed25519(
ed25519_dalek::PublicKey::from_bytes(r.read_string()?)?,
)),
Expand Down Expand Up @@ -510,6 +512,7 @@ fn key_blob(public: &key::PublicKey, buf: &mut CryptoVec) -> Result<(), Error> {
#[allow(clippy::indexing_slicing)] // length is known
BigEndian::write_u32(&mut buf[5..], (len1 - len0) as u32);
}
#[cfg(feature = "rs-crypto")]
PublicKey::Ed25519(ref p) => {
buf.extend(&[0, 0, 0, 0]);
let len0 = buf.len();
Expand Down
2 changes: 2 additions & 0 deletions russh-keys/src/agent/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,9 +233,11 @@ impl<S: AsyncRead + AsyncWrite + Send + Unpin + 'static, A: Agent + Send + 'stat
constrained: bool,
writebuf: &mut CryptoVec,
) -> Result<bool, Error> {
#[cfg(feature = "rs-crypto")]
let pos0 = r.position;
let t = r.read_string()?;
let (blob, key) = match t {
#[cfg(feature = "rs-crypto")]
b"ssh-ed25519" => {
let public_ = r.read_string()?;
let pos1 = r.position;
Expand Down
104 changes: 60 additions & 44 deletions russh-keys/src/format/openssh.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
use aes::cipher::block_padding::NoPadding;
use aes::cipher::{BlockDecryptMut, KeyIvInit, StreamCipher};
use bcrypt_pbkdf;
use ctr::Ctr64LE;
#[cfg(feature = "openssl")]
use openssl::bn::BigNum;

Expand Down Expand Up @@ -35,21 +31,24 @@ pub fn decode_openssh(secret: &[u8], password: Option<&str>) -> Result<key::KeyP
for _ in 0..nkeys {
// TODO check: never really loops beyong the first key
let key_type = position.read_string()?;
if key_type == KEYTYPE_ED25519 {
let pubkey = position.read_string()?;
let seckey = position.read_string()?;
let _comment = position.read_string()?;
if Some(pubkey) != seckey.get(32..) {
return Err(Error::KeyIsCorrupt);
if key_type == KEYTYPE_ED25519 && cfg!(feature = "rs-crypto") {
#[cfg(feature = "rs-crypto")]
{
let pubkey = position.read_string()?;
let seckey = position.read_string()?;
let _comment = position.read_string()?;
if Some(pubkey) != seckey.get(32..) {
return Err(Error::KeyIsCorrupt);
}
let secret = ed25519_dalek::SecretKey::from_bytes(
seckey.get(..32).ok_or(Error::KeyIsCorrupt)?,
)?;
let public = (&secret).into();
return Ok(key::KeyPair::Ed25519(ed25519_dalek::Keypair {
secret,
public,
}));
}
let secret = ed25519_dalek::SecretKey::from_bytes(
seckey.get(..32).ok_or(Error::KeyIsCorrupt)?,
)?;
let public = (&secret).into();
return Ok(key::KeyPair::Ed25519(ed25519_dalek::Keypair {
secret,
public,
}));
} else if key_type == KEYTYPE_RSA && cfg!(feature = "openssl") {
#[cfg(feature = "openssl")]
{
Expand Down Expand Up @@ -91,8 +90,6 @@ pub fn decode_openssh(secret: &[u8], password: Option<&str>) -> Result<key::KeyP
}
}

use aes::*;

fn decrypt_secret_key(
ciphername: &[u8],
kdfname: &[u8],
Expand Down Expand Up @@ -130,32 +127,51 @@ fn decrypt_secret_key(

let mut dec = secret_key.to_vec();
dec.resize(dec.len() + 32, 0u8);
match ciphername {
b"aes128-cbc" => {
#[allow(clippy::unwrap_used)] // parameters are static
let cipher = cbc::Decryptor::<Aes128>::new_from_slices(key, iv).unwrap();
let n = cipher.decrypt_padded_mut::<NoPadding>(&mut dec)?.len();
dec.truncate(n)
}
b"aes256-cbc" => {
#[allow(clippy::unwrap_used)] // parameters are static
let cipher = cbc::Decryptor::<Aes256>::new_from_slices(key, iv).unwrap();
let n = cipher.decrypt_padded_mut::<NoPadding>(&mut dec)?.len();
dec.truncate(n)
}
b"aes128-ctr" => {
#[allow(clippy::unwrap_used)] // parameters are static
let mut cipher = Ctr64LE::<Aes128>::new_from_slices(key, iv).unwrap();
cipher.apply_keystream(&mut dec);
dec.truncate(secret_key.len())
#[cfg(feature = "rs-crypto")]
{
use aes::cipher::block_padding::NoPadding;
use aes::cipher::{BlockDecryptMut, KeyIvInit, StreamCipher};
use aes::*;
use ctr::Ctr64LE;

match ciphername {
b"aes128-cbc" => {
#[allow(clippy::unwrap_used)] // parameters are static
let cipher = cbc::Decryptor::<Aes128>::new_from_slices(key, iv).unwrap();
let n = cipher.decrypt_padded_mut::<NoPadding>(&mut dec)?.len();
dec.truncate(n)
}
b"aes256-cbc" => {
#[allow(clippy::unwrap_used)] // parameters are static
let cipher = cbc::Decryptor::<Aes256>::new_from_slices(key, iv).unwrap();
let n = cipher.decrypt_padded_mut::<NoPadding>(&mut dec)?.len();
dec.truncate(n)
}
b"aes128-ctr" => {
#[allow(clippy::unwrap_used)] // parameters are static
let mut cipher = Ctr64LE::<Aes128>::new_from_slices(key, iv).unwrap();
cipher.apply_keystream(&mut dec);
dec.truncate(secret_key.len())
}
b"aes256-ctr" => {
#[allow(clippy::unwrap_used)] // parameters are static
let mut cipher = Ctr64LE::<Aes256>::new_from_slices(key, iv).unwrap();
cipher.apply_keystream(&mut dec);
dec.truncate(secret_key.len())
}
_ => {}
}
b"aes256-ctr" => {
#[allow(clippy::unwrap_used)] // parameters are static
let mut cipher = Ctr64LE::<Aes256>::new_from_slices(key, iv).unwrap();
cipher.apply_keystream(&mut dec);
dec.truncate(secret_key.len())
}
#[cfg(all(feature = "openssl", not(feature = "rs-crypto")))]
{
use openssl::symm::{decrypt, Cipher};
dec = match ciphername {
b"aes128-cbc" => decrypt(Cipher::aes_128_cbc(), key, Some(iv), &dec)?,
b"aes256-cbc" => decrypt(Cipher::aes_256_cbc(), key, Some(iv), &dec)?,
b"aes128-ctr" => decrypt(Cipher::aes_128_ctr(), key, Some(iv), &dec)?,
b"aes256-ctr" => decrypt(Cipher::aes_256_ctr(), key, Some(iv), &dec)?,
_ => dec,
}
_ => {}
}
Ok(dec)
} else {
Expand Down
10 changes: 2 additions & 8 deletions russh-keys/src/format/pkcs5.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use aes::*;

use super::Encryption;
use crate::{key, Error};

Expand All @@ -11,8 +9,7 @@ pub fn decode_pkcs5(
password: Option<&str>,
enc: Encryption,
) -> Result<key::KeyPair, Error> {
use aes::cipher::{BlockDecryptMut, KeyIvInit};
use block_padding::Pkcs7;
use openssl::symm::{decrypt, Cipher};

if let Some(pass) = password {
let sec = match enc {
Expand All @@ -23,10 +20,7 @@ pub fn decode_pkcs5(
let md5 = c.compute();

#[allow(clippy::unwrap_used)] // AES parameters are static
let c = cbc::Decryptor::<Aes128>::new_from_slices(&md5.0, &iv[..]).unwrap();
let mut dec = secret.to_vec();
c.decrypt_padded_mut::<Pkcs7>(&mut dec)?;
dec
decrypt(Cipher::aes_128_cbc(), &md5.0, Some(&iv[..]), secret)?
}
Encryption::Aes256Cbc(_) => unimplemented!(),
};
Expand Down
Loading

0 comments on commit e1d29f0

Please sign in to comment.