From 2b007f7920de73f5a582a9a61ffca4c362e22ffa Mon Sep 17 00:00:00 2001 From: sergej jurecko Date: Tue, 5 Feb 2019 09:40:50 +0100 Subject: [PATCH 1/6] ios hashing --- commoncrypto-sys/Cargo.toml | 4 +- commoncrypto-sys/src/lib.rs | 13 ++- commoncrypto/Cargo.toml | 5 +- commoncrypto/src/hash.rs | 16 ++- commoncrypto/src/ios.rs | 218 ++++++++++++++++++++++++++++++++++++ commoncrypto/src/lib.rs | 8 ++ 6 files changed, 249 insertions(+), 15 deletions(-) create mode 100644 commoncrypto/src/ios.rs diff --git a/commoncrypto-sys/Cargo.toml b/commoncrypto-sys/Cargo.toml index 0f10a3ae..5cf07566 100644 --- a/commoncrypto-sys/Cargo.toml +++ b/commoncrypto-sys/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "commoncrypto-sys" -version = "0.2.0" +version = "0.2.1" authors = ["Mark Lee"] description = "FFI bindings to Mac OS X's CommonCrypto library" documentation = "https://docs.rs/commoncrypto-sys" @@ -14,8 +14,6 @@ travis-ci = { repository = "malept/rust-commoncrypto" } lint = ["clippy"] [dependencies] -libc = "0.2" - clippy = { version = "0.0", optional = true } [dev-dependencies] diff --git a/commoncrypto-sys/src/lib.rs b/commoncrypto-sys/src/lib.rs index ac02ee47..be440c43 100644 --- a/commoncrypto-sys/src/lib.rs +++ b/commoncrypto-sys/src/lib.rs @@ -22,9 +22,7 @@ #![warn(missing_docs)] -extern crate libc; - -use libc::{c_int, c_uint}; +use std::os::raw::{c_int, c_uint}; /// Total number of operations. const MD5_CBLOCK: usize = 64; @@ -85,7 +83,7 @@ macro_rules! cc_sha2_struct { hash: [$ty; 8], wbuf: [$ty; 16], } - } + }; } cc_sha2_struct!(CC_SHA256_CTX, u32); @@ -103,12 +101,16 @@ pub enum CCDigestAlgorithm { kCCDigestMD4 = 2, /// MD5 kCCDigestMD5 = 3, + #[cfg(target_os = "macos")] /// RIPEMD-128 kCCDigestRMD128 = 4, + #[cfg(target_os = "macos")] /// RIPEMD-160 kCCDigestRMD160 = 5, + #[cfg(target_os = "macos")] /// RIPEMD-256 kCCDigestRMD256 = 6, + #[cfg(target_os = "macos")] /// RIPEMD-320 kCCDigestRMD320 = 7, /// SHA1 @@ -199,6 +201,9 @@ extern "C" { pub fn CC_SHA512_Update(ctx: *mut CC_SHA512_CTX, data: *const u8, n: usize) -> c_int; /// Generates SHA512 hash. See `man 3cc CC_SHA` for details. pub fn CC_SHA512_Final(md: *mut u8, ctx: *mut CC_SHA512_CTX) -> c_int; +} +#[cfg(target_os = "macos")] +extern "C" { /// Generic digest hasher. pub fn CCDigest( algorithm: CCDigestAlgorithm, diff --git a/commoncrypto/Cargo.toml b/commoncrypto/Cargo.toml index 9301fc88..c974e4d1 100644 --- a/commoncrypto/Cargo.toml +++ b/commoncrypto/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "commoncrypto" -version = "0.2.0" +version = "0.2.1" authors = ["Mark Lee"] description = "Idiomatic Rust wrappers for Mac OS X's CommonCrypto library" documentation = "https://docs.rs/commoncrypto" @@ -11,11 +11,12 @@ license = "MIT" travis-ci = { repository = "malept/rust-commoncrypto" } [features] +# default = ["ios-compat"] +ios-compat = [] lint = ["clippy"] [dependencies] commoncrypto-sys = { version = "0.2.0", path = "../commoncrypto-sys" } - clippy = { version = "0.0", optional = true } [dev-dependencies] diff --git a/commoncrypto/src/hash.rs b/commoncrypto/src/hash.rs index a30ee4d1..cd88ec16 100644 --- a/commoncrypto/src/hash.rs +++ b/commoncrypto/src/hash.rs @@ -20,19 +20,23 @@ //! Idiomatic Rust wrapper for `CommonCrypto`'s `CCDigestCtx` struct. -use commoncrypto_sys::{CCDigestCreate, CCDigestCtx, CCDigestDestroy, CCDigestFinal, - CCDigestGetOutputSizeFromRef, CCDigestReset, CCDigestUpdate}; +use commoncrypto_sys::{ + CCDigestCreate, CCDigestCtx, CCDigestDestroy, CCDigestFinal, CCDigestGetOutputSizeFromRef, + CCDigestReset, CCDigestUpdate, +}; use std::io; pub use commoncrypto_sys::CCDigestAlgorithm; const MAX_DIGEST_SIZE: usize = 64; -macro_rules! err_from_ccdigest_retval{ +macro_rules! err_from_ccdigest_retval { ($func_name: expr, $val: expr) => { - Err(io::Error::new(io::ErrorKind::Other, - format!("{} returned nonzero: {}", $func_name, $val))) - } + Err(io::Error::new( + io::ErrorKind::Other, + format!("{} returned nonzero: {}", $func_name, $val), + )) + }; } #[derive(PartialEq, Copy, Clone, Debug)] diff --git a/commoncrypto/src/ios.rs b/commoncrypto/src/ios.rs new file mode 100644 index 00000000..d8217cd0 --- /dev/null +++ b/commoncrypto/src/ios.rs @@ -0,0 +1,218 @@ +// Copyright (c) 2016 Mark Lee +// +// 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. + +//! Idiomatic Rust wrapper for `CommonCrypto`'s `CCDigestCtx` struct. + +use commoncrypto_sys::*; +use std::io; +use std::os::raw::{c_int, c_void}; + +pub use commoncrypto_sys::CCDigestAlgorithm; + +const MAX_DIGEST_SIZE: usize = 64; + +macro_rules! err_from_ccdigest_retval { + ($func_name: expr, $val: expr) => { + Err(io::Error::new( + io::ErrorKind::Other, + format!("{} returned nonzero: {}", $func_name, $val), + )) + }; +} + +#[derive(PartialEq, Copy, Clone, Debug)] +enum State { + Reset, + Updated, + Finalized, +} + +#[derive(Debug)] +enum AlgoData { + None, + MD5(CC_MD5_CTX), + SHA(CC_SHA512_CTX), +} + +impl AlgoData { + fn as_ptr(&mut self) -> *mut c_void { + match self { + AlgoData::None => std::ptr::null_mut(), + AlgoData::MD5(ref mut md5) => md5 as *mut CC_MD5_CTX as *mut c_void, + AlgoData::SHA(ref mut sha) => sha as *mut CC_SHA512_CTX as *mut c_void, + } + } +} + +/// Generates cryptographic hashes. +#[derive(Debug)] +pub struct Hasher { + state: State, + ctx: AlgoData, + init_f: unsafe extern "C" fn(*mut c_void) -> c_int, + update_f: unsafe extern "C" fn(*mut c_void, *const u8, usize) -> c_int, + final_f: unsafe extern "C" fn(*mut u8, *mut c_void) -> c_int, + len: usize, +} + +impl Hasher { + /// Creates a new `Hasher` which will use the given cryptographic `algorithm`. + pub fn new(algorithm: CCDigestAlgorithm) -> Hasher { + unsafe { + let mut out = match algorithm { + CCDigestAlgorithm::kCCDigestMD5 => Hasher { + state: State::Reset, + ctx: AlgoData::MD5(CC_MD5_CTX::default()), + init_f: std::mem::transmute(CC_MD5_Init as usize), + update_f: std::mem::transmute(CC_MD5_Update as usize), + final_f: std::mem::transmute(CC_MD5_Final as usize), + len: MD5_DIGEST_LENGTH, + }, + CCDigestAlgorithm::kCCDigestSHA1 => Hasher { + state: State::Reset, + ctx: AlgoData::SHA(CC_SHA512_CTX::default()), + init_f: std::mem::transmute(CC_SHA1_Init as usize), + update_f: std::mem::transmute(CC_SHA1_Update as usize), + final_f: std::mem::transmute(CC_SHA1_Final as usize), + len: SHA1_DIGEST_LENGTH, + }, + CCDigestAlgorithm::kCCDigestSHA256 => Hasher { + state: State::Reset, + ctx: AlgoData::SHA(CC_SHA512_CTX::default()), + init_f: std::mem::transmute(CC_SHA256_Init as usize), + update_f: std::mem::transmute(CC_SHA256_Update as usize), + final_f: std::mem::transmute(CC_SHA256_Final as usize), + len: SHA256_DIGEST_LENGTH, + }, + CCDigestAlgorithm::kCCDigestSHA384 => Hasher { + state: State::Reset, + ctx: AlgoData::SHA(CC_SHA512_CTX::default()), + init_f: std::mem::transmute(CC_SHA384_Init as usize), + update_f: std::mem::transmute(CC_SHA384_Update as usize), + final_f: std::mem::transmute(CC_SHA384_Final as usize), + len: SHA384_DIGEST_LENGTH, + }, + CCDigestAlgorithm::kCCDigestSHA512 => Hasher { + state: State::Reset, + ctx: AlgoData::SHA(CC_SHA512_CTX::default()), + init_f: std::mem::transmute(CC_SHA512_Init as usize), + update_f: std::mem::transmute(CC_SHA512_Update as usize), + final_f: std::mem::transmute(CC_SHA512_Final as usize), + len: SHA512_DIGEST_LENGTH, + }, + _ => Hasher { + state: State::Reset, + ctx: AlgoData::None, + init_f: std::mem::transmute(CC_SHA512_Init as usize), + update_f: std::mem::transmute(CC_SHA512_Update as usize), + final_f: std::mem::transmute(CC_SHA512_Final as usize), + len: 0, + }, + }; + (out.init_f)(out.ctx.as_ptr()); + out + } + } + + fn init(&mut self) { + match self.state { + State::Reset => return, + State::Updated => { + let _ = self.finish(); + } + State::Finalized => (), + } + match self.ctx { + AlgoData::MD5(_) => { + self.ctx = AlgoData::MD5(CC_MD5_CTX::default()); + } + AlgoData::SHA(_) => { + self.ctx = AlgoData::SHA(CC_SHA512_CTX::default()); + } + AlgoData::None => {} + } + self.state = State::Reset; + unsafe { (self.init_f)(self.ctx.as_ptr()) }; + } + + /// Feeds data into the hasher. + pub fn update(&mut self, data: &[u8]) -> io::Result { + if self.state == State::Finalized { + self.init(); + } + match self.ctx { + AlgoData::None => { + return Ok(0); + } + _ => {} + } + let result = + unsafe { (self.update_f)(self.ctx.as_ptr(), data.as_ptr() as *mut _, data.len()) }; + if result == 1 { + self.state = State::Updated; + Ok(data.len()) + } else { + err_from_ccdigest_retval!("digest_update", result) + } + } + + /// Finalizes digest operations and produces the digest output. + pub fn finish(&mut self) -> io::Result> { + if self.state == State::Finalized { + self.init(); + } + match self.ctx { + AlgoData::None => { + return Ok(Vec::new()); + } + _ => {} + } + let mut md = vec![0; MAX_DIGEST_SIZE]; + // let result = unsafe { CCDigestFinal(self.ctx, md.as_mut_ptr()) }; + let result = unsafe { (self.final_f)(md.as_mut_ptr(), self.ctx.as_ptr()) }; + if result == 1 { + self.state = State::Finalized; + md.truncate(self.len); + Ok(md) + } else { + err_from_ccdigest_retval!("digest_final", result) + } + } +} + +impl io::Write for Hasher { + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result { + self.update(buf) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +impl Drop for Hasher { + fn drop(&mut self) { + if self.state != State::Finalized { + let _ = self.finish(); + } + // unsafe { CCDigestDestroy(self.ctx) } + } +} diff --git a/commoncrypto/src/lib.rs b/commoncrypto/src/lib.rs index 3b58f915..b66a0188 100644 --- a/commoncrypto/src/lib.rs +++ b/commoncrypto/src/lib.rs @@ -25,6 +25,14 @@ extern crate commoncrypto_sys; #[warn(missing_docs)] +#[cfg(all(target_os = "macos", not(feature = "ios-compat")))] pub mod hash; #[warn(missing_docs)] +#[cfg(all(target_os = "macos", not(feature = "ios-compat")))] pub mod pbkdf2; + +#[warn(missing_docs)] +#[cfg(any(target_os = "ios", feature = "ios-compat"))] +pub mod ios; +#[cfg(any(target_os = "ios", feature = "ios-compat"))] +pub use ios as hash; From 489b657d4beba8044a2931467a59870fabb7f8e0 Mon Sep 17 00:00:00 2001 From: sergej jurecko Date: Tue, 5 Feb 2019 09:43:28 +0100 Subject: [PATCH 2/6] also disable md2 md4 --- commoncrypto-sys/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/commoncrypto-sys/src/lib.rs b/commoncrypto-sys/src/lib.rs index be440c43..1bc1ca6a 100644 --- a/commoncrypto-sys/src/lib.rs +++ b/commoncrypto-sys/src/lib.rs @@ -95,8 +95,10 @@ cc_sha2_struct!(CC_SHA512_CTX, u64); pub enum CCDigestAlgorithm { /// No digest algorithm kCCDigestNone = 0, + #[cfg(target_os = "macos")] /// MD2 kCCDigestMD2 = 1, + #[cfg(target_os = "macos")] /// MD4 kCCDigestMD4 = 2, /// MD5 From e2f36761f52300f56db3c9237530219b85269668 Mon Sep 17 00:00:00 2001 From: sergej jurecko Date: Tue, 5 Feb 2019 09:54:02 +0100 Subject: [PATCH 3/6] no vers bump --- commoncrypto-sys/Cargo.toml | 2 +- commoncrypto/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/commoncrypto-sys/Cargo.toml b/commoncrypto-sys/Cargo.toml index 5cf07566..c6bf14d6 100644 --- a/commoncrypto-sys/Cargo.toml +++ b/commoncrypto-sys/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "commoncrypto-sys" -version = "0.2.1" +version = "0.2.0" authors = ["Mark Lee"] description = "FFI bindings to Mac OS X's CommonCrypto library" documentation = "https://docs.rs/commoncrypto-sys" diff --git a/commoncrypto/Cargo.toml b/commoncrypto/Cargo.toml index c974e4d1..5236157d 100644 --- a/commoncrypto/Cargo.toml +++ b/commoncrypto/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "commoncrypto" -version = "0.2.1" +version = "0.2.0" authors = ["Mark Lee"] description = "Idiomatic Rust wrappers for Mac OS X's CommonCrypto library" documentation = "https://docs.rs/commoncrypto" From 57ea89af2e6f3bd46acd54e88e2ead1bb97b146c Mon Sep 17 00:00:00 2001 From: Mark Lee Date: Tue, 20 Aug 2019 08:32:10 -0700 Subject: [PATCH 4/6] chore: move features block to the bottom --- commoncrypto/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/commoncrypto/Cargo.toml b/commoncrypto/Cargo.toml index d24369f5..e7c02a53 100644 --- a/commoncrypto/Cargo.toml +++ b/commoncrypto/Cargo.toml @@ -9,9 +9,6 @@ keywords = ["crypto", "hash", "digest", "osx", "commoncrypto"] categories = ["cryptography", "api-bindings", "os::macos-apis"] license = "MIT" -[features] -# default = ["ios-compat"] - [badges] travis-ci = { repository = "malept/rust-commoncrypto" } @@ -20,3 +17,6 @@ commoncrypto-sys = { version = "0.2.0", path = "../commoncrypto-sys" } [dev-dependencies] hex = "0.3" + +[features] +# default = ["ios-compat"] From fc7b0c4127dca8b8758f277e8dc5098b14d13da5 Mon Sep 17 00:00:00 2001 From: Mark Lee Date: Tue, 20 Aug 2019 08:51:08 -0700 Subject: [PATCH 5/6] build: add compile-only stage for iOS targets on Travis --- .travis.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.travis.yml b/.travis.yml index b7bc218d..95bebb5a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,6 +17,12 @@ jobs: - osx_image: xcode8 # 10.11 - osx_image: xcode9.2 # 10.12 - osx_image: xcode10.1 # 10.13 + - stage: compile-only + env: TARGET=aarch64-apple-ios DISABLE_TESTS=1 + - env: TARGET=armv7-apple-ios DISABLE_TESTS=1 + - env: TARGET=armv7s-apple-ios DISABLE_TESTS=1 + - env: TARGET=i386-apple-ios DISABLE_TESTS=1 + - env: TARGET=x86_64-apple-ios DISABLE_TESTS=1 matrix: allow_failures: @@ -30,6 +36,7 @@ branches: stages: - style-docs - compile-test +- compile-only before_script: ci/before_script.sh script: ci/script.sh From 173d5e76fd3b226376624dfd4349fc6ed9f5cc1c Mon Sep 17 00:00:00 2001 From: Mark Lee Date: Tue, 20 Aug 2019 09:21:52 -0700 Subject: [PATCH 6/6] build: remove return --- ci/script.sh | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/ci/script.sh b/ci/script.sh index 845693c1..5db3f850 100755 --- a/ci/script.sh +++ b/ci/script.sh @@ -26,10 +26,8 @@ else cross build --target $TARGET cross build --target $TARGET --release - if [ ! -z $DISABLE_TESTS ]; then - return + if [ -z $DISABLE_TESTS ]; then + cross test --target $TARGET + cross test --target $TARGET --release fi - - cross test --target $TARGET - cross test --target $TARGET --release fi