totp-lite-2.0.1/.cargo_vcs_info.json0000644000000001360000000000100127550ustar { "git": { "sha1": "bfeb955b2d836c9b8ed9ee4eb444fb98967d1acd" }, "path_in_vcs": "" }totp-lite-2.0.1/.github/dependabot.yml000064400000000000000000000001651046102023000157370ustar 00000000000000version: 2 updates: - package-ecosystem: "github-actions" directory: "/" schedule: interval: "daily" totp-lite-2.0.1/.github/workflows/rust.yml000064400000000000000000000003671046102023000166700ustar 00000000000000name: Rust on: push: branches: [master] pull_request: env: CARGO_TERM_COLOR: always jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Run tests run: cargo test --all-targets totp-lite-2.0.1/.gitignore000064400000000000000000000000101046102023000135240ustar 00000000000000target/ totp-lite-2.0.1/CHANGELOG.md000064400000000000000000000010501046102023000133520ustar 00000000000000# totp-lite Changelog ## 2.0.1 (2023-10-30) #### Changed - Switch to `sha1` to `sha-1`, which was deprecated. ## 2.0.0 (2022-05-19) #### Changed - Bump cryptography dependencies. This technically alters the user-facing API, but not in way that should affect anyone since it only added a few extra trait contraints. ## 1.0.3 (2021-05-27) #### Changed - Allow `hmac-0.11`. ## 1.0.2 (2020-11-19) #### Changed - Allow `hmac-0.10`. ## 1.0.1 (2020-08-21) #### Fixed - A broken link in docstrings. ## 1.0.0 (2020-08-20) Initial release. totp-lite-2.0.1/Cargo.lock0000644000000252250000000000100107360ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "aho-corasick" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "block-buffer" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ "generic-array", ] [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cpufeatures" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" dependencies = [ "libc", ] [[package]] name = "crypto-common" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", "typenum", ] [[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", "subtle", ] [[package]] name = "equivalent" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "form_urlencoded" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" dependencies = [ "percent-encoding", ] [[package]] name = "generic-array" version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", ] [[package]] name = "hashbrown" version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" [[package]] name = "hmac" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ "digest", ] [[package]] name = "idna" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" dependencies = [ "unicode-bidi", "unicode-normalization", ] [[package]] name = "indexmap" version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" dependencies = [ "equivalent", "hashbrown", ] [[package]] name = "koibumi-base32" version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d138d86042bc525f86860655d92c2e3acc285d1aca883c05856753c5102bbb" dependencies = [ "lazy_static", ] [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" version = "0.2.149" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" [[package]] name = "memchr" version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "percent-encoding" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "proc-macro2" version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" dependencies = [ "unicode-ident", ] [[package]] name = "pulldown-cmark" version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77a1a2f1f0a7ecff9c31abbe177637be0e97a0aef46cf8738ece09327985d998" dependencies = [ "bitflags", "memchr", "unicase", ] [[package]] name = "quote" version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] [[package]] name = "regex" version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick", "memchr", "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "semver" version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" [[package]] name = "serde" version = "1.0.190" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.190" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_spanned" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" dependencies = [ "serde", ] [[package]] name = "sha1" version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures", "digest", ] [[package]] name = "sha2" version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", "digest", ] [[package]] name = "subtle" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "syn" version = "2.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "tinyvec" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" dependencies = [ "tinyvec_macros", ] [[package]] name = "tinyvec_macros" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "toml" version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" dependencies = [ "serde", "serde_spanned", "toml_datetime", "toml_edit", ] [[package]] name = "toml_datetime" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" dependencies = [ "serde", ] [[package]] name = "toml_edit" version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", "winnow", ] [[package]] name = "totp-lite" version = "2.0.1" dependencies = [ "digest", "hmac", "koibumi-base32", "sha1", "sha2", "version-sync", ] [[package]] name = "typenum" version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicase" version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" dependencies = [ "version_check", ] [[package]] name = "unicode-bidi" version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" dependencies = [ "tinyvec", ] [[package]] name = "url" version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" dependencies = [ "form_urlencoded", "idna", "percent-encoding", ] [[package]] name = "version-sync" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "835169da0173ea373ddf5987632aac1f918967fbbe58195e304342282efa6089" dependencies = [ "proc-macro2", "pulldown-cmark", "regex", "semver", "syn", "toml", "url", ] [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "winnow" version = "0.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3b801d0e0a6726477cc207f60162da452f3a95adb368399bef20a946e06f65c" dependencies = [ "memchr", ] totp-lite-2.0.1/Cargo.toml0000644000000022750000000000100107610ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "totp-lite" version = "2.0.1" authors = ["Colin Woodbury "] description = "A simple, correct TOTP library." homepage = "https://github.com/fosskers/totp-lite" readme = "README.md" keywords = [ "authentication", "totp", "otp", "2fa", ] categories = ["authentication"] license = "MIT" repository = "https://github.com/fosskers/totp-lite" [dependencies.digest] version = "0.10" [dependencies.hmac] version = "0.12" [dependencies.sha1] version = "0.10" [dependencies.sha2] version = "0.10" [dev-dependencies.koibumi-base32] version = "0.0" [dev-dependencies.version-sync] version = "0.9" [badges.github] branch = "master" repository = "fosskers/totp-lite" workflow = "Rust" totp-lite-2.0.1/Cargo.toml.orig000064400000000000000000000011531046102023000144340ustar 00000000000000[package] name = "totp-lite" version = "2.0.1" authors = ["Colin Woodbury "] edition = "2018" description = "A simple, correct TOTP library." homepage = "https://github.com/fosskers/totp-lite" repository = "https://github.com/fosskers/totp-lite" readme = "README.md" license = "MIT" keywords = ["authentication", "totp", "otp", "2fa"] categories = ["authentication"] [badges] github = { repository = "fosskers/totp-lite", branch = "master", workflow = "Rust" } [dependencies] digest = "0.10" hmac = "0.12" sha1 = "0.10" sha2 = "0.10" [dev-dependencies] version-sync = "0.9" koibumi-base32 = "0.0" totp-lite-2.0.1/LICENSE000064400000000000000000000020661046102023000125560ustar 00000000000000MIT License Copyright (c) 2020 - 2021 Colin Woodbury 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. totp-lite-2.0.1/README.md000064400000000000000000000026661046102023000130360ustar 00000000000000[![Workflow Status](https://github.com/fosskers/totp-lite/workflows/Rust/badge.svg)](https://github.com/fosskers/totp-lite/actions?query=workflow%3A%22Rust%22) [![](https://img.shields.io/crates/v/totp-lite.svg)](https://crates.io/crates/totp-lite) # totp-lite A simple, correct TOTP library. Time-based One-time Passwords are a useful way to authenticate a client, since a valid password expires long before it could ever be guessed by an attacker. This library provides an implementation of TOTP that matches its specification [RFC6238], along with a simple interface. ## Usage The `totp` function is likely what you need. It uses the default time step of 30 seconds and produces 8 digits of output: ```rust use std::time::{SystemTime, UNIX_EPOCH}; use totp_lite::{totp, Sha512}; // Negotiated between you and the authenticating service. let password: &[u8] = b"secret"; // The number of seconds since the Unix Epoch. let seconds: u64 = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs(); // Specify the desired Hash algorithm via a type parameter. // `Sha1` and `Sha256` are also available. let result: String = totp::(password, seconds); assert_eq!(8, result.len()); ``` For full control over how the algorithm is configured, consider `totp_custom`. ## Resources - [RFC6238: TOTP][RFC6238] - [RFC6238 Errata](https://www.rfc-editor.org/errata_search.php?rfc=6238) [RFC6238]: https://tools.ietf.org/html/rfc6238 License: MIT totp-lite-2.0.1/examples/ga.rs000064400000000000000000000034411046102023000143220ustar 00000000000000//! A Google Authenticator compatible TOTP implementation. //! Technical reference: //! https://en.wikipedia.org/wiki/Google_Authenticator#Technical_description //! //! In order to keep this example short it has no error handling, and //! therefore it can panic, for example if you enter an invalid base32 //! character. //! //! You can run this example as follows: //! ```sh //! cargo run --example ga //! ``` use koibumi_base32 as base32; use std::io::{self, Write}; use std::time::SystemTime; use totp_lite::{totp_custom, Sha1, DEFAULT_STEP}; fn main() { println!("Press ctrl-c to cancel."); loop { let mut input = String::new(); // Request the TOTP secret. print!("Enter your TOTP secret: "); io::stdout().flush().unwrap(); io::stdin().read_line(&mut input).unwrap(); let length = input.trim().len(); if length != 16 && length != 26 && length != 32 { println!("Invalid TOTP secret, must be 16, 26 or 32 characters."); continue; } // The number of seconds since the Unix Epoch, used to calcuate a TOTP secret. let seconds: u64 = SystemTime::now() .duration_since(SystemTime::UNIX_EPOCH) .unwrap() .as_secs(); // Calculate a 6 digit TOTP two-factor authentication code. println!( "Your TOTP code: {}", totp_custom::( // Calculate a new code every 30 seconds. DEFAULT_STEP, // Calculate a 6 digit code. 6, // Convert the secret into bytes using base32::decode(). &base32::decode(&input.trim().to_lowercase()).unwrap(), // Seconds since the Unix Epoch. seconds, ) ); } } totp-lite-2.0.1/src/lib.rs000064400000000000000000000160751046102023000134610ustar 00000000000000//! A simple, correct TOTP library. //! //! Time-based One-time Passwords are a useful way to authenticate a client, //! since a valid password expires long before it could ever be guessed by an //! attacker. This library provides an implementation of TOTP that matches its //! specification [RFC6238], along with a simple interface. //! //! # Usage //! //! The `totp` function is likely what you need. It uses the default time step //! of 30 seconds and produces 8 digits of output: //! //! ``` //! use std::time::{SystemTime, UNIX_EPOCH}; //! use totp_lite::{totp, Sha512}; //! //! // Negotiated between you and the authenticating service. //! let password: &[u8] = b"secret"; //! //! // The number of seconds since the Unix Epoch. //! let seconds: u64 = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs(); //! //! // Specify the desired Hash algorithm via a type parameter. //! // `Sha1` and `Sha256` are also available. //! let result: String = totp::(password, seconds); //! assert_eq!(8, result.len()); //! ``` //! //! For full control over how the algorithm is configured, consider //! `totp_custom`. //! //! # Resources //! - [RFC6238: TOTP][RFC6238] //! - [RFC6238 Errata](https://www.rfc-editor.org/errata_search.php?rfc=6238) //! //! [RFC6238]: https://tools.ietf.org/html/rfc6238 #![doc(html_root_url = "https://docs.rs/totp-lite/2.0.1")] use digest::{ block_buffer::Eager, core_api::{BlockSizeUser, BufferKindUser, CoreProxy, FixedOutputCore, UpdateCore}, generic_array::typenum::{IsLess, Le, NonZero, U256}, FixedOutput, HashMarker, Update, }; use hmac::{Hmac, Mac}; pub use sha1::Sha1; pub use sha2::{Sha256, Sha512}; /// 30 seconds. pub const DEFAULT_STEP: u64 = 30; /// 8 digits of output. pub const DEFAULT_DIGITS: u32 = 8; /// Produce a Time-based One-time Password with default settings. /// /// ``` /// use std::time::{SystemTime, UNIX_EPOCH}; /// use totp_lite::{totp, Sha512}; /// /// // Negotiated between you and the authenticating service. /// let password: &[u8] = b"secret"; /// /// // The number of seconds since the Unix Epoch. /// let seconds: u64 = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs(); /// /// // Specify the desired Hash algorithm via a type parameter. /// // `Sha1` and `Sha256` are also available. /// let result: String = totp::(password, seconds); /// assert_eq!(8, result.len()); /// assert_eq!("71788658", totp::(password, 1234567890)); // 2009 February 13. /// ``` pub fn totp(secret: &[u8], time: u64) -> String where H: Update + FixedOutput + CoreProxy, H::Core: HashMarker + UpdateCore + FixedOutputCore + BufferKindUser + Default + Clone, ::BlockSize: IsLess, Le<::BlockSize, U256>: NonZero, { totp_custom::(DEFAULT_STEP, DEFAULT_DIGITS, secret, time) } /// Produce a Time-based One-time Password with full control over algorithm parameters. /// /// ``` /// use std::time::{SystemTime, UNIX_EPOCH}; /// use totp_lite::{totp_custom, Sha512, DEFAULT_STEP}; /// /// // Negotiated between you and the authenticating service. /// let password: &[u8] = b"secret"; /// /// // The number of seconds since the Unix Epoch. /// let seconds: u64 = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs(); /// /// // Uses the default step of 30 seconds, but asks for 10 result digits instead. /// let result: String = totp_custom::(DEFAULT_STEP, 10, password, seconds); /// assert_eq!(10, result.len()); /// ``` pub fn totp_custom(step: u64, digits: u32, secret: &[u8], time: u64) -> String where H: Update + FixedOutput + CoreProxy, H::Core: HashMarker + UpdateCore + FixedOutputCore + BufferKindUser + Default + Clone, ::BlockSize: IsLess, Le<::BlockSize, U256>: NonZero, { // Hash the secret and the time together. let mut mac = as Mac>::new_from_slice(secret).unwrap(); as Update>::update(&mut mac, &to_bytes(time / step)); let hash: &[u8] = &mac.finalize().into_bytes(); // Magic from the RFC. let offset: usize = (hash.last().unwrap() & 0xf) as usize; let binary: u64 = (((hash[offset] & 0x7f) as u64) << 24) | ((hash[offset + 1] as u64) << 16) | ((hash[offset + 2] as u64) << 8) | (hash[offset + 3] as u64); format!("{:01$}", binary % (10_u64.pow(digits)), digits as usize) } /// Convert a `u64` into its individual bytes. fn to_bytes(n: u64) -> [u8; 8] { let mask = 0x00000000000000ff; let mut bytes: [u8; 8] = [0; 8]; (0..8).for_each(|i| bytes[7 - i] = (mask & (n >> (i * 8))) as u8); bytes } #[cfg(test)] mod tests { use super::*; #[test] fn to_bytes_test() { assert_eq!(vec![0, 0, 0, 0, 0, 0, 0, 1], to_bytes(59 / DEFAULT_STEP)); assert_eq!( vec![0, 0, 0, 0, 0x02, 0x35, 0x23, 0xec], to_bytes(1111111109 / DEFAULT_STEP) ); assert_eq!( vec![0, 0, 0, 0, 0x27, 0xbc, 0x86, 0xaa], to_bytes(20000000000 / DEFAULT_STEP) ); } #[test] fn variable_length() { let secret: &[u8] = b"12345678901234567890123456789012"; assert_eq!( "2102975832", totp_custom::(DEFAULT_STEP, 10, secret, 100) ); assert_eq!( "975832", totp_custom::(DEFAULT_STEP, 6, secret, 100) ); } #[test] fn totp1_tests() { let secret: &[u8] = b"12345678901234567890"; assert_eq!(20, secret.len()); let pairs = vec![ ("94287082", 59), ("07081804", 1111111109), ("14050471", 1111111111), ("89005924", 1234567890), ("69279037", 2000000000), ("65353130", 20000000000), ]; pairs.into_iter().for_each(|(expected, time)| { assert_eq!(expected, totp::(secret, time)); }); } #[test] fn totp256_tests() { let secret: &[u8] = b"12345678901234567890123456789012"; assert_eq!(32, secret.len()); let pairs = vec![ ("46119246", 59), ("68084774", 1111111109), ("67062674", 1111111111), ("91819424", 1234567890), ("90698825", 2000000000), ("77737706", 20000000000), ]; pairs.into_iter().for_each(|(expected, time)| { assert_eq!(expected, totp::(secret, time)); }); } #[test] fn totp512_tests() { let secret: &[u8] = b"1234567890123456789012345678901234567890123456789012345678901234"; assert_eq!(64, secret.len()); let pairs = vec![ ("90693936", 59), ("25091201", 1111111109), ("99943326", 1111111111), ("93441116", 1234567890), ("38618901", 2000000000), ("47863826", 20000000000), ]; pairs.into_iter().for_each(|(expected, time)| { assert_eq!(expected, totp::(secret, time)); }); } } totp-lite-2.0.1/tests/version-numbers.rs000064400000000000000000000001431046102023000164110ustar 00000000000000#[test] fn test_html_root_url() { version_sync::assert_html_root_url_updated!("src/lib.rs"); }