Disable deprecated stream ciphers by default

- Enable stream ciphers explicitly with stream-cipher feature
- Upgraded shadowsocks-crypto to v0.1.2

fixes #373
This commit is contained in:
zonyitoo
2021-01-04 23:08:00 +08:00
parent 47169d6fc1
commit 9000b31ffb
14 changed files with 67 additions and 27 deletions

View File

@@ -33,7 +33,7 @@ jobs:
- name: Build & Test (--no-default-features)
run: cargo test --verbose --no-default-features --no-fail-fast
- name: Build with All Features Enabled
run: cargo build --verbose --features "local-redir local-dns dns-over-tls"
run: cargo build --verbose --features "local-redir local-dns dns-over-tls dns-over-https stream-cipher"
build-windows:
runs-on: windows-latest
@@ -56,7 +56,7 @@ jobs:
- name: Build & Test (--no-default-features)
run: cargo test --verbose --no-default-features --no-fail-fast
- name: Build with All Features Enabled
run: cargo build --verbose --features "local-dns dns-over-tls"
run: cargo build --verbose --features "local-dns dns-over-tls dns-over-https stream-cipher"
build-macos:
runs-on: macos-latest
@@ -84,4 +84,4 @@ jobs:
- name: Build & Test (--no-default-features)
run: cargo test --verbose --no-default-features --no-fail-fast
- name: Build with All Features Enabled
run: cargo build --verbose --features "local-redir local-dns dns-over-tls"
run: cargo build --verbose --features "local-redir local-dns dns-over-tls dns-over-https stream-cipher"

32
Cargo.lock generated
View File

@@ -273,9 +273,9 @@ checksum = "993a608597367c6377b258c25d7120740f00ed23a2252b729b1932dd7866f908"
[[package]]
name = "derivative"
version = "2.1.1"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb582b60359da160a9477ee80f15c8d784c477e69c217ef2cdd4169c24ea380f"
checksum = "eaed5874effa6cde088c644ddcdcb4ffd1511391c5be4fdd7a5ccd02c7e4a183"
dependencies = [
"proc-macro2",
"quote",
@@ -482,13 +482,13 @@ dependencies = [
[[package]]
name = "getrandom"
version = "0.2.0"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee8025cf36f917e6a52cce185b7c7177689b838b7ec138364e50cc2277a56cf4"
checksum = "4060f4657be78b8e766215b02b18a2e862d83745545de804638e2b545e81aee6"
dependencies = [
"cfg-if 0.1.10",
"cfg-if 1.0.0",
"libc",
"wasi 0.9.0+wasi-snapshot-preview1",
"wasi 0.10.0+wasi-snapshot-preview1",
]
[[package]]
@@ -1234,7 +1234,7 @@ version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8b34ba8cfb21243bd8df91854c830ff0d785fff2e82ebd4434c2644cb9ada18"
dependencies = [
"getrandom 0.2.0",
"getrandom 0.2.1",
]
[[package]]
@@ -1503,12 +1503,12 @@ dependencies = [
[[package]]
name = "shadowsocks-crypto"
version = "0.1.0"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84db25042349bccfed0c40513ba3ee3522aeebef4f6c398fcc56e123e6e5c665"
checksum = "01ecc6d22f07b98e272641a08fbfa30aa04578669bfa49254d6fa73ac56ddc62"
dependencies = [
"crypto2",
"rand 0.7.3",
"rand 0.8.0",
"ring",
]
@@ -1600,9 +1600,9 @@ checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
[[package]]
name = "smallvec"
version = "1.5.1"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae524f056d7d770e174287294f562e95044c68e88dec909a00d2094805db9d75"
checksum = "1a55ca5f3b68e41c979bf8c46a6f1da892ca4db8f94023ce0bd32407573b1ac0"
[[package]]
name = "socket2"
@@ -1653,9 +1653,9 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.56"
version = "1.0.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9802ddde94170d186eeee5005b798d9c159fa970403f1be19976d0cfb939b72"
checksum = "4211ce9909eb971f111059df92c45640aad50a619cf55cd76476be803c4c68e6"
dependencies = [
"proc-macro2",
"quote",
@@ -2404,9 +2404,9 @@ dependencies = [
[[package]]
name = "yaml-rust"
version = "0.4.4"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39f0c922f1a334134dc2f7a8b67dc5d25f0735263feec974345ff706bcf20b0d"
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
dependencies = [
"linked-hash-map",
]

View File

@@ -101,6 +101,12 @@ tcmalloc-vendored = ["tcmalloc/bundled"]
# Enable tokio's multi-threaded runtime
multi-threaded = ["tokio/rt-multi-thread"]
# Enable Stream Cipher Protocol
# WARN: Stream Cipher Protocol is proved to be insecured
# https://github.com/shadowsocks/shadowsocks-rust/issues/373
# Users should always avoid using these ciphers in practice
stream-cipher = ["shadowsocks-service/stream-cipher"]
[dependencies]
log = "0.4"
log4rs = { version = "1.0", optional = true }

View File

@@ -56,6 +56,12 @@ local-tunnel = ["local"]
# Enable socks4 protocol for sslocal
local-socks4 = ["local"]
# Enable Stream Cipher Protocol
# WARN: Stream Cipher Protocol is proved to be insecured
# https://github.com/shadowsocks/shadowsocks-rust/issues/373
# Users should always avoid using these ciphers in practice
stream-cipher = ["shadowsocks/stream-cipher"]
[dependencies]
log = "0.4"
log4rs = "1.0"

View File

@@ -44,6 +44,7 @@ pub async fn run(mut config: Config) -> io::Result<()> {
trace!("{:?}", config);
// Warning for Stream Ciphers
#[cfg(feature = "stream-cipher")]
for server in config.server.iter() {
if server.method().is_stream() {
warn!("stream cipher {} for server {} have inherent weaknesses (see discussion in https://github.com/shadowsocks/shadowsocks-org/issues/36). \

View File

@@ -31,6 +31,7 @@ pub async fn run(config: Config) -> io::Result<()> {
trace!("{:?}", config);
// Warning for Stream Ciphers
#[cfg(feature = "stream-cipher")]
for server in config.server.iter() {
if server.method().is_stream() {
warn!("stream cipher {} for server {} have inherent weaknesses (see discussion in https://github.com/shadowsocks/shadowsocks-org/issues/36). \

View File

@@ -21,6 +21,12 @@ default = [
# Uses trust-dns instead of tokio's builtin DNS resolver
trust-dns = ["trust-dns-resolver"]
# Enable Stream Cipher Protocol
# WARN: Stream Cipher Protocol is proved to be insecured
# https://github.com/shadowsocks/shadowsocks-rust/issues/373
# Users should always avoid using these ciphers in practice
stream-cipher = ["shadowsocks-crypto/v1-stream"]
[dependencies]
log = "0.4"
@@ -50,10 +56,10 @@ tokio = { version = "1.0", features = ["io-util", "macros", "net", "parking_lot"
trust-dns-resolver = { version = "0.20", optional = true }
[target.'cfg(any(target_arch = "x86_64", target_arch = "aarch64"))'.dependencies]
shadowsocks-crypto = { version = "0.1", features = ["ring"] }
shadowsocks-crypto = { version = "0.1.2", features = ["ring"] }
[target.'cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))'.dependencies]
shadowsocks-crypto = { version = "0.1", features = [] }
shadowsocks-crypto = { version = "0.1.2", features = [] }
[target.'cfg(windows)'.dependencies]

View File

@@ -16,15 +16,15 @@ use crate::{
crypto::v1::{random_iv_or_salt, CipherCategory, CipherKind},
};
use super::{
aead::{DecryptedReader as AeadDecryptedReader, EncryptedWriter as AeadEncryptedWriter},
stream::{DecryptedReader as StreamDecryptedReader, EncryptedWriter as StreamEncryptedWriter},
};
use super::aead::{DecryptedReader as AeadDecryptedReader, EncryptedWriter as AeadEncryptedWriter};
#[cfg(feature = "stream-cipher")]
use super::stream::{DecryptedReader as StreamDecryptedReader, EncryptedWriter as StreamEncryptedWriter};
/// Reader for reading encrypted data stream from shadowsocks' tunnel
pub enum DecryptedReader {
None,
Aead(AeadDecryptedReader),
#[cfg(feature = "stream-cipher")]
Stream(StreamDecryptedReader),
}
@@ -32,6 +32,7 @@ impl DecryptedReader {
/// Create a new reader for reading encrypted data
pub fn new(method: CipherKind, key: &[u8]) -> DecryptedReader {
match method.category() {
#[cfg(feature = "stream-cipher")]
CipherCategory::Stream => DecryptedReader::Stream(StreamDecryptedReader::new(method, key)),
CipherCategory::Aead => DecryptedReader::Aead(AeadDecryptedReader::new(method, key)),
CipherCategory::None => DecryptedReader::None,
@@ -51,6 +52,7 @@ impl DecryptedReader {
S: AsyncRead + Unpin + ?Sized,
{
match *self {
#[cfg(feature = "stream-cipher")]
DecryptedReader::Stream(ref mut reader) => reader.poll_read_decrypted(cx, context, stream, buf),
DecryptedReader::Aead(ref mut reader) => reader.poll_read_decrypted(cx, context, stream, buf),
DecryptedReader::None => Pin::new(stream).poll_read(cx, buf),
@@ -62,6 +64,7 @@ impl DecryptedReader {
pub enum EncryptedWriter {
None,
Aead(AeadEncryptedWriter),
#[cfg(feature = "stream-cipher")]
Stream(StreamEncryptedWriter),
}
@@ -69,6 +72,7 @@ impl EncryptedWriter {
/// Create a new writer for writing encrypted data
pub fn new(method: CipherKind, key: &[u8], nonce: &[u8]) -> EncryptedWriter {
match method.category() {
#[cfg(feature = "stream-cipher")]
CipherCategory::Stream => EncryptedWriter::Stream(StreamEncryptedWriter::new(method, key, nonce)),
CipherCategory::Aead => EncryptedWriter::Aead(AeadEncryptedWriter::new(method, key, nonce)),
CipherCategory::None => EncryptedWriter::None,
@@ -87,6 +91,7 @@ impl EncryptedWriter {
S: AsyncWrite + Unpin + ?Sized,
{
match *self {
#[cfg(feature = "stream-cipher")]
EncryptedWriter::Stream(ref mut writer) => writer.poll_write_encrypted(cx, stream, buf),
EncryptedWriter::Aead(ref mut writer) => writer.poll_write_encrypted(cx, stream, buf),
EncryptedWriter::None => Pin::new(stream).poll_write(cx, buf),
@@ -113,12 +118,14 @@ impl<S> CryptoStream<S> {
}
let prev_len = match category {
#[cfg(feature = "stream-cipher")]
CipherCategory::Stream => method.iv_len(),
CipherCategory::Aead => method.salt_len(),
CipherCategory::None => 0,
};
let iv = match category {
#[cfg(feature = "stream-cipher")]
CipherCategory::Stream => {
let local_iv = loop {
let mut iv = vec![0u8; prev_len];

View File

@@ -9,5 +9,6 @@ mod aead;
pub mod crypto_io;
pub mod proxy_listener;
pub mod proxy_stream;
#[cfg(feature = "stream-cipher")]
mod stream;
pub mod utils;

View File

@@ -116,7 +116,9 @@ where
pub fn alloc_encrypted_read_buffer(method: CipherKind) -> Box<[u8]> {
match method.category() {
CipherCategory::Aead => vec![0u8; super::aead::MAX_PACKET_SIZE + method.tag_len()].into_boxed_slice(),
CipherCategory::Stream | CipherCategory::None => vec![0u8; 1 << 14].into_boxed_slice(),
#[cfg(feature = "stream-cipher")]
CipherCategory::Stream => vec![0u8; 1 << 14].into_boxed_slice(),
CipherCategory::None => vec![0u8; 1 << 14].into_boxed_slice(),
}
}
@@ -124,6 +126,8 @@ pub fn alloc_encrypted_read_buffer(method: CipherKind) -> Box<[u8]> {
pub fn alloc_plain_read_buffer(method: CipherKind) -> Box<[u8]> {
match method.category() {
CipherCategory::Aead => vec![0u8; super::aead::MAX_PACKET_SIZE].into_boxed_slice(),
CipherCategory::Stream | CipherCategory::None => vec![0u8; 1 << 14].into_boxed_slice(),
#[cfg(feature = "stream-cipher")]
CipherCategory::Stream => vec![0u8; 1 << 14].into_boxed_slice(),
CipherCategory::None => vec![0u8; 1 << 14].into_boxed_slice(),
}
}

View File

@@ -46,11 +46,13 @@ pub fn encrypt_payload(
addr.write_to_buf(dst);
dst.put_slice(payload);
}
#[cfg(feature = "stream-cipher")]
CipherCategory::Stream => encrypt_payload_stream(context, method, key, addr, payload, dst),
CipherCategory::Aead => encrypt_payload_aead(context, method, key, addr, payload, dst),
}
}
#[cfg(feature = "stream-cipher")]
fn encrypt_payload_stream(
context: &Context,
method: CipherKind,
@@ -157,10 +159,13 @@ pub async fn decrypt_payload(
}
}
}
#[cfg(feature = "stream-cipher")]
CipherCategory::Stream => decrypt_payload_stream(context, method, key, payload).await,
CipherCategory::Aead => decrypt_payload_aead(context, method, key, payload).await,
}
}
#[cfg(feature = "stream-cipher")]
async fn decrypt_payload_stream(
context: &Context,
method: CipherKind,

View File

@@ -163,6 +163,7 @@ async fn tcp_tunnel_aead() {
.unwrap();
}
#[cfg(feature = "stream-cipher")]
#[tokio::test]
async fn tcp_tunnel_stream() {
let _ = env_logger::try_init();

View File

@@ -148,6 +148,7 @@ async fn udp_tunnel_aead() {
.unwrap();
}
#[cfg(feature = "stream-cipher")]
#[tokio::test]
async fn udp_tunnel_stream() {
let _ = env_logger::try_init();

View File

@@ -71,6 +71,7 @@ impl Socks5TestServer {
}
}
#[cfg(feature = "stream-cipher")]
#[tokio::test]
async fn socks5_relay_stream() {
let _ = env_logger::try_init();