1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
45//! IEEE Std 802.11-2016 WEP descriptors and credentials.
6//!
7//! **WEP is insecure and support will be removed. This module is provided for legacy support only
8//! and its use should be avoided.**
9//!
10//! WEP has no dedicated descriptor data. Only WEP-40 and WEP-104 are supported and key size is not
11//! negotiated with remote stations.
1213// TODO(https://fxbug.dev/42178070): Name items in this module in a way that makes it clear that they
14// implement an insecure security protocol.
1516use fidl_fuchsia_wlan_common_security as fidl_security;
1718use thiserror::Error;
1920use crate::security::SecurityError;
2122pub const WEP40_KEY_BYTES: usize = 5;
23pub const WEP104_KEY_BYTES: usize = 13;
2425#[derive(Clone, Copy, Debug, Error, Eq, PartialEq)]
26#[non_exhaustive]
27pub enum WepError {
28#[error("invalid WEP key size: {0} bytes")]
29Size(usize),
30#[error("invalid WEP key encoding")]
31Encoding,
32}
3334/// WEP key.
35///
36/// IEEE Std 802.11-2016 describes two WEP key sizes: WEP-40 and WEP-104. `Key` provides variants
37/// for these standard key sizes represented as unencoded bytes.
38#[derive(Clone, Debug, Eq, PartialEq)]
39pub enum WepKey {
40/// WEP-40 key. This is a partial key and is joined with an IV to form a 64-bit key.
41Wep40([u8; WEP40_KEY_BYTES]),
42/// WEP-104 key. This is a partial key and is joined with an IV to form a 128-bit key.
43Wep104([u8; WEP104_KEY_BYTES]),
44}
4546impl WepKey {
47/// Parses a WEP key from a byte sequence.
48 ///
49 /// This function parses both unencoded keys and ASCII hexadecimal encoded keys. IEEE Std
50 /// 802.11-2016 does not specify an encoding for non-hexadecimal keys, so the raw bytes are
51 /// accepted as is, though these keys are typically ASCII or UTF-8 encoded text in practice.
52 /// ASCII hexadecimal encoded keys are decoded into raw bytes.
53 ///
54 /// Note that `Key` does not provide a mechanism to restore the original byte sequence parsed
55 /// by this function, so the exact encoding of ASCII hexadecimal encoded keys may be lost.
56 ///
57 /// # Errors
58 ///
59 /// Returns an error if the size or encoding of the byte sequence is incompatible.
60pub fn parse(bytes: impl AsRef<[u8]>) -> Result<Self, WepError> {
61const WEP40_HEX_ENCODING_BYTES: usize = WEP40_KEY_BYTES * 2;
62const WEP104_HEX_ENCODING_BYTES: usize = WEP104_KEY_BYTES * 2;
6364let bytes = bytes.as_ref();
65match bytes.len() {
66 WEP40_HEX_ENCODING_BYTES | WEP104_HEX_ENCODING_BYTES => {
67let bytes = hex::decode(bytes).map_err(|_| WepError::Encoding)?;
68Ok(match bytes.len() {
69 WEP40_KEY_BYTES => WepKey::Wep40(bytes.try_into().unwrap()),
70 WEP104_KEY_BYTES => WepKey::Wep104(bytes.try_into().unwrap()),
71_ => unreachable!(),
72 })
73 }
74_ => WepKey::try_from_literal_bytes(bytes),
75 }
76 }
7778/// Converts unencoded bytes into a WEP key.
79 ///
80 /// This conversion is not a parse and does **not** accept ASCII hexadecimal encoded keys; the
81 /// bytes are interpreted literally and copied as is. Use `Key::parse` for hexadecimal keys.
82pub(crate) fn try_from_literal_bytes(bytes: impl AsRef<[u8]>) -> Result<Self, WepError> {
83let bytes = bytes.as_ref();
84let n = bytes.len();
85match n {
86 WEP40_KEY_BYTES => Ok(WepKey::Wep40(bytes.try_into().unwrap())),
87 WEP104_KEY_BYTES => Ok(WepKey::Wep104(bytes.try_into().unwrap())),
88_ => Err(WepError::Size(n)),
89 }
90 }
91}
9293impl AsRef<[u8]> for WepKey {
94fn as_ref(&self) -> &[u8] {
95match self {
96 WepKey::Wep40(ref bytes) => bytes,
97 WepKey::Wep104(ref bytes) => bytes,
98 }
99 }
100}
101102impl From<[u8; WEP40_KEY_BYTES]> for WepKey {
103fn from(bytes: [u8; WEP40_KEY_BYTES]) -> Self {
104 WepKey::Wep40(bytes)
105 }
106}
107108impl From<[u8; WEP104_KEY_BYTES]> for WepKey {
109fn from(bytes: [u8; WEP104_KEY_BYTES]) -> Self {
110 WepKey::Wep104(bytes)
111 }
112}
113114impl From<WepKey> for Vec<u8> {
115fn from(key: WepKey) -> Self {
116match key {
117 WepKey::Wep40(bytes) => bytes.into(),
118 WepKey::Wep104(bytes) => bytes.into(),
119 }
120 }
121}
122123/// WEP authenticator.
124#[derive(Clone, Debug, Eq, PartialEq)]
125pub struct WepAuthenticator {
126/// WEP key used to authenticate.
127pub key: WepKey,
128}
129130impl From<WepAuthenticator> for fidl_security::Protocol {
131fn from(_: WepAuthenticator) -> Self {
132 fidl_security::Protocol::Wep
133 }
134}
135136impl From<WepAuthenticator> for fidl_security::WepCredentials {
137fn from(authenticator: WepAuthenticator) -> Self {
138let key = authenticator.key.into();
139 fidl_security::WepCredentials { key }
140 }
141}
142143impl TryFrom<fidl_security::WepCredentials> for WepAuthenticator {
144type Error = SecurityError;
145146fn try_from(credentials: fidl_security::WepCredentials) -> Result<Self, Self::Error> {
147let key = WepKey::try_from_literal_bytes(credentials.key)?;
148Ok(WepAuthenticator { key })
149 }
150}
151152#[cfg(test)]
153mod tests {
154use test_case::test_case;
155156use crate::security::wep::{WepError, WepKey, WEP104_KEY_BYTES};
157158#[test_case([0xFF; 5] => Ok(WepKey::Wep40([0xFF; 5])))]
159#[test_case("wep40" => Ok(WepKey::Wep40([b'w', b'e', b'p', b'4', b'0'])))]
160#[test_case("abcdef0000" => Ok(WepKey::Wep40([0xAB, 0xCD, 0xEF, 0, 0])))]
161#[test_case("FFFFFF0000" => Ok(WepKey::Wep40([0xFF, 0xFF, 0xFF, 0, 0])))]
162#[test_case("aaaAAA0000" => Ok(WepKey::Wep40([0xAA, 0xAA, 0xAA, 0, 0])))]
163#[test_case("authenticates" => Ok(WepKey::Wep104([
164b'a', b'u', b't', b'h', b'e', b'n', b't', b'i', b'c', b'a', b't', b'e', b's',
165 ])))]
166#[test_case("ffffffffffffffffffffffffff" => Ok(WepKey::Wep104([0xFF; WEP104_KEY_BYTES])))]
167#[test_case("abcdef" => Err(WepError::Size(6)))]
168 #[test_case("abcdefZZZZ" => Err(WepError::Encoding))]
169fn parse_wep_key(bytes: impl AsRef<[u8]>) -> Result<WepKey, WepError> {
170 WepKey::parse(bytes)
171 }
172}