wlan_common/security/
wep.rs

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.
4
5//! 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.
12
13// 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.
15
16use fidl_fuchsia_wlan_common_security as fidl_security;
17
18use thiserror::Error;
19
20use crate::security::SecurityError;
21
22pub const WEP40_KEY_BYTES: usize = 5;
23pub const WEP104_KEY_BYTES: usize = 13;
24
25#[derive(Clone, Copy, Debug, Error, Eq, PartialEq)]
26#[non_exhaustive]
27pub enum WepError {
28    #[error("invalid WEP key size: {0} bytes")]
29    Size(usize),
30    #[error("invalid WEP key encoding")]
31    Encoding,
32}
33
34/// 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.
41    Wep40([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.
43    Wep104([u8; WEP104_KEY_BYTES]),
44}
45
46impl 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.
60    pub fn parse(bytes: impl AsRef<[u8]>) -> Result<Self, WepError> {
61        const WEP40_HEX_ENCODING_BYTES: usize = WEP40_KEY_BYTES * 2;
62        const WEP104_HEX_ENCODING_BYTES: usize = WEP104_KEY_BYTES * 2;
63
64        let bytes = bytes.as_ref();
65        match bytes.len() {
66            WEP40_HEX_ENCODING_BYTES | WEP104_HEX_ENCODING_BYTES => {
67                let bytes = hex::decode(bytes).map_err(|_| WepError::Encoding)?;
68                Ok(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    }
77
78    /// 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.
82    pub(crate) fn try_from_literal_bytes(bytes: impl AsRef<[u8]>) -> Result<Self, WepError> {
83        let bytes = bytes.as_ref();
84        let n = bytes.len();
85        match 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}
92
93impl AsRef<[u8]> for WepKey {
94    fn as_ref(&self) -> &[u8] {
95        match self {
96            WepKey::Wep40(ref bytes) => bytes,
97            WepKey::Wep104(ref bytes) => bytes,
98        }
99    }
100}
101
102impl From<[u8; WEP40_KEY_BYTES]> for WepKey {
103    fn from(bytes: [u8; WEP40_KEY_BYTES]) -> Self {
104        WepKey::Wep40(bytes)
105    }
106}
107
108impl From<[u8; WEP104_KEY_BYTES]> for WepKey {
109    fn from(bytes: [u8; WEP104_KEY_BYTES]) -> Self {
110        WepKey::Wep104(bytes)
111    }
112}
113
114impl From<WepKey> for Vec<u8> {
115    fn from(key: WepKey) -> Self {
116        match key {
117            WepKey::Wep40(bytes) => bytes.into(),
118            WepKey::Wep104(bytes) => bytes.into(),
119        }
120    }
121}
122
123/// WEP authenticator.
124#[derive(Clone, Debug, Eq, PartialEq)]
125pub struct WepAuthenticator {
126    /// WEP key used to authenticate.
127    pub key: WepKey,
128}
129
130impl From<WepAuthenticator> for fidl_security::Protocol {
131    fn from(_: WepAuthenticator) -> Self {
132        fidl_security::Protocol::Wep
133    }
134}
135
136impl From<WepAuthenticator> for fidl_security::WepCredentials {
137    fn from(authenticator: WepAuthenticator) -> Self {
138        let key = authenticator.key.into();
139        fidl_security::WepCredentials { key }
140    }
141}
142
143impl TryFrom<fidl_security::WepCredentials> for WepAuthenticator {
144    type Error = SecurityError;
145
146    fn try_from(credentials: fidl_security::WepCredentials) -> Result<Self, Self::Error> {
147        let key = WepKey::try_from_literal_bytes(credentials.key)?;
148        Ok(WepAuthenticator { key })
149    }
150}
151
152#[cfg(test)]
153mod tests {
154    use test_case::test_case;
155
156    use crate::security::wep::{WepError, WepKey, WEP104_KEY_BYTES};
157
158    #[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([
164        b'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))]
169    fn parse_wep_key(bytes: impl AsRef<[u8]>) -> Result<WepKey, WepError> {
170        WepKey::parse(bytes)
171    }
172}