summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Kreutz <mail@skreutz.com>2022-01-03 15:49:53 +0100
committerStefan Kreutz <mail@skreutz.com>2022-01-03 15:49:53 +0100
commit74ac452eebd4d3520c1f610260d55b7e7233eca9 (patch)
tree9c4da84059a168001c8645175e04b9014de0907f
downloadwpa-psk-74ac452eebd4d3520c1f610260d55b7e7233eca9.tar
Add initial implementationwpa-psk-0.1.0
-rw-r--r--.gitignore1
-rw-r--r--Cargo.lock346
-rw-r--r--Cargo.toml20
-rw-r--r--LICENSE-APACHE-2.012
-rw-r--r--LICENSE-MIT19
-rw-r--r--README.md31
-rw-r--r--src/lib.rs138
-rw-r--r--src/main.rs48
8 files changed, 615 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ea8c4bf
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/target
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..4aca404
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,346 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
+
+[[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.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1d36a02058e76b040de25a4464ba1c80935655595b661505c8b39b664828b95"
+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 = "clap"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d17bf219fcd37199b9a29e00ba65dfb8cd5b2688b7297ec14ff829c40ac50ca9"
+dependencies = [
+ "atty",
+ "bitflags",
+ "clap_derive",
+ "indexmap",
+ "lazy_static",
+ "os_str_bytes",
+ "strsim",
+ "termcolor",
+ "textwrap",
+]
+
+[[package]]
+name = "clap_derive"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e1b9752c030a14235a0bd5ef3ad60a1dcac8468c30921327fc8af36b20c790b9"
+dependencies = [
+ "heck",
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "cpufeatures"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "crypto-common"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "683d6b536309245c849479fba3da410962a43ed8e51c26b729208ec0ac2798d0"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "digest"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b697d66081d42af4fba142d56918a3cb21dc8eb63372c6b85d14f44fb9c5979b"
+dependencies = [
+ "block-buffer",
+ "crypto-common",
+ "generic-array",
+ "subtle",
+]
+
+[[package]]
+name = "generic-array"
+version = "0.14.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"
+dependencies = [
+ "typenum",
+ "version_check",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
+
+[[package]]
+name = "heck"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
+dependencies = [
+ "unicode-segmentation",
+]
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "hmac"
+version = "0.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ddca131f3e7f2ce2df364b57949a9d47915cfbd35e46cfee355ccebbf794d6a2"
+dependencies = [
+ "digest",
+]
+
+[[package]]
+name = "indexmap"
+version = "1.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
+dependencies = [
+ "autocfg",
+ "hashbrown",
+]
+
+[[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.112"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125"
+
+[[package]]
+name = "memchr"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
+
+[[package]]
+name = "os_str_bytes"
+version = "6.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "pbkdf2"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4628cc3cf953b82edcd3c1388c5715401420ce5524fedbab426bd5aba017434"
+dependencies = [
+ "digest",
+]
+
+[[package]]
+name = "proc-macro-error"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
+dependencies = [
+ "proc-macro-error-attr",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro-error-attr"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.36"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
+dependencies = [
+ "unicode-xid",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47aa80447ce4daf1717500037052af176af5d38cc3e571d9ec1c7353fc10c87d"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "sha-1"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "digest",
+]
+
+[[package]]
+name = "strsim"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
+
+[[package]]
+name = "subtle"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
+
+[[package]]
+name = "syn"
+version = "1.0.84"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ecb2e6da8ee5eb9a61068762a32fa9619cc591ceb055b3687f4cd4051ec2e06b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
+[[package]]
+name = "termcolor"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "textwrap"
+version = "0.14.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
+
+[[package]]
+name = "typenum"
+version = "1.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
+
+[[package]]
+name = "unicode-segmentation"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
+
+[[package]]
+name = "version_check"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "wpa-psk"
+version = "0.1.0"
+dependencies = [
+ "clap",
+ "hmac",
+ "pbkdf2",
+ "sha-1",
+]
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..2987092
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,20 @@
+[package]
+name = "wpa-psk"
+version = "0.1.0"
+authors = ["Stefan Kreutz <mail@skreutz.com>"]
+edition = "2021"
+description = "Compute the WPA-PSK of a Wi-FI SSID and passphrase"
+readme = "README.md"
+repository = "https://www.skreutz.com/repos/wpa-psk-rs.git"
+license = "MIT OR Apache-2.0"
+keywords = ["wifi", "wpa", "password", "hash"]
+categories = ["command-line-utilities", "algorithms"]
+publish = true
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+pbkdf2 = { version = "0.10.0", default-features = false }
+hmac = { version = "0.12.0", default-features = false }
+sha-1 = { version = "0.10.0", default-features = false }
+clap = { version = "3.0.0-rc.11", features = ["derive"] }
diff --git a/LICENSE-APACHE-2.0 b/LICENSE-APACHE-2.0
new file mode 100644
index 0000000..7eefa9d
--- /dev/null
+++ b/LICENSE-APACHE-2.0
@@ -0,0 +1,12 @@
+Copyright 2021 Stefan Kreutz <mail@skreutz.com>
+
+Licensed under the Apache License, Version 2.0 (the "License"); you may not use
+this file except in compliance with the License. You may obtain a copy of the
+License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software distributed
+under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+CONDITIONS OF ANY KIND, either express or implied. See the License for the
+specific language governing permissions and limitations under the License.
diff --git a/LICENSE-MIT b/LICENSE-MIT
new file mode 100644
index 0000000..4012e61
--- /dev/null
+++ b/LICENSE-MIT
@@ -0,0 +1,19 @@
+Copyright 2021 Stefan Kreutz <mail@skreutz.com>
+
+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.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..0fcc42f
--- /dev/null
+++ b/README.md
@@ -0,0 +1,31 @@
+# WPA-PSK
+
+This is a command-line utility and Rust library to compute the WPA pre-shared key of a Wi-Fi SSID and passphrase.
+
+## Example
+
+I've created the tool to connect to wireless networks with *special* or technically *invalid* SSIDs and passphrases:
+
+ $ wpa-psk "123abcABC.,-" "456defDEF *<:D"
+ 0x8a366e5bc51cd5d8fbbeffacc5f1af23fac30e3ac93cdcc368fafbbf63a1085c
+
+ $ wpa-psk --force "bar" "2short"
+ 0xcb5de4e4d23b2ab0bf5b9ba0fe8132c1e2af3bb52298ec801af8ad520cea3437
+
+## License
+
+This work is distributed under the terms of both, the [MIT License](LICENSE-MIT) and the [Apache License, Version 2.0](LICENSE-APACHE-2.0).
+
+## Contribution
+
+Contributions are welcome!
+Please contact me via email.
+
+Note: The `Cargo.toml` points to a bare git repository served over dumb HTTPS.
+You can clone it as follows:
+
+ $ git clone https://www.skreutz.com/repos/wpa-psk-rs.git
+
+## See also
+
+The popular [wpa_supplicant](https://hostap.epitest.fi/wpa_supplicant/) comes with a similar tool, `wpa_passphrase(8)`.
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..f50dea0
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,138 @@
+//! Compute the WPA-PSK of a Wi-Fi SSID and passphrase.
+//!
+//! # Example
+//!
+//! Compute and print the WPA-PSK of a valid SSID and passphrase:
+//!
+//! ```
+//! # use wpa_psk::{Ssid, Passphrase, wpa_psk, bytes_to_hex};
+//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
+//! let ssid = Ssid::try_from("home")?;
+//! let passphrase = Passphrase::try_from("0123-4567-89")?;
+//! let psk = wpa_psk(&ssid, &passphrase);
+//! assert_eq!(bytes_to_hex(&psk), "150c047b6fad724512a17fa431687048ee503d14c1ea87681d4f241beb04f5ee");
+//! # Ok(())
+//! # }
+//! ```
+//!
+//! Compute the WPA-PSK of possibly invalid raw bytes:
+//!
+//! ```
+//! # use wpa_psk::{wpa_psk_unchecked, bytes_to_hex};
+//! let ssid = "bar".as_bytes();
+//! let passphrase = "2short".as_bytes();
+//! let psk = wpa_psk_unchecked(&ssid, &passphrase);
+//! assert_eq!(bytes_to_hex(&psk), "cb5de4e4d23b2ab0bf5b9ba0fe8132c1e2af3bb52298ec801af8ad520cea3437");
+//! ```
+
+use std::fmt::Display;
+
+use hmac::Hmac;
+use pbkdf2::pbkdf2;
+use sha1::Sha1;
+
+/// An SSID consisting of 1 up to 32 arbitrary bytes.
+#[derive(Debug)]
+pub struct Ssid<'a>(&'a [u8]);
+
+impl<'a> TryFrom<&'a [u8]> for Ssid<'a> {
+ type Error = &'static str;
+
+ fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
+ if value.is_empty() {
+ Err("SSID must have at least one byte")
+ } else if value.len() > 32 {
+ Err("SSID must have at most 32 bytes")
+ } else {
+ Ok(Ssid(value))
+ }
+ }
+}
+
+impl<'a> TryFrom<&'a str> for Ssid<'a> {
+ type Error = &'static str;
+
+ fn try_from(value: &'a str) -> Result<Self, Self::Error> {
+ Self::try_from(value.as_bytes())
+ }
+}
+
+/// A passphrase consisting of 8 up to 63 printable ASCII characters.
+#[derive(Debug)]
+pub struct Passphrase<'a>(&'a [u8]);
+
+impl<'a> TryFrom<&'a [u8]> for Passphrase<'a> {
+ type Error = &'static str;
+
+ fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
+ if value.len() < 8 {
+ Err("passphrase must have at least 8 bytes")
+ } else if value.len() > 63 {
+ Err("passphrase must have at most 63 bytes")
+ } else if value.iter().any(|i| !matches!(i, 32u8..=126)) {
+ Err("passphrase must consist of printable ASCII characters")
+ } else {
+ Ok(Passphrase(value))
+ }
+ }
+}
+
+impl<'a> TryFrom<&'a str> for Passphrase<'a> {
+ type Error = &'static str;
+
+ fn try_from(value: &'a str) -> Result<Self, Self::Error> {
+ Self::try_from(value.as_bytes())
+ }
+}
+
+impl Display for Passphrase<'_> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{}", std::str::from_utf8(self.0).unwrap())
+ }
+}
+
+/// Returns the WPA-PSK of the given SSID and passphrase.
+pub fn wpa_psk(ssid: &Ssid, passphrase: &Passphrase) -> [u8; 32] {
+ wpa_psk_unchecked(ssid.0, passphrase.0)
+}
+
+/// Unchecked WPA-PSK.
+/// See [`wpa_psk`].
+pub fn wpa_psk_unchecked(ssid: &[u8], passphrase: &[u8]) -> [u8; 32] {
+ let mut buf = [0u8; 32];
+ pbkdf2::<Hmac<Sha1>>(passphrase, ssid, 4096, &mut buf);
+ buf
+}
+
+/// Returns the hexdecimal representation of the given bytes.
+pub fn bytes_to_hex(bytes: &[u8]) -> String {
+ bytes.iter().map(|b| format!("{:02x}", b)).collect()
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn special_characters() {
+ let ssid = Ssid::try_from("123abcABC.,-").unwrap();
+ let passphrase = Passphrase::try_from("456defDEF *<:D").unwrap();
+ assert_eq!(
+ bytes_to_hex(&wpa_psk(&ssid, &passphrase)),
+ "8a366e5bc51cd5d8fbbeffacc5f1af23fac30e3ac93cdcc368fafbbf63a1085c"
+ );
+ }
+
+ #[test]
+ fn passphrase_too_short() {
+ Passphrase::try_from("foobar").unwrap_err();
+ }
+
+ #[test]
+ fn display_passphrase() {
+ assert_eq!(
+ format!("{}", Passphrase::try_from("foobarbuzz").unwrap()),
+ "foobarbuzz"
+ );
+ }
+}
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..2a8c555
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,48 @@
+use std::process::exit;
+
+use clap::Parser;
+use wpa_psk::{bytes_to_hex, wpa_psk, wpa_psk_unchecked, Passphrase, Ssid};
+
+/// Compute the WPA-PSK of a Wi-Fi SSID and passphrase.
+#[derive(Debug, Parser)]
+#[clap(about, version, author)]
+struct Args {
+ /// An SSID consisting of 1 up to 32 arbitrary bytes.
+ ssid: String,
+
+ /// A passphrase consisting of 8 up to 63 printable ASCII characters.
+ passphrase: String,
+
+ /// Don't check the given SSID and passphrase.
+ #[clap(short, long)]
+ force: bool,
+}
+
+fn main() {
+ exit(match run() {
+ Ok(_) => 0,
+ Err(err) => {
+ eprintln!("{}", err);
+ 1
+ }
+ })
+}
+
+fn run() -> Result<(), Box<dyn std::error::Error>> {
+ let args = Args::try_parse()?;
+ let psk = if args.force {
+ wpa_psk_unchecked(args.ssid.as_bytes(), args.passphrase.as_bytes())
+ } else {
+ let ssid = Ssid::try_from(args.ssid.as_bytes())?;
+ let passphrase = Passphrase::try_from(args.passphrase.as_bytes())?;
+ wpa_psk(&ssid, &passphrase)
+ };
+ println!("0x{}", bytes_to_hex(&psk));
+ Ok(())
+}
+
+#[test]
+fn verify_clap_app() {
+ use clap::IntoApp;
+ Args::into_app().debug_assert()
+}
Generated by cgit. See skreutz.com for my tech blog and contact information.