├── .appveyor.yml ├── .github ├── FUNDING.yml └── dependabot.yml ├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── Cargo.toml ├── LICENSE ├── Makefile ├── NEWS.md ├── README.md ├── ci ├── after_success.sh ├── install.sh └── script.sh └── src ├── imp ├── commoncrypto.rs ├── cryptoapi.rs └── openssl.rs ├── lib.rs └── test.rs /.appveyor.yml: -------------------------------------------------------------------------------- 1 | # Based on the "trust" template v0.1.2 2 | # https://github.com/japaric/trust/tree/v0.1.2 3 | 4 | platform: 5 | - x86 6 | - x64 7 | environment: 8 | matrix: 9 | - RUST_VERSION: stable 10 | BUILD_TARGET: msvc 11 | - RUST_VERSION: stable 12 | BUILD_TARGET: gnu 13 | - RUST_VERSION: nightly 14 | BUILD_TARGET: msvc 15 | - RUST_VERSION: nightly 16 | BUILD_TARGET: gnu 17 | matrix: 18 | allow_failures: 19 | - BUILD_TARGET: msvc 20 | platform: x86 21 | - RUST_VERSION: nightly 22 | branches: 23 | only: 24 | - master 25 | - /v\d+\.\d+\.\d+/ 26 | cache: 27 | - target 28 | - '%USERPROFILE%\.cargo\registry' 29 | install: 30 | - ps: | 31 | $env:PATH += ";${env:USERPROFILE}\.cargo\bin"; 32 | if ($env:platform -eq 'x86') { 33 | $env:RUST_ARCH = "i686-pc-windows-${env:BUILD_TARGET}"; 34 | $env:ARCH = "x86"; 35 | $env:bits = "32"; 36 | } else { 37 | $env:RUST_ARCH = "x86_64-pc-windows-${env:BUILD_TARGET}"; 38 | $env:ARCH = "amd64"; 39 | $env:bits ="64"; 40 | } 41 | if ($env:BUILD_TARGET -eq 'gnu') { 42 | $env:PATH += ";C:\msys64\mingw${env:bits}\bin"; 43 | gcc --version; 44 | } 45 | - curl --fail --retry 3 --silent --show-error --location -o rustup-init.exe https://win.rustup.rs 46 | - rustup-init.exe --default-host %RUST_ARCH% --default-toolchain %RUST_VERSION% -y 47 | - call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %ARCH% 48 | - rustc -vV 49 | - cargo -vV 50 | build: false 51 | test_script: 52 | # we don't run the "test phase" when doing deploys 53 | - if [%APPVEYOR_REPO_TAG%]==[false] ( 54 | cargo build --target %RUST_ARCH% && 55 | cargo build --target %RUST_ARCH% --release && 56 | cargo test --target %RUST_ARCH% && 57 | cargo test --target %RUST_ARCH% --release 58 | ) 59 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: malept 2 | tidelift: cargo/crypto-hash 3 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: cargo 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | open-pull-requests-limit: 10 8 | - package-ecosystem: "github-actions" 9 | directory: "/" 10 | schedule: 11 | interval: daily 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.bk 2 | target 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Based on the "trust" template v0.1.2 2 | # https://github.com/japaric/trust/tree/v0.1.2 3 | 4 | language: rust 5 | os: linux 6 | dist: bionic 7 | rust: stable 8 | 9 | cache: cargo 10 | 11 | jobs: 12 | include: 13 | # rustdoc/rustfmt/clippy 14 | - stage: style-docs 15 | name: "Docs/Formatting/Lints" 16 | env: TARGET=all-style-docs 17 | 18 | # Android 19 | - stage: compile-only 20 | env: TARGET=aarch64-linux-android DISABLE_TESTS=1 21 | - env: TARGET=arm-linux-androideabi DISABLE_TESTS=1 22 | - env: TARGET=armv7-linux-androideabi DISABLE_TESTS=1 23 | - env: TARGET=i686-linux-android DISABLE_TESTS=1 24 | - env: TARGET=x86_64-linux-android DISABLE_TESTS=1 25 | 26 | # *BSD 27 | - env: TARGET=x86_64-unknown-netbsd DISABLE_TESTS=1 28 | 29 | # iOS 30 | - env: TARGET=aarch64-apple-ios DISABLE_TESTS=1 31 | os: osx 32 | - env: TARGET=armv7-apple-ios DISABLE_TESTS=1 33 | os: osx 34 | - env: TARGET=armv7s-apple-ios DISABLE_TESTS=1 35 | os: osx 36 | - env: TARGET=i386-apple-ios DISABLE_TESTS=1 37 | os: osx 38 | - env: TARGET=x86_64-apple-ios DISABLE_TESTS=1 39 | os: osx 40 | 41 | # Linux 42 | - env: TARGET=s390x-unknown-linux-gnu DISABLE_TESTS=1 43 | 44 | - stage: compile-test 45 | env: TARGET=aarch64-unknown-linux-gnu 46 | - env: TARGET=arm-unknown-linux-gnueabi 47 | - env: TARGET=armv7-unknown-linux-gnueabihf 48 | - env: TARGET=i686-unknown-linux-gnu 49 | - env: TARGET=i686-unknown-linux-musl 50 | - env: TARGET=mips-unknown-linux-gnu 51 | - env: TARGET=mips64-unknown-linux-gnuabi64 52 | - env: TARGET=mips64el-unknown-linux-gnuabi64 53 | - env: TARGET=mipsel-unknown-linux-gnu 54 | - env: TARGET=powerpc-unknown-linux-gnu 55 | - env: TARGET=powerpc64-unknown-linux-gnu 56 | - env: TARGET=powerpc64le-unknown-linux-gnu 57 | - env: TARGET=x86_64-unknown-linux-gnu 58 | # necessary for `cargo coveralls` 59 | addons: 60 | apt: 61 | packages: 62 | - binutils-dev 63 | - libcurl4-openssl-dev 64 | - libdw-dev 65 | - libelf-dev 66 | - libiberty-dev 67 | - env: TARGET=x86_64-unknown-linux-musl 68 | 69 | # OSX 70 | - env: TARGET=i686-apple-darwin 71 | os: osx 72 | - env: TARGET=x86_64-apple-darwin 73 | os: osx 74 | 75 | # Testing other channels 76 | - env: TARGET=x86_64-unknown-linux-gnu 77 | rust: nightly 78 | - env: TARGET=x86_64-apple-darwin 79 | os: osx 80 | rust: nightly 81 | allow_failures: 82 | - rust: nightly 83 | 84 | branches: 85 | only: 86 | - master 87 | - /^v\d+\.\d+\.\d+/ 88 | 89 | stages: 90 | - style-docs 91 | - compile-test 92 | - compile-only 93 | 94 | install: ci/install.sh 95 | script: ci/script.sh 96 | after_success: ci/after_success.sh 97 | 98 | env: 99 | global: 100 | - PATH=$HOME/.local/bin:$PATH 101 | # encrypted github token for doc upload 102 | - secure: "ttZL5OpzNMQOHuaTj7cKyl5N24r3HPB0V/ogWt4Ws10t08aGoonlRSLVlUZaTKI9D5CZMthaWbHRczeJ0DO3MFvAyKcMsnBaM+hc04oRAK7GweoOW3AeKGhBGOVljQK47ySa/Bjniky9zejw/8gzHyOeji+Ydb6YwAdgxTqaHGL+5YAoB1CurxdoVZnVaCLLvvsbPsL27YFkOZrYsI51OlTzkoXj783GowgwjTWc6DBzIgtMTokBKkoPIvVRFBHpwrLhX/pvet3bauXrn2WGkl8+Ab5mBOEhwpmz9TkQW47qyWbibpOwkTwf55C7Ecpi1Aix5o21wLKEDdcZgzY72ri7DillNkLgbcIpHGBQpT+P1lK6pmG1G9HzW2bNPn8k0LukEIY8E0Q1kDef7mc4qw5zkMTgyruRi+yd6r9pTXXh1mDTvNc956Rx/fsfHgxhJIk73/IlYNIaDcmMHbyYQ/AeohWaxup45fqNRaK8AbYFm5rV3o6Ce9c+lW2cHm3ssbhQ5T6L8kGyrDO9glEeyvdKsO6lXRc6x0hiwu9msuRyCgDW1iPD0mkXiMYM5MVC3mg/h9E+e0KcjZg1+PaVqnUWHINsGynNJCctzCmfUMb9aufPTAtoYweT7FMTHekaTLhvxjaYxfPsVmi7kL6HaXAVKQf2qZgp/IjI7AtFsaE=" 103 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to `crypto-hash` 2 | 3 | `crypto-hash` is a part of the Rust ecosystem. As such, all contributions to this project follow the 4 | [Rust language's code of conduct](https://www.rust-lang.org/conduct.html) where appropriate. 5 | 6 | This project is hosted at [GitHub](https://github.com/malept/crypto-hash). Both pull requests and 7 | issues of many different kinds are accepted. 8 | 9 | ## Filing Issues 10 | 11 | Issues include bugs, questions, feedback, and feature requests. Before you file a new issue, please 12 | make sure that your issue has not already been filed by someone else. 13 | 14 | ### Filing Bugs 15 | 16 | When filing a bug, please include the following information: 17 | 18 | * Operating system and version. If on Linux, please also include the distribution name. 19 | * System architecture. Examples include: x86-64, x86, and ARMv7. 20 | * Rust version that compiled `crypto-hash`. 21 | * The version (and/or git revision) of `crypto-hash`. 22 | * A detailed list of steps to reproduce the bug. A minimal testcase would be very helpful, 23 | if possible. 24 | * If there any any error messages in the console, copying them in the bug summary will be 25 | very helpful. 26 | 27 | ## Adding a new implementation 28 | 29 | If you are requesting or adding a new library source for hash algorithms, please make sure that it 30 | supports all of the existing algorithms. For example, while the creator of this project supports the 31 | efforts of the team writing LibreSSL, it does not support the MD5 algorithm. 32 | 33 | ## Adding a new hash algorithm 34 | 35 | If you are requesting or adding a wrapper for a new hash algorithm, please make sure that it is 36 | available in all of the supported implementations listed in the README. 37 | 38 | ## Filing Pull Requests 39 | 40 | Here are some things to keep in mind as you file a pull request to fix a bug, add a new feature, 41 | etc.: 42 | 43 | * Travis CI (for Linux and OS X) and AppVeyor (for Windows) are used to make sure that the project 44 | builds as expected on the supported platforms, using the current stable and beta versions of Rust. 45 | Make sure the testsuite passes locally by running `cargo test`. 46 | * Unless it's impractical, please write tests for your changes. This will help spot regressions 47 | much easier. 48 | * If your PR changes the behavior of an existing feature, or adds a new feature, please add/edit 49 | the `rustdoc` inline documentation. 50 | * Please ensure that your changes follow the [rustfmt](https://github.com/rust-lang-nursery/rustfmt) 51 | coding standard, and do not produce any warnings when running the 52 | [clippy](https://github.com/Manishearth/rust-clippy) linter. 53 | * If you are contributing a nontrivial change, please add an entry to `NEWS.md`. The format is 54 | similar to the one described at [Keep a Changelog](http://keepachangelog.com/). 55 | * Please make sure your commits are rebased onto the latest commit in the master branch, and that 56 | you limit/squash the number of commits created to a "feature"-level. For instance: 57 | 58 | bad: 59 | 60 | ``` 61 | commit 1: add foo algorithm 62 | commit 2: run rustfmt 63 | commit 3: add test 64 | commit 4: add docs 65 | commit 5: add bar 66 | commit 6: add test + docs 67 | ``` 68 | 69 | good: 70 | 71 | ``` 72 | commit 1: add foo algorithm 73 | commit 2: add bar 74 | ``` 75 | 76 | If you are continuing the work of another person's PR and need to rebase/squash, please retain the 77 | attribution of the original author(s) and continue the work in subsequent commits. 78 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "crypto-hash" 3 | version = "0.3.4" 4 | authors = ["Mark Lee"] 5 | description = "A wrapper for OS-level cryptographic hash functions" 6 | documentation = "https://docs.rs/crypto-hash" 7 | repository = "https://github.com/malept/crypto-hash" 8 | readme = "README.md" 9 | keywords = ["crypto", "hash", "digest"] 10 | license = "MIT" 11 | exclude = [ 12 | ".*.yml", 13 | "ci/*" 14 | ] 15 | 16 | [badges] 17 | travis-ci = { repository = "malept/crypto-hash" } 18 | appveyor = { repository = "malept/crypto-hash" } 19 | 20 | [dependencies] 21 | hex = "0.4" 22 | 23 | [target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies] 24 | commoncrypto = "0.2" 25 | 26 | [target.'cfg(target_os = "windows")'.dependencies] 27 | winapi = { version = "0.3", features = ["minwindef", "wincrypt"] } 28 | 29 | [target.'cfg(not(any(target_os = "windows", target_os = "macos", target_os = "ios")))'.dependencies] 30 | openssl = "0.10" 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, 2016 Mark Lee 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CARGO ?= cargo 2 | CARGO_BUILD_TEST = $(CARGO) test --no-run 3 | KCOV ?= kcov 4 | TEST_APP = debug/crypto_hash-*.exe 5 | WIN_TARGET = x86_64-pc-windows-gnu 6 | 7 | build-test: 8 | $(CARGO_BUILD_TEST) 9 | 10 | check-i686: 11 | PKG_CONFIG_LIBDIR=/usr/lib/i386-linux-gnu/pkgconfig \ 12 | PKG_CONFIG_ALLOW_CROSS=1 \ 13 | $(CARGO) test --target i686-unknown-linux-gnu --verbose 14 | 15 | check-wine64: 16 | $(CARGO_BUILD_TEST) --target $(WIN_TARGET) 17 | WINEPREFIX=$(HOME)/.local/share/wineprefixes/wine64 wine64 target/$(WIN_TARGET)/$(TEST_APP) 18 | 19 | cov: build-test 20 | $(KCOV) --exclude-pattern=/.multirust,test.rs target/cov target/$(TEST_APP) 21 | 22 | debug: build-test 23 | rust-gdb target/$(TEST_APP) 24 | 25 | fmt: 26 | $(CARGO) fmt 27 | 28 | lint: 29 | $(CARGO) +nightly clippy -- --allow clippy::pedantic 30 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | # `crypto-hash`: Changes by Version 2 | 3 | ## [Unreleased](https://github.com/malept/crypto-hash/compare/v0.3.4...master) 4 | 5 | ## [0.3.4] - 2019-08-18 6 | 7 | [0.3.4]: https://github.com/malept/crypto-hash/compare/v0.3.3...v0.3.4 8 | 9 | ### Added 10 | 11 | * `Copy`, `Eq`, `Hash`, & `PartialEq` derives on `Algorithm` (#11) 12 | 13 | ## [0.3.3] - 2018-12-20 14 | 15 | [0.3.3]: https://github.com/malept/crypto-hash/compare/v0.3.2...v0.3.3 16 | 17 | ### Changed 18 | 19 | * Revert API change (#6) 20 | 21 | ## [0.3.2] - 2018-12-20 22 | 23 | [0.3.2]: https://github.com/malept/crypto-hash/compare/v0.3.1...v0.3.2 24 | 25 | **Note: This release was yanked from Cargo due to #6.** 26 | 27 | ### Added 28 | 29 | * iOS support 30 | 31 | ## [0.3.1] - 2018-02-14 32 | 33 | [0.3.1]: https://github.com/malept/crypto-hash/compare/v0.3.0...v0.3.1 34 | 35 | ### Changed 36 | 37 | * Upgrade to `openssl` 0.10.x (#1) 38 | * Upgrade to `winapi` 0.3.x 39 | 40 | ## [0.3.0] - 2017-06-18 41 | 42 | [0.3.0]: https://github.com/malept/crypto-hash/compare/v0.2.1...v0.3.0 43 | 44 | ### Changed 45 | 46 | * Upgrade to `commoncrypto` 0.2.x 47 | * Function signatures for `digest` and `hex_digest` changed to use `&[u8]`, per Clippy 48 | 49 | ## [0.2.1] - 2016-12-12 50 | 51 | [0.2.1]: https://github.com/malept/crypto-hash/compare/v0.2.0...v0.2.1 52 | 53 | ### Changed 54 | 55 | * Move CommonCrypto implementation to its own crate 56 | 57 | ## [0.2.0] - 2016-11-06 58 | 59 | [0.2.0]: https://github.com/malept/crypto-hash/compare/v0.1.0...v0.2.0 60 | 61 | ### Added 62 | 63 | * SHA-1 algorithm 64 | 65 | ### Changed 66 | 67 | * Upgrade rust-openssl to 0.9 68 | 69 | ## [0.1.0] - 2016-06-26 70 | 71 | [0.1.0]: https://github.com/malept/crypto-hash/releases/tag/v0.1.0 72 | 73 | This release signifies the minimum amount of algorithms and implementations necessary for 74 | [HTTP digest authentication](https://tools.ietf.org/html/rfc7616). 75 | 76 | ### Added 77 | 78 | Algorithms: 79 | 80 | * MD5 81 | * SHA256 82 | * SHA512 83 | 84 | Implementations: 85 | 86 | * CommonCrypto (OS X) 87 | * CryptoAPI (Windows) 88 | * OpenSSL (Linux/BSD/etc.) 89 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `crypto-hash` 2 | 3 | [![Linux/OS X Status](https://travis-ci.org/malept/crypto-hash.svg?branch=master)](https://travis-ci.org/malept/crypto-hash) 4 | [![Windows status](https://ci.appveyor.com/api/projects/status/xwc9nb4633b5n67r/branch/master?svg=true)](https://ci.appveyor.com/project/malept/crypto-hash) 5 | [![Crates.io](https://img.shields.io/crates/v/crypto-hash.svg?maxAge=2592000)](https://crates.io/crates/crypto-hash) 6 | 7 | `crypto-hash` is a Rust wrapper around OS-level implementations of cryptographic hash functions. 8 | 9 | The purpose of this crate is to provide access to hash algorithms with as few dependencies as 10 | possible. This means that when possible, the library uses the hashing functions that are provided by 11 | the given operating system's bundled cryptographic libraries. 12 | 13 | ## Supported Implementations 14 | 15 | By operating system: 16 | 17 | * Windows: CryptoAPI 18 | * OS X: [CommonCrypto](https://crates.io/crates/commoncrypto) 19 | * Linux/BSD/etc.: [OpenSSL](https://crates.io/crates/openssl) 20 | 21 | ## Supported Algorithms 22 | 23 | * MD5 24 | * SHA1 25 | * SHA256 26 | * SHA512 27 | 28 | ## Usage 29 | 30 | Add `crypto-hash` to your project's `Cargo.toml`. For more details, consult the 31 | [Cargo guide](http://doc.crates.io/guide.html#adding-dependencies). 32 | 33 | Example: 34 | 35 | ```rust 36 | use crypto_hash::{Algorithm, hex_digest}; 37 | 38 | let digest = hex_digest(Algorithm::SHA256, b"crypto-hash"); 39 | ``` 40 | 41 | For more examples, consult the [documentation](https://malept.github.io/crypto-hash/). 42 | 43 | ## [Release Notes](https://github.com/malept/crypto-hash/blob/master/NEWS.md) 44 | 45 | ## [Contributing](https://github.com/malept/crypto-hash/blob/master/CONTRIBUTING.md) 46 | 47 | ## Acknowledgements 48 | 49 | This crate was inspired by [rust-native-tls](https://github.com/sfackler/rust-native-tls) and 50 | [crypto-bench](https://github.com/briansmith/crypto-bench). 51 | 52 | ## Legal 53 | 54 | `crypto-hash` is copyrighted under the terms of the MIT license. See LICENSE for details. 55 | -------------------------------------------------------------------------------- /ci/after_success.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | if test "$TARGET" = "all-style-docs"; then 4 | # upload the documentation from the build with stable (automatically only actually 5 | # runs on the master branch, not individual PRs) 6 | cargo doc-upload 7 | elif test "$TARGET" = "x86_64-unknown-linux-gnu" -a "$TRAVIS_RUST_VERSION" = "stable"; then 8 | cargo tarpaulin --out Xml 9 | bash <(curl -s https://codecov.io/bash) 10 | fi 11 | -------------------------------------------------------------------------------- /ci/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -xe 2 | 3 | install_cargo_plugins() { 4 | cargo install cargo-update || echo "cargo-update already installed" 5 | cargo install cargo-travis || echo "cargo-travis already installed" 6 | cargo install cargo-tarpaulin || echo "cargo-tarpaulin already installed" 7 | cargo install-update -a 8 | } 9 | 10 | install_style_docs_dependencies() { 11 | rustup component add rustfmt clippy --toolchain=$TRAVIS_RUST_VERSION 12 | install_cargo_plugins 13 | } 14 | 15 | install_compile_dependencies() { 16 | # Builds for iOS are done on OSX, but require the specific target to be installed. 17 | case $TARGET in 18 | *-apple-ios) 19 | rustup target install $TARGET 20 | ;; 21 | esac 22 | 23 | local target= 24 | if [ $TRAVIS_OS_NAME = linux ]; then 25 | target=x86_64-unknown-linux-musl 26 | else 27 | target=x86_64-apple-darwin 28 | fi 29 | 30 | # Pinning to v0.1.16 because v0.2 removes openssl from the images 31 | # https://github.com/rust-embedded/cross/pull/322 32 | local tag=v0.1.16 33 | curl -LSfs https://japaric.github.io/trust/install.sh | \ 34 | sh -s -- \ 35 | --force \ 36 | --git rust-embedded/cross \ 37 | --tag $tag \ 38 | --target $target 39 | 40 | if test "$TARGET" = "x86_64-unknown-linux-gnu" -a "$TRAVIS_RUST_VERSION" = "stable"; then 41 | install_cargo_plugins 42 | fi 43 | } 44 | 45 | main() { 46 | if test "$TARGET" = "all-style-docs"; then 47 | install_style_docs_dependencies 48 | else 49 | install_compile_dependencies 50 | fi 51 | } 52 | 53 | main 54 | -------------------------------------------------------------------------------- /ci/script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -xe 2 | 3 | build_and_test() { 4 | cross build --target $TARGET 5 | cross build --target $TARGET --release 6 | 7 | if [ -n $DISABLE_TESTS ]; then 8 | return 9 | fi 10 | 11 | cross test --target $TARGET 12 | cross test --target $TARGET --release 13 | } 14 | 15 | style_and_docs() { 16 | cargo doc 17 | 18 | if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then 19 | cargo fmt -- --check $(git diff --name-only "$TRAVIS_COMMIT" "$TRAVIS_BRANCH" | grep \.rs$) 20 | else 21 | cargo fmt -- --check $(git show --format= --name-only "$TRAVIS_COMMIT_RANGE" | sort -u | grep \.rs$) 22 | fi 23 | 24 | cargo clippy -- --allow clippy::pedantic 25 | } 26 | 27 | main() { 28 | if test "$TARGET" = "all-style-docs"; then 29 | style_and_docs 30 | else 31 | build_and_test 32 | fi 33 | } 34 | 35 | # we don't run the "test phase" when doing deploys 36 | if [ -z $TRAVIS_TAG ]; then 37 | main 38 | fi 39 | -------------------------------------------------------------------------------- /src/imp/commoncrypto.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Mark Lee 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | //! A cryptographic hash generator dependent upon OSX's `CommonCrypto`. 22 | 23 | use super::Algorithm; 24 | use commoncrypto::hash; 25 | use std::io; 26 | 27 | /// Generator of digests using a cryptographic hash function. 28 | /// 29 | /// # Examples 30 | /// 31 | /// ```rust 32 | /// use crypto_hash::{Algorithm, Hasher}; 33 | /// use std::io::Write; 34 | /// 35 | /// let mut hasher = Hasher::new(Algorithm::SHA256); 36 | /// hasher.write_all(b"crypto"); 37 | /// hasher.write_all(b"-"); 38 | /// hasher.write_all(b"hash"); 39 | /// let result = hasher.finish(); 40 | /// let expected = 41 | /// b"\xfd\x1a\xfb`\"\xcdMG\xc8\x90\x96\x1cS9(\xea\xcf\xe8!\x9f\x1b%$\xf7\xfb*a\x84}\xdf\x8c'" 42 | /// .to_vec(); 43 | /// assert_eq!(expected, result) 44 | /// ``` 45 | #[derive(Debug)] 46 | pub struct Hasher(hash::Hasher); 47 | 48 | impl Hasher { 49 | /// Create a new `Hasher` for the given `Algorithm`. 50 | pub fn new(algorithm: Algorithm) -> Hasher { 51 | let cc_algorithm = match algorithm { 52 | Algorithm::MD5 => hash::CCDigestAlgorithm::kCCDigestMD5, 53 | Algorithm::SHA1 => hash::CCDigestAlgorithm::kCCDigestSHA1, 54 | Algorithm::SHA256 => hash::CCDigestAlgorithm::kCCDigestSHA256, 55 | Algorithm::SHA512 => hash::CCDigestAlgorithm::kCCDigestSHA512, 56 | }; 57 | 58 | Hasher(hash::Hasher::new(cc_algorithm)) 59 | } 60 | 61 | /// Generate a digest from the data written to the `Hasher`. 62 | pub fn finish(&mut self) -> Vec { 63 | let Hasher(ref mut hasher) = *self; 64 | match hasher.finish() { 65 | Ok(digest) => digest, 66 | Err(error) => panic!("CommonCrypto error: {}", error), 67 | } 68 | } 69 | } 70 | 71 | impl io::Write for Hasher { 72 | fn write(&mut self, buf: &[u8]) -> io::Result { 73 | let Hasher(ref mut hasher) = *self; 74 | hasher.write(buf) 75 | } 76 | 77 | fn flush(&mut self) -> io::Result<()> { 78 | let Hasher(ref mut hasher) = *self; 79 | hasher.flush() 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/imp/cryptoapi.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Mark Lee 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | //! A cryptographic hash generator dependent upon Windows's `CryptoAPI`. 22 | //! 23 | //! Originally based on: 24 | //! https://github.com/rust-lang/cargo/blob/0.10.0/src/cargo/util/sha256.rs 25 | //! which is copyright (c) 2014 The Rust Project Developers under the MIT license. 26 | 27 | use super::Algorithm; 28 | use std::io; 29 | use std::ptr; 30 | use winapi::shared::minwindef::DWORD; 31 | use winapi::um::wincrypt::{ 32 | CryptAcquireContextW, CryptCreateHash, CryptDestroyHash, CryptGetHashParam, CryptHashData, 33 | CryptReleaseContext, ALG_ID, CALG_MD5, CALG_SHA1, CALG_SHA_256, CALG_SHA_512, CRYPT_SILENT, 34 | CRYPT_VERIFYCONTEXT, HCRYPTHASH, HCRYPTPROV, HP_HASHVAL, PROV_RSA_AES, 35 | }; 36 | 37 | macro_rules! call { 38 | ($e:expr) => {{ 39 | if $e == 0 { 40 | panic!("failed {}: {}", stringify!($e), io::Error::last_os_error()) 41 | } 42 | }}; 43 | } 44 | 45 | macro_rules! finish_algorithm { 46 | ($func_name: ident, $size: ident) => { 47 | fn $func_name(&mut self) -> Vec { 48 | let mut len = $size as u32; 49 | let mut hash = [0u8; $size]; 50 | call!(unsafe { 51 | CryptGetHashParam(self.hcrypthash, HP_HASHVAL, hash.as_mut_ptr(), &mut len, 0) 52 | }); 53 | assert_eq!(len as usize, hash.len()); 54 | hash.to_vec() 55 | } 56 | } 57 | } 58 | 59 | const MD5_LENGTH: usize = 16; 60 | const SHA1_LENGTH: usize = 20; 61 | const SHA256_LENGTH: usize = 32; 62 | const SHA512_LENGTH: usize = 64; 63 | 64 | /// Generator of digests using a cryptographic hash function. 65 | /// 66 | /// # Examples 67 | /// 68 | /// ```rust 69 | /// use crypto_hash::{Algorithm, Hasher}; 70 | /// use std::io::Write; 71 | /// 72 | /// let mut hasher = Hasher::new(Algorithm::SHA256); 73 | /// hasher.write_all(b"crypto"); 74 | /// hasher.write_all(b"-"); 75 | /// hasher.write_all(b"hash"); 76 | /// let result = hasher.finish(); 77 | /// let expected = 78 | /// b"\xfd\x1a\xfb`\"\xcdMG\xc8\x90\x96\x1cS9(\xea\xcf\xe8!\x9f\x1b%$\xf7\xfb*a\x84}\xdf\x8c'" 79 | /// .to_vec(); 80 | /// assert_eq!(expected, result) 81 | /// ``` 82 | pub struct Hasher { 83 | alg_id: ALG_ID, 84 | hcryptprov: HCRYPTPROV, 85 | hcrypthash: HCRYPTHASH, 86 | } 87 | 88 | impl Hasher { 89 | /// Create a new `Hasher` for the given `Algorithm`. 90 | pub fn new(algorithm: Algorithm) -> Hasher { 91 | let mut hcp = 0; 92 | call!(unsafe { 93 | CryptAcquireContextW( 94 | &mut hcp, 95 | ptr::null(), 96 | ptr::null(), 97 | PROV_RSA_AES, 98 | CRYPT_VERIFYCONTEXT | CRYPT_SILENT, 99 | ) 100 | }); 101 | 102 | let alg_id = match algorithm { 103 | Algorithm::MD5 => CALG_MD5, 104 | Algorithm::SHA1 => CALG_SHA1, 105 | Algorithm::SHA256 => CALG_SHA_256, 106 | Algorithm::SHA512 => CALG_SHA_512, 107 | }; 108 | 109 | let mut hasher = Hasher { 110 | alg_id, 111 | hcryptprov: hcp, 112 | hcrypthash: 0, 113 | }; 114 | 115 | call!(unsafe { 116 | CryptCreateHash( 117 | hasher.hcryptprov, 118 | hasher.alg_id, 119 | 0, 120 | 0, 121 | &mut hasher.hcrypthash, 122 | ) 123 | }); 124 | hasher 125 | } 126 | 127 | /// Generate a digest from the data written to the `Hasher`. 128 | pub fn finish(&mut self) -> Vec { 129 | match self.alg_id { 130 | CALG_MD5 => self.finish_md5(), 131 | CALG_SHA1 => self.finish_sha1(), 132 | CALG_SHA_256 => self.finish_sha256(), 133 | CALG_SHA_512 => self.finish_sha512(), 134 | _ => panic!("Unknown algorithm {}", self.alg_id), 135 | } 136 | } 137 | 138 | finish_algorithm!(finish_md5, MD5_LENGTH); 139 | finish_algorithm!(finish_sha1, SHA1_LENGTH); 140 | finish_algorithm!(finish_sha256, SHA256_LENGTH); 141 | finish_algorithm!(finish_sha512, SHA512_LENGTH); 142 | } 143 | 144 | impl io::Write for Hasher { 145 | fn write(&mut self, buf: &[u8]) -> io::Result { 146 | call!(unsafe { 147 | CryptHashData( 148 | self.hcrypthash, 149 | buf.as_ptr() as *mut _, 150 | buf.len() as DWORD, 151 | 0, 152 | ) 153 | }); 154 | Ok(buf.len()) 155 | } 156 | 157 | fn flush(&mut self) -> io::Result<()> { 158 | Ok(()) 159 | } 160 | } 161 | 162 | impl Drop for Hasher { 163 | fn drop(&mut self) { 164 | if self.hcrypthash != 0 { 165 | call!(unsafe { CryptDestroyHash(self.hcrypthash) }); 166 | } 167 | call!(unsafe { CryptReleaseContext(self.hcryptprov, 0) }); 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /src/imp/openssl.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, 2016 Mark Lee 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | //! A cryptographic hash digest generator dependent upon `OpenSSL`. 22 | 23 | #![warn(missing_docs)] 24 | 25 | use super::Algorithm; 26 | use openssl::hash; 27 | use std::io; 28 | 29 | /// Generator of digests using a cryptographic hash function. 30 | /// 31 | /// # Examples 32 | /// 33 | /// ```rust 34 | /// use crypto_hash::{Algorithm, Hasher}; 35 | /// use std::io::Write; 36 | /// 37 | /// let mut hasher = Hasher::new(Algorithm::SHA256); 38 | /// hasher.write_all(b"crypto"); 39 | /// hasher.write_all(b"-"); 40 | /// hasher.write_all(b"hash"); 41 | /// let result = hasher.finish(); 42 | /// let expected = 43 | /// b"\xfd\x1a\xfb`\"\xcdMG\xc8\x90\x96\x1cS9(\xea\xcf\xe8!\x9f\x1b%$\xf7\xfb*a\x84}\xdf\x8c'" 44 | /// .to_vec(); 45 | /// assert_eq!(expected, result) 46 | /// ``` 47 | pub struct Hasher(hash::Hasher); 48 | 49 | impl Hasher { 50 | /// Create a new `Hasher` for the given `Algorithm`. 51 | pub fn new(algorithm: Algorithm) -> Hasher { 52 | let hash_type = match algorithm { 53 | Algorithm::MD5 => hash::MessageDigest::md5(), 54 | Algorithm::SHA1 => hash::MessageDigest::sha1(), 55 | Algorithm::SHA256 => hash::MessageDigest::sha256(), 56 | Algorithm::SHA512 => hash::MessageDigest::sha512(), 57 | }; 58 | 59 | match hash::Hasher::new(hash_type) { 60 | Ok(hasher) => Hasher(hasher), 61 | Err(error_stack) => panic!("OpenSSL error(s): {}", error_stack), 62 | } 63 | } 64 | 65 | /// Generate a digest from the data written to the `Hasher`. 66 | pub fn finish(&mut self) -> Vec { 67 | let Hasher(ref mut hasher) = *self; 68 | match hasher.finish() { 69 | Ok(digest) => digest.to_vec(), 70 | Err(error_stack) => panic!("OpenSSL error(s): {}", error_stack), 71 | } 72 | } 73 | } 74 | 75 | impl io::Write for Hasher { 76 | fn write(&mut self, buf: &[u8]) -> io::Result { 77 | let Hasher(ref mut hasher) = *self; 78 | hasher.write(buf) 79 | } 80 | 81 | fn flush(&mut self) -> io::Result<()> { 82 | let Hasher(ref mut hasher) = *self; 83 | hasher.flush() 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, 2016, 2017 Mark Lee 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | //! A set of [cryptographic hash 22 | //! functions](https://en.wikipedia.org/wiki/Cryptographic_hash_function) provided by the operating 23 | //! system, when available. 24 | //! 25 | //! The purpose of this crate is to provide access to hash algorithms with as few dependencies as 26 | //! possible. This means that when possible, the library uses the hashing functions that are 27 | //! provided by the given operating system's bundled cryptographic libraries. 28 | //! 29 | //! # Supported Implementations 30 | //! 31 | //! By operating system: 32 | //! 33 | //! * Windows: `CryptoAPI` 34 | //! * Mac OS X: `CommonCrypto` 35 | //! * Linux/BSD/etc.: `OpenSSL` 36 | //! 37 | //! # Supported Algorithms 38 | //! 39 | //! * MD5 40 | //! * SHA1 41 | //! * SHA256 42 | //! * SHA512 43 | 44 | #![warn(missing_docs)] 45 | 46 | #[cfg(any(target_os = "macos", target_os = "ios"))] 47 | extern crate commoncrypto; 48 | extern crate hex; 49 | #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows")))] 50 | extern crate openssl; 51 | #[cfg(target_os = "windows")] 52 | extern crate winapi; 53 | 54 | use std::io::Write; 55 | 56 | #[cfg(any(target_os = "macos", target_os = "ios"))] 57 | #[path = "imp/commoncrypto.rs"] 58 | mod imp; 59 | #[cfg(target_os = "windows")] 60 | #[path = "imp/cryptoapi.rs"] 61 | mod imp; 62 | #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows")))] 63 | #[path = "imp/openssl.rs"] 64 | mod imp; 65 | 66 | mod test; 67 | 68 | pub use imp::Hasher; 69 | 70 | /// Available cryptographic hash functions. 71 | #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 72 | pub enum Algorithm { 73 | /// Popular message digest algorithm, only available for backwards compatibility purposes. 74 | MD5, 75 | /// SHA-1 algorithm from NIST FIPS, only available for backwards compatibility purposes. 76 | SHA1, 77 | /// SHA-2 family algorithm (256 bits). 78 | SHA256, 79 | /// SHA-2 family algorithm (512 bits). 80 | SHA512, 81 | } 82 | 83 | /// Helper function for `Hasher` which generates a cryptographic digest from the given 84 | /// data and algorithm. 85 | /// 86 | /// # Examples 87 | /// 88 | /// ```rust 89 | /// use crypto_hash::{Algorithm, digest}; 90 | /// 91 | /// let data = b"crypto-hash"; 92 | /// let result = digest(Algorithm::SHA256, data); 93 | /// let expected = 94 | /// b"\xfd\x1a\xfb`\"\xcdMG\xc8\x90\x96\x1cS9(\xea\xcf\xe8!\x9f\x1b%$\xf7\xfb*a\x84}\xdf\x8c'" 95 | /// .to_vec(); 96 | /// assert_eq!(expected, result) 97 | /// ``` 98 | pub fn digest(algorithm: Algorithm, data: &[u8]) -> Vec { 99 | let mut hasher = imp::Hasher::new(algorithm); 100 | hasher.write_all(data).expect("Could not write hash data"); 101 | hasher.finish() 102 | } 103 | 104 | /// Helper function for `Hasher` which generates a cryptographic digest serialized in 105 | /// hexadecimal from the given data and algorithm. 106 | /// 107 | /// # Examples 108 | /// 109 | /// ```rust 110 | /// use crypto_hash::{Algorithm, hex_digest}; 111 | /// 112 | /// let data = b"crypto-hash"; 113 | /// let result = hex_digest(Algorithm::SHA256, data); 114 | /// let expected = "fd1afb6022cd4d47c890961c533928eacfe8219f1b2524f7fb2a61847ddf8c27"; 115 | /// assert_eq!(expected, result) 116 | /// ``` 117 | pub fn hex_digest(algorithm: Algorithm, data: &[u8]) -> String { 118 | hex::encode(digest(algorithm, data)) 119 | } 120 | -------------------------------------------------------------------------------- /src/test.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 2017 Mark Lee 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | #![cfg(test)] 22 | 23 | use super::{hex_digest, Algorithm, Hasher}; 24 | use hex; 25 | use std::io::Write; 26 | 27 | // From Wikipedia 28 | const MD5_EMPTY_STRING: &'static str = "d41d8cd98f00b204e9800998ecf8427e"; 29 | const SHA1_EMPTY_STRING: &'static str = "da39a3ee5e6b4b0d3255bfef95601890afd80709"; 30 | const SHA256_EMPTY_STRING: &'static str = concat!( 31 | "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649", 32 | "b934ca495991b7852b855" 33 | ); 34 | const SHA512_EMPTY_STRING: &'static str = concat!( 35 | "cf83e1357eefb8bdf1542850d66d8007d620e4050b5", 36 | "715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318", 37 | "d2877eec2f63b931bd47417a81a538327af927da3e" 38 | ); 39 | const TO_HASH: &'static str = "The quick brown fox jumps over the lazy dog"; 40 | const TO_HASH_MD5: &'static str = "9e107d9d372bb6826bd81d3542a419d6"; 41 | 42 | #[test] 43 | fn md5_empty_string() { 44 | assert_hex_hashed_empty_string(Algorithm::MD5, MD5_EMPTY_STRING) 45 | } 46 | 47 | #[test] 48 | fn sha1_empty_string() { 49 | assert_hex_hashed_empty_string(Algorithm::SHA1, SHA1_EMPTY_STRING) 50 | } 51 | 52 | #[test] 53 | fn sha256_empty_string() { 54 | // From Wikipedia 55 | assert_hex_hashed_empty_string(Algorithm::SHA256, SHA256_EMPTY_STRING) 56 | } 57 | 58 | #[test] 59 | fn sha512_empty_string() { 60 | assert_hex_hashed_empty_string(Algorithm::SHA512, SHA512_EMPTY_STRING) 61 | } 62 | 63 | #[test] 64 | fn hasher_sans_write() { 65 | let mut hasher = Hasher::new(Algorithm::MD5); 66 | let actual = hex::encode(hasher.finish()); 67 | assert_eq!(MD5_EMPTY_STRING, actual) 68 | } 69 | 70 | #[test] 71 | fn hasher_with_write() { 72 | let mut hasher = Hasher::new(Algorithm::MD5); 73 | hasher 74 | .write_all(TO_HASH.as_bytes()) 75 | .expect("Could not write to hasher"); 76 | let actual = hex::encode(hasher.finish()); 77 | assert_eq!(TO_HASH_MD5, actual) 78 | } 79 | 80 | fn assert_hex_hashed_empty_string(algorithm: Algorithm, expected: &str) { 81 | let vec = vec![]; 82 | assert_eq!(expected, hex_digest(algorithm, vec.as_slice()).as_str()) 83 | } 84 | --------------------------------------------------------------------------------