0

我正在尝试将 Arduino 连接到 WiFi 网络。

const char* ssid = "ssid";
char* password = "some_hex_chars";
.
.
.
void setup(void){
  WiFi.begin(ssid, password);
.
.
.

问题是,密码短语中某处的代码为 0x00。由于 begin() 方法采用参数 char,它是以 null 结尾的字符串,因此密码被截断。有没有办法解决这个问题?我在哪里可以找到 begin() 方法的来源来修改它?

编辑:错误。这不是密码,它是 64 个十六进制字符的 PSK,它不想连接。

更新:我解决了这个问题。我不是PSK问题,而是WiFi路由器高级设置。什么时候

54g™ 模式设置为54g 性能,它不想连接。在我将其更改为54g Auto后,它工作正常。

4

1 回答 1

4

我对 Arduino 一无所知——但对 802.11 又名 Wi-Fi 了解更多。一个这样:

不要那样做。根据 IEEE 802.11 标准,如果您的密码短语中间有 0x00,那么它在技术上是无效的。

因此,我认为,如果正确实施,您的 802.11 堆栈会将您的密码短语的倒数第二个字符(= 密码短语是此 0x00之前的所有内容)解释为您正在寻找未定义的行为 - 充其量是互操作性问题,在最坏的情况下,你是在打赌。

那个怎么样?

(警告:这会很无聊,很多“网络律师”的东西)

与此相关的 IEEE 802.11 标准是 IEEE Std 802.11i-2004“修订 6:媒体访问控制 (MAC) 安全增强”[0],又名“WPA2”。

(我不会深入研究 WEP,它显然已被弃用,也不会使用“基本”WPA,它是等待此 WPA2 标准完成的过渡)。

相关部分可以在 802.11i 中找到,ASN MIB[1](附件 D,规范)第 136 页,将“ dot11RSNAConfigPSKPassPhrase”定义为“ DisplayString”。那么“ DisplayString”到底是什么类型的数据呢?

RFC 1213,“基于 TCP/IP 的互联网的网络管理的管理信息库:MIB-II”,从 1991 年开始,第 3 页,指出:

“DisplayString 仅限于 NVT ASCII 字符集,如 [6] 第 10-11 页中所定义。”

好的...

这个“[6]”是 1983 年的 RFC 854(哇!这些 IETF 和 IEEE 认真地设计了他们的标准,真的,真的建立在上面)。你还跟着我吗?:-) 因此,通过查看它,我们了解到 NVT 代表“网络虚拟终端”,并且在指向第 10 页和第 11 页时,我们发现:

NVT 打印机 [原文如此!请记住那是 1983 年] [...] 可以生成所有 95 个 USASCII 图形(代码 32 到 126)的表示。

好的,ASCII 码 32 到 126。现在让我们回到 IEEE 802.11i:

在附件 H(资料性)中,“RSNA 参考实现和测试向量”,“H.4 建议的密码短语到 PSK 映射”部分(请记住,密码短语的目的,在数学上与 SSID 一起按摩,是为了导出一个PSK(预共享密钥),对 802.11 操作更有用,但比“我可以用该死的键盘输入的该死的简单密码短语”更不友好)。其中,用 IEEE 的方式表述,给出了这个(第 165 页):

RSNA PSK 由 256 位组成,或以十六进制表示时为 64 个八位字节。用户很难正确输入 64 个十六进制字符。然而,大多数用户都熟悉密码和密码短语,并且感觉输入它们比输入密钥更舒服。用户更有可能输入 ASCII 密码或密码短语,即使这样做会限制可能的密钥集。这表明最好的办法是将密码短语引入 PSK 映射。

本节定义了密码短语到 PSK 的映射,这是与 RSNA 一起使用的推荐做法。

引入此密码短语映射是为了鼓励不熟悉密码概念的用户启用其 WLAN 的安全功能。

...所以密码的目的是什么。然后在第 166 页:

在这里,以下假设适用:

  • 密码短语是 8 到 63 个 ASCII 编码字符的序列。63 的限制来自于区分
    密码短语和显示为 64 个十六进制
    字符的 PSK 的愿望。
  • 密码短语中的每个字符都必须具有 32 到 126(十进制)范围内的编码,包括 32 到 126(十进制)。[强调我的]

瞧!事实上,“32 到 126(十进制),包括在内”。

所以这里我们再次将密码短语作为 ASCII “在 32 到 126(十进制)的范围内”,从 IEEE 到 IETF 再到 IEEE 确认。我们还了解到它的长度应该在 8 到 63 个字节之间,我推断,这意味着如果超过 63 个字节,它将被修剪(而不是 NULL 终止,这不是问题),如果更短,将在 32-126 ASCII 码之外的第一个字符处被剪切。当然,C 字符串 NULL 终止符 0x00 更实用,更适合用于此 BTW。

因此,密码 = 仅由 32 到 126(十进制)ASCII 码组成的字符串。

查看 ASCII 表,您会看到它以空格开头,以波浪号“~”结尾。

绝对没有 0x00 。

因此,长话短说:您的密码在标准方面在技术上是无效的,并且您正在寻找未定义的行为。

恭喜你读到这里!

附录:

当谈到网络协议时,永远不要假设看起来像“字符串”的东西只是你可能预设的“字符串”,并始终检查确切的编码/限制。

关于 Wi-Fi 的其他示例:

另一个“字符串”是 SSID。这真的是一个字符串吗?,它是一个 32 字节的原始数组,没有 ASCII,没有 UTF-8,Unicode,无论如何,没有终止,只有 32 个原始字节,即使你将它“设置”为“foobar + NULL 终止符”,整个 32 个字节也会被堆栈使用并播出(查看wireshark跟踪,然后双击剖析中的SSID字段:32字节长)。因此,一个 SSID 可以只包含 ASCII 空格、制表符、CR、LF 和一些 0x00,或者只包含 0x00 顺便说一句,无论如何,它将完全有效并作为一个完整的 32 字节序列进行管理。

编辑:

我想知道你设置这样一个密码的动机,我能想出的唯一想法——如果我错了,请纠正我——你的目的是玩一个巧妙的把戏,以确保普通用户使用普通键盘,永远无法输入密码。遗憾的是——或者实际上希望——正如我解释的那样,这行不通,因为IEEE 精确地设计了密码短语数据类型,以 100% 确保任何人使用最基本的键盘始终可以键入它。那是他们的动机。

那么,你能做什么呢?

作为替代方案,您可以直接使用 PSK。那是纯原始的 32 字节(表示 64 十六进制数字 ASCII),没有可输入/可打印的考虑。例如,从 hostapd.conf 文件(当然,示例 PSK 在这里表示为“文本”,但这实际上是原始字节):

# WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit
# secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase
# (8..63 characters) that will be converted to PSK. This conversion uses SSID
# so the PSK changes when ASCII passphrase is used and the SSID is changed.
# wpa_psk (dot11RSNAConfigPSKValue)
# wpa_passphrase (dot11RSNAConfigPSKPassPhrase)
#wpa_psk=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
#wpa_passphrase=secret passphrase

但是当然,1/ 这可能不适合您的用例(部署方面),并且 2/ Arduino Wi-Fi API 可能没有这样的功能。

希望这有帮助。

[0]:您可以在这里免费下载:http: //standards.ieee.org/getieee802/download/802.11i-2004.pdf

[1]:这是“抽象语法表示法”中“管理信息库”的 IEEE 行话,它是给定标准的每个数据及其名称和类型的正式分层表示法。您可以将其视为“XML”,只是它不是XML,并且被 IETF 和 IEEE(RFC 2578、RFC 1213)使用。

于 2016-05-08T11:24:33.967 回答