Add a feature flag to omit ASM dependencies

Compiling the ASM dependencies has turned out to be a major pain point.
This commit adds a feature flag to optionally disable support for all
algorithms that require ASM.
diff --git a/Cargo.toml b/Cargo.toml
index 2123253..b401776 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -14,7 +14,9 @@
 name = "crypto"
 
 [features]
+default = ["with-asm"]
 with-bench = []
+with-asm = []
 
 [build-dependencies]
 gcc = "^0.3"
diff --git a/build.rs b/build.rs
index 92dd2b6..a77ba27 100644
--- a/build.rs
+++ b/build.rs
@@ -10,32 +10,33 @@
 use std::path::Path;
 
 fn main() {
-    let target = env::var("TARGET").unwrap();
-    let host = env::var("HOST").unwrap();
-    if target.contains("msvc") && host.contains("windows") {
-        let mut config = gcc::Config::new();
-        config.file("src/util_helpers.asm");
-        config.file("src/aesni_helpers.asm");
-        if target.contains("x86_64") {
-            config.define("X64", None);
-        }
-        config.compile("lib_rust_crypto_helpers.a");
-    }
-    else {
-        let mut cfg = gcc::Config::new();
-        cfg.file("src/util_helpers.c");
-        cfg.file("src/aesni_helpers.c");
-        if env::var_os("CC").is_none() {
-            if host.contains("openbsd") {
-                // Use clang on openbsd since there have been reports that
-                // GCC doesn't like some of the assembly that we use on that
-                // platform.
-                cfg.compiler(Path::new("clang"));
-            } else if target == host {
-                cfg.compiler(Path::new("cc"));
+    if env::var("CARGO_FEATURE_WITH_ASM").is_ok() {
+        let target = env::var("TARGET").unwrap();
+        let host = env::var("HOST").unwrap();
+        if target.contains("msvc") && host.contains("windows") {
+            let mut config = gcc::Config::new();
+            config.file("src/util_helpers.asm");
+            config.file("src/aesni_helpers.asm");
+            if target.contains("x86_64") {
+                config.define("X64", None);
             }
+            config.compile("lib_rust_crypto_helpers.a");
         }
-        cfg.compile("lib_rust_crypto_helpers.a");
+        else {
+            let mut cfg = gcc::Config::new();
+            cfg.file("src/util_helpers.c");
+            cfg.file("src/aesni_helpers.c");
+            if env::var_os("CC").is_none() {
+                if host.contains("openbsd") {
+                    // Use clang on openbsd since there have been reports that
+                    // GCC doesn't like some of the assembly that we use on that
+                    // platform.
+                    cfg.compiler(Path::new("clang"));
+                } else if target == host {
+                    cfg.compiler(Path::new("cc"));
+                }
+            }
+            cfg.compile("lib_rust_crypto_helpers.a");
+        }
     }
 }
-
diff --git a/src/aes.rs b/src/aes.rs
index 1de8c56..f10867a 100644
--- a/src/aes.rs
+++ b/src/aes.rs
@@ -4,13 +4,17 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+#[cfg(all(feature = "with-asm", any(target_arch = "x86", target_arch = "x86_64")))]
 use aesni;
 
 use aessafe;
-use blockmodes::{PaddingProcessor, EcbEncryptor, EcbDecryptor, CbcEncryptor, CbcDecryptor, CtrMode,
+use blockmodes::{PaddingProcessor, EcbEncryptor, EcbDecryptor, CbcEncryptor, CbcDecryptor,
     CtrModeX8};
+#[cfg(all(feature = "with-asm", any(target_arch = "x86", target_arch = "x86_64")))]
+use blockmodes::CtrMode;
 use symmetriccipher::{Encryptor, Decryptor, SynchronousStreamCipher};
+
+#[cfg(feature = "with-asm")]
 use util;
 
 /// AES key size
@@ -22,7 +26,7 @@
 }
 
 /// Get the best implementation of an EcbEncryptor
-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+#[cfg(all(feature = "with-asm", any(target_arch = "x86", target_arch = "x86_64")))]
 pub fn ecb_encryptor<X: PaddingProcessor + Send + 'static>(
         key_size: KeySize,
         key: &[u8],
@@ -53,7 +57,7 @@
 }
 
 /// Get the best implementation of an EcbEncryptor
-#[cfg(all(not(target_arch = "x86"), not(target_arch = "x86_64")))]
+#[cfg(any(not(feature = "with-asm"), all(not(target_arch = "x86"), not(target_arch = "x86_64"))))]
 pub fn ecb_encryptor<X: PaddingProcessor + Send + 'static>(
         key_size: KeySize,
         key: &[u8],
@@ -78,7 +82,7 @@
 }
 
 /// Get the best implementation of an EcbDecryptor
-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+#[cfg(all(feature = "with-asm", any(target_arch = "x86", target_arch = "x86_64")))]
 pub fn ecb_decryptor<X: PaddingProcessor + Send + 'static>(
         key_size: KeySize,
         key: &[u8],
@@ -109,7 +113,7 @@
 }
 
 /// Get the best implementation of an EcbDecryptor
-#[cfg(all(not(target_arch = "x86"), not(target_arch = "x86_64")))]
+#[cfg(any(not(feature = "with-asm"), all(not(target_arch = "x86"), not(target_arch = "x86_64"))))]
 pub fn ecb_decryptor<X: PaddingProcessor + Send + 'static>(
         key_size: KeySize,
         key: &[u8],
@@ -134,7 +138,7 @@
 }
 
 /// Get the best implementation of a CbcEncryptor
-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+#[cfg(all(feature = "with-asm", any(target_arch = "x86", target_arch = "x86_64")))]
 pub fn cbc_encryptor<X: PaddingProcessor + Send + 'static>(
         key_size: KeySize,
         key: &[u8],
@@ -166,7 +170,7 @@
 }
 
 /// Get the best implementation of a CbcEncryptor
-#[cfg(all(not(target_arch = "x86"), not(target_arch = "x86_64")))]
+#[cfg(any(not(feature = "with-asm"), all(not(target_arch = "x86"), not(target_arch = "x86_64"))))]
 pub fn cbc_encryptor<X: PaddingProcessor + Send + 'static>(
         key_size: KeySize,
         key: &[u8],
@@ -192,7 +196,7 @@
 }
 
 /// Get the best implementation of a CbcDecryptor
-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+#[cfg(all(feature = "with-asm", any(target_arch = "x86", target_arch = "x86_64")))]
 pub fn cbc_decryptor<X: PaddingProcessor + Send + 'static>(
         key_size: KeySize,
         key: &[u8],
@@ -224,7 +228,7 @@
 }
 
 /// Get the best implementation of a CbcDecryptor
-#[cfg(all(not(target_arch = "x86"), not(target_arch = "x86_64")))]
+#[cfg(any(not(feature = "with-asm"), all(not(target_arch = "x86"), not(target_arch = "x86_64"))))]
 pub fn cbc_decryptor<X: PaddingProcessor + Send + 'static>(
         key_size: KeySize,
         key: &[u8],
@@ -250,7 +254,7 @@
 }
 
 /// Get the best implementation of a Ctr
-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+#[cfg(all(feature = "with-asm", any(target_arch = "x86", target_arch = "x86_64")))]
 pub fn ctr(
         key_size: KeySize,
         key: &[u8],
@@ -281,7 +285,7 @@
 }
 
 /// Get the best implementation of a Ctr
-#[cfg(all(not(target_arch = "x86"), not(target_arch = "x86_64")))]
+#[cfg(any(not(feature = "with-asm"), all(not(target_arch = "x86"), not(target_arch = "x86_64"))))]
 pub fn ctr(
         key_size: KeySize,
         key: &[u8],
@@ -309,14 +313,16 @@
 mod test {
     use std::iter::repeat;
 
-    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    #[cfg(all(feature = "with-asm", any(target_arch = "x86", target_arch = "x86_64")))]
     use aesni;
 
     use aessafe;
     use symmetriccipher::{BlockEncryptor, BlockDecryptor, BlockEncryptorX8, BlockDecryptorX8,
             SynchronousStreamCipher};
+    #[cfg(feature = "with-asm")]
     use util;
     use aes;
+    #[cfg(all(feature = "with-asm", any(target_arch = "x86", target_arch = "x86_64")))]
     use aes::KeySize::{KeySize128, KeySize192, KeySize256};
 
     // Test vectors from:
@@ -472,7 +478,7 @@
         }
     }
 
-    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    #[cfg(all(feature = "with-asm", any(target_arch = "x86", target_arch = "x86_64")))]
     #[test]
     fn test_aesni_128() {
         if util::supports_aesni() {
@@ -485,7 +491,7 @@
         }
     }
 
-    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    #[cfg(all(feature = "with-asm", any(target_arch = "x86", target_arch = "x86_64")))]
     #[test]
     fn test_aesni_192() {
         if util::supports_aesni() {
@@ -498,7 +504,7 @@
         }
     }
 
-    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    #[cfg(all(feature = "with-asm", any(target_arch = "x86", target_arch = "x86_64")))]
     #[test]
     fn test_aesni_256() {
         if util::supports_aesni() {
@@ -709,7 +715,7 @@
 mod bench {
     use test::Bencher;
 
-    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    #[cfg(all(feature = "with-asm", any(target_arch = "x86", target_arch = "x86_64")))]
     use aesni;
 
     use aessafe;
@@ -717,25 +723,25 @@
     use util;
     use aes::KeySize::{self, KeySize128, KeySize192, KeySize256};
 
-    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    #[cfg(all(feature = "with-asm", any(target_arch = "x86", target_arch = "x86_64")))]
     #[bench]
     pub fn aesni_128_bench(bh: &mut Bencher) {
         aesni_bench(bh, KeySize128);
     }
 
-    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    #[cfg(all(feature = "with-asm", any(target_arch = "x86", target_arch = "x86_64")))]
     #[bench]
     pub fn aesni_192_bench(bh: &mut Bencher) {
         aesni_bench(bh, KeySize192);
     }
 
-    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    #[cfg(all(feature = "with-asm", any(target_arch = "x86", target_arch = "x86_64")))]
     #[bench]
     pub fn aesni_256_bench(bh: &mut Bencher) {
         aesni_bench(bh, KeySize256);
     }
 
-    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    #[cfg(all(feature = "with-asm", any(target_arch = "x86", target_arch = "x86_64")))]
     fn aesni_bench(bh: &mut Bencher, key_size: KeySize) {
         if util::supports_aesni() {
             let key: [u8; 16] = [1u8; 16];
diff --git a/src/cryptoutil.rs b/src/cryptoutil.rs
index f6744e0..0c1acaa 100644
--- a/src/cryptoutil.rs
+++ b/src/cryptoutil.rs
@@ -165,6 +165,7 @@
 }
 
 /// Read the value of a vector of bytes as a u32 value in big-endian format.
+#[cfg(all(feature = "with-asm", any(target_arch = "x86", target_arch = "x86_64")))]
 pub fn read_u32_be(input: &[u8]) -> u32 {
     assert!(input.len() == 4);
     unsafe {
diff --git a/src/lib.rs b/src/lib.rs
index 59ad3af..e82cfbc 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -16,33 +16,46 @@
 
 pub mod aead;
 pub mod aes;
+#[cfg(feature = "with-asm")]
 pub mod aes_gcm;
 pub mod aessafe;
 pub mod bcrypt;
 pub mod bcrypt_pbkdf;
+#[cfg(feature = "with-asm")]
 pub mod blake2b;
+#[cfg(feature = "with-asm")]
 pub mod blake2s;
 pub mod blockmodes;
 pub mod blowfish;
 pub mod buffer;
 pub mod chacha20;
+#[cfg(feature = "with-asm")]
 pub mod chacha20poly1305;
 mod cryptoutil;
+#[cfg(feature = "with-asm")]
 pub mod curve25519;
 pub mod digest;
+#[cfg(feature = "with-asm")]
 pub mod ed25519;
 pub mod fortuna;
+#[cfg(feature = "with-asm")]
 pub mod ghash;
 pub mod hc128;
+#[cfg(feature = "with-asm")]
 pub mod hmac;
+#[cfg(feature = "with-asm")]
 pub mod hkdf;
+#[cfg(feature = "with-asm")]
 pub mod mac;
 pub mod md5;
+#[cfg(feature = "with-asm")]
 pub mod pbkdf2;
+#[cfg(feature = "with-asm")]
 pub mod poly1305;
 pub mod rc4;
 pub mod ripemd160;
 pub mod salsa20;
+#[cfg(feature = "with-asm")]
 pub mod scrypt;
 pub mod sha1;
 pub mod sha2;
@@ -51,8 +64,9 @@
 pub mod sosemanuk;
 mod step_by;
 pub mod symmetriccipher;
+#[cfg(feature = "with-asm")]
 pub mod util;
 pub mod whirlpool;
 
-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+#[cfg(all(feature = "with-asm", any(target_arch = "x86", target_arch = "x86_64")))]
 pub mod aesni;