mirror of
https://github.com/shadowsocks/shadowsocks-rust.git
synced 2026-11-06 16:14:11 +00:00
add rc4-md5 method, fixed bugs
This commit is contained in:
+4
-3
@@ -16,6 +16,8 @@ default = [
|
||||
"cipher-cast5-cfb",
|
||||
"cipher-des-cfb",
|
||||
"cipher-rc2-cfb",
|
||||
"cipher-rc4",
|
||||
"cipher-rc4-md5",
|
||||
]
|
||||
|
||||
cipher-aes-cfb = []
|
||||
@@ -27,6 +29,8 @@ cipher-cast5-cfb = []
|
||||
cipher-des-cfb = []
|
||||
cipher-idea-cfb = []
|
||||
cipher-rc2-cfb = []
|
||||
cipher-rc4 = []
|
||||
cipher-rc4-md5 = []
|
||||
cipher-seed-cfb = []
|
||||
|
||||
[[bin]]
|
||||
@@ -38,6 +42,3 @@ path = "src/bin/local.rs"
|
||||
|
||||
name = "ssserver"
|
||||
path = "src/bin/server.rs"
|
||||
|
||||
[dependencies.rust-crypto]
|
||||
git = "https://github.com/DaGenix/rust-crypto.git"
|
||||
|
||||
+11
-2
@@ -88,10 +88,14 @@ pub const CIPHER_DES_CFB: &'static str = "des-cfb";
|
||||
pub const CIPHER_IDEA_CFB: &'static str = "idea-cfb";
|
||||
#[cfg(feature="cipher-rc2-cfb")]
|
||||
pub const CIPHER_RC2_CFB: &'static str = "rc2-cfb";
|
||||
#[cfg(feature="cipher-rc4")]
|
||||
pub const CIPHER_RC4: &'static str = "rc4";
|
||||
#[cfg(feature="cipher-rc4-md5")]
|
||||
pub const CIPHER_RC4_MD5: &'static str = "rc4-md5";
|
||||
#[cfg(feature="cipher-seed-cfb")]
|
||||
pub const CIPHER_SEED_CFB: &'static str = "seed-cfb";
|
||||
|
||||
#[deriving(Clone)]
|
||||
#[deriving(Clone, Show)]
|
||||
pub enum CipherType {
|
||||
CipherTypeUnknown,
|
||||
|
||||
@@ -128,7 +132,8 @@ pub enum CipherType {
|
||||
#[cfg(feature="cipher-des-cfb")] CipherTypeDesCfb,
|
||||
#[cfg(feature="cipher-idea-cfb")] CipherTypeIdeaCfb,
|
||||
#[cfg(feature="cipher-rc2-cfb")] CipherTypeRc2Cfb,
|
||||
#[cfg(feature="cipher-rc4-hmac-md5")] CipherTypeRc4HmacMd5,
|
||||
#[cfg(feature="cipher-rc4")] CipherTypeRc4,
|
||||
#[cfg(feature="cipher-rc4-md5")] CipherTypeRc4Md5,
|
||||
#[cfg(feature="cipher-seed-cfb")] CipherTypeSeedCfb,
|
||||
}
|
||||
|
||||
@@ -234,6 +239,10 @@ pub fn with_name(method: &str, key: &[u8]) -> Option<CipherVariant> {
|
||||
CIPHER_IDEA_CFB => Some(OpenSSLCrypto(openssl::OpenSSLCipher::new(CipherTypeIdeaCfb, key))),
|
||||
#[cfg(feature="cipher-rc2-cfb")]
|
||||
CIPHER_RC2_CFB => Some(OpenSSLCrypto(openssl::OpenSSLCipher::new(CipherTypeRc2Cfb, key))),
|
||||
#[cfg(feature="cipher-rc4")]
|
||||
CIPHER_RC4 => Some(OpenSSLCrypto(openssl::OpenSSLCipher::new(CipherTypeRc4, key))),
|
||||
#[cfg(feature="cipher-rc4-md5")]
|
||||
CIPHER_RC4_MD5 => Some(OpenSSLCrypto(openssl::OpenSSLCipher::new(CipherTypeRc4Md5, key))),
|
||||
#[cfg(feature="cipher-seed-cfb")]
|
||||
CIPHER_SEED_CFB => Some(OpenSSLCrypto(openssl::OpenSSLCipher::new(CipherTypeSeedCfb, key))),
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2014 Y. T. CHUNG
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
pub trait Digest {
|
||||
fn update(&mut self, data: &[u8]);
|
||||
fn digest(&mut self) -> Vec<u8>;
|
||||
}
|
||||
|
||||
#[deriving(Clone)]
|
||||
pub enum DigestType {
|
||||
Md5,
|
||||
Sha1,
|
||||
Sha,
|
||||
UnknownDigest,
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -23,8 +23,7 @@
|
||||
|
||||
extern crate libc;
|
||||
extern crate test;
|
||||
extern crate "rust-crypto" as rust_crypto;
|
||||
|
||||
pub mod cipher;
|
||||
pub mod openssl;
|
||||
pub mod rust;
|
||||
pub mod digest;
|
||||
|
||||
+151
-4
@@ -28,6 +28,9 @@ extern crate test;
|
||||
use crypto::cipher::Cipher;
|
||||
use crypto::cipher;
|
||||
|
||||
use crypto::digest::Digest;
|
||||
use crypto::digest;
|
||||
|
||||
use std::ptr;
|
||||
use std::clone::Clone;
|
||||
use std::mem::swap;
|
||||
@@ -37,6 +40,8 @@ type EVP_CIPHER_CTX = *const libc::c_void;
|
||||
#[allow(non_camel_case_types)]
|
||||
type EVP_CIPHER = *const libc::c_void;
|
||||
#[allow(non_camel_case_types)]
|
||||
type EVP_MD_CTX = *mut libc::c_void;
|
||||
#[allow(non_camel_case_types)]
|
||||
type EVP_MD = *const libc::c_void;
|
||||
#[allow(non_camel_case_types)]
|
||||
type ENGINE = *const libc::c_void;
|
||||
@@ -118,13 +123,125 @@ extern {
|
||||
fn EVP_rc2_cfb64() -> EVP_CIPHER;
|
||||
#[cfg(feature="cipher-seed-cfb")]
|
||||
fn EVP_seed_cfb128() -> EVP_CIPHER;
|
||||
#[cfg(any(feature="cipher-rc4", feature="cipher-rc4-md5"))]
|
||||
fn EVP_rc4() -> EVP_CIPHER;
|
||||
|
||||
// MD
|
||||
fn EVP_MD_CTX_create() -> EVP_MD_CTX;
|
||||
fn EVP_MD_CTX_init(ctx: EVP_MD_CTX);
|
||||
fn EVP_MD_CTX_cleanup(ctx: EVP_MD_CTX);
|
||||
fn EVP_MD_CTX_destroy(ctx: EVP_MD_CTX);
|
||||
fn EVP_MD_CTX_copy_ex(out: EVP_MD_CTX, ctx_in: EVP_MD_CTX) -> libc::c_int;
|
||||
fn EVP_DigestInit_ex(ctx: EVP_MD_CTX, md_type: EVP_MD, engine: ENGINE) -> libc::c_int;
|
||||
fn EVP_DigestUpdate(ctx: EVP_MD_CTX, d: *const libc::c_void, cnt: libc::size_t) -> libc::c_int;
|
||||
fn EVP_DigestFinal_ex(ctx: EVP_MD_CTX, md: *mut libc::c_uchar, s: *mut libc::c_uint);
|
||||
|
||||
fn EVP_md5() -> EVP_MD;
|
||||
fn EVP_sha() -> EVP_MD;
|
||||
fn EVP_sha1() -> EVP_MD;
|
||||
}
|
||||
|
||||
struct OpenSSLDigest {
|
||||
md_ctx: EVP_MD_CTX,
|
||||
digest_len: uint,
|
||||
}
|
||||
|
||||
impl OpenSSLDigest {
|
||||
pub fn new(t: digest::DigestType) -> OpenSSLDigest {
|
||||
let ctx = unsafe {
|
||||
let md_ctx = EVP_MD_CTX_create();
|
||||
assert!(!md_ctx.is_null());
|
||||
EVP_MD_CTX_init(md_ctx);
|
||||
md_ctx
|
||||
};
|
||||
|
||||
let dlen = unsafe {
|
||||
let (md, len) = OpenSSLDigest::get_md(t);
|
||||
EVP_DigestInit_ex(ctx, md, ptr::null());
|
||||
len
|
||||
};
|
||||
|
||||
OpenSSLDigest {
|
||||
md_ctx: ctx,
|
||||
digest_len: dlen,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_md(t: digest::DigestType) -> (EVP_MD, uint) {
|
||||
unsafe {
|
||||
match t {
|
||||
digest::Md5 => { (EVP_md5(), 16u) },
|
||||
digest::Sha => { (EVP_sha(), 20u) },
|
||||
digest::Sha1 => { (EVP_sha1(), 20u) },
|
||||
|
||||
digest::UnknownDigest => { (ptr::null(), 0u) },
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Digest for OpenSSLDigest {
|
||||
fn update(&mut self, data: &[u8]) {
|
||||
unsafe {
|
||||
if EVP_DigestUpdate(self.md_ctx, data.as_ptr() as *const libc::c_void, data.len() as libc::size_t)
|
||||
!= 1 as libc::c_int {
|
||||
fail!("Failed to call EVP_DigestUpdate");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn digest(&mut self) -> Vec<u8> {
|
||||
let mut dig = Vec::from_elem(self.digest_len, 0u8);
|
||||
unsafe {
|
||||
EVP_DigestFinal_ex(self.md_ctx, dig.as_mut_ptr(), ptr::null_mut());
|
||||
}
|
||||
dig
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for OpenSSLDigest {
|
||||
fn clone(&self) -> OpenSSLDigest {
|
||||
let ctx = unsafe {
|
||||
let md_ctx = EVP_MD_CTX_create();
|
||||
assert!(!md_ctx.is_null());
|
||||
if EVP_MD_CTX_copy_ex(md_ctx, self.md_ctx) != 1 as libc::c_int {
|
||||
EVP_MD_CTX_destroy(md_ctx);
|
||||
fail!("Failed to call EVP_MD_CTX_copy_ex");
|
||||
}
|
||||
md_ctx
|
||||
};
|
||||
OpenSSLDigest {
|
||||
md_ctx: ctx,
|
||||
digest_len: self.digest_len,
|
||||
}
|
||||
}
|
||||
|
||||
fn clone_from(&mut self, source: &OpenSSLDigest) {
|
||||
self.md_ctx = unsafe {
|
||||
let md_ctx = EVP_MD_CTX_create();
|
||||
assert!(!md_ctx.is_null());
|
||||
if EVP_MD_CTX_copy_ex(md_ctx, source.md_ctx) != 1 as libc::c_int {
|
||||
EVP_MD_CTX_destroy(md_ctx);
|
||||
fail!("Failed to call EVP_MD_CTX_copy_ex");
|
||||
}
|
||||
EVP_MD_CTX_cleanup(self.md_ctx);
|
||||
EVP_MD_CTX_destroy(self.md_ctx);
|
||||
md_ctx
|
||||
};
|
||||
self.digest_len = source.digest_len;
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe_destructor]
|
||||
impl Drop for OpenSSLDigest {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
EVP_MD_CTX_cleanup(self.md_ctx);
|
||||
EVP_MD_CTX_destroy(self.md_ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This two modes will be converted into the last parameter of `EVP_CipherInit_ex`.
|
||||
enum CryptoMode {
|
||||
CryptoModeDecrypt,
|
||||
@@ -159,7 +276,7 @@ impl OpenSSLCrypto {
|
||||
let (ctx, _, block_size) = unsafe {
|
||||
let (cipher, key_size, block_size) = OpenSSLCrypto::get_cipher(cipher_type);
|
||||
|
||||
assert!(iv.len() >= block_size);
|
||||
// assert!(iv.len() >= block_size);
|
||||
|
||||
let evp_ctx = EVP_CIPHER_CTX_new();
|
||||
assert!(!evp_ctx.is_null());
|
||||
@@ -253,6 +370,10 @@ impl OpenSSLCrypto {
|
||||
cipher::CipherTypeRc2Cfb => { (EVP_rc2_cfb64(), 16, 8) },
|
||||
#[cfg(feature="cipher-seed-cfb")]
|
||||
cipher::CipherTypeSeedCfb => { (EVP_seed_cfb128(), 16, 16) },
|
||||
#[cfg(feature="cipher-rc4")]
|
||||
cipher::CipherTypeRc4 => { (EVP_rc4(), 16, 16) },
|
||||
#[cfg(feature="cipher-rc4-md5")]
|
||||
cipher::CipherTypeRc4Md5 => { (EVP_rc4(), 16, 16) },
|
||||
|
||||
cipher::CipherTypeUnknown => { (ptr::null(), 0, 0) },
|
||||
}
|
||||
@@ -366,11 +487,25 @@ impl Cipher for OpenSSLCipher {
|
||||
match self.encryptor {
|
||||
Some(ref encryptor) => { encryptor.update(data) },
|
||||
None => {
|
||||
let (key, mut iv) = OpenSSLCrypto::bytes_to_key(
|
||||
let (key, mut iv) = {
|
||||
let (key, iv) = OpenSSLCrypto::bytes_to_key(
|
||||
self.cipher_type,
|
||||
self.key.as_slice()
|
||||
);
|
||||
|
||||
match self.cipher_type {
|
||||
cipher::CipherTypeRc4Md5 => {
|
||||
let mut md5_digest = OpenSSLDigest::new(digest::Md5);
|
||||
md5_digest.update(key.as_slice());
|
||||
md5_digest.update(iv.as_slice());
|
||||
(md5_digest.digest(), iv)
|
||||
},
|
||||
_ => {
|
||||
(key, iv)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let encryptor = OpenSSLCrypto::new(self.cipher_type, key.as_slice(), iv.as_slice(), CryptoModeEncrypt);
|
||||
self.encryptor = Some(encryptor);
|
||||
|
||||
@@ -387,15 +522,27 @@ impl Cipher for OpenSSLCipher {
|
||||
match self.decryptor {
|
||||
Some(ref decryptor) => { decryptor.update(data) },
|
||||
None => {
|
||||
let (key, iv) = OpenSSLCrypto::bytes_to_key(
|
||||
let (_, _, expected_iv_len) = OpenSSLCrypto::get_cipher(self.cipher_type);
|
||||
let (pad_key, _) = OpenSSLCrypto::bytes_to_key(
|
||||
self.cipher_type,
|
||||
self.key.as_slice()
|
||||
);
|
||||
|
||||
// Get the begining IV from the data
|
||||
let expected_iv_len = iv.len();
|
||||
let (real_iv, data) = data.split_at(expected_iv_len);
|
||||
|
||||
let key = match self.cipher_type {
|
||||
cipher::CipherTypeRc4Md5 => {
|
||||
let mut md5_digest = OpenSSLDigest::new(digest::Md5);
|
||||
md5_digest.update(pad_key.as_slice());
|
||||
md5_digest.update(real_iv.as_slice());
|
||||
md5_digest.digest()
|
||||
},
|
||||
_ => {
|
||||
pad_key
|
||||
}
|
||||
};
|
||||
|
||||
let decryptor = OpenSSLCrypto::new(self.cipher_type, key.as_slice(), real_iv, CryptoModeDecrypt);
|
||||
self.decryptor = Some(decryptor);
|
||||
|
||||
|
||||
@@ -29,8 +29,6 @@ extern crate serialize;
|
||||
#[phase(plugin, link)]
|
||||
extern crate log;
|
||||
|
||||
extern crate native;
|
||||
|
||||
pub const VERSION: &'static str = "0.9.0";
|
||||
|
||||
pub mod config;
|
||||
|
||||
Reference in New Issue
Block a user